Voltar ao catálogo
Season 9 20 Episódios 1h 13m 2026

Pydantic: Data Validation

v2.12 — Edição de 2026. Uma análise aprofundada ao Pydantic v2.12, a biblioteca de validação de dados mais utilizada em Python, desde a utilização básica até funcionalidades avançadas como custom core schemas e observabilidade com Logfire.

Validação de Dados Python Core
Pydantic: Data Validation
A Reproduzir
Click play to start
0:00
0:00
1
A Filosofia do Pydantic: Type Hints como Validação
Este episódio apresenta a premissa central do Pydantic. Irá aprender como os type hints do Python podem ser utilizados para impor schemas e como o core em Rust impulsiona enormes ganhos de desempenho.
3m 28s
2
A Anatomia de um BaseModel
Mergulhe no BaseModel, a abstração fundamental do Pydantic. Irá aprender como a instanciação valida dados, como os fields sofrem coerção e como os erros de validação são apresentados.
3m 48s
3
Restrições de Field e o Padrão Annotated
Aprenda a impor limites para além dos tipos básicos. Irá descobrir como utilizar a função Field e o construto de tipagem Annotated para adicionar restrições como mínimos e comprimentos máximos.
4m 13s
4
Aliases de Field para Validação e Serialização
Resolva o conflito de convenções de nomenclatura entre APIs externas e código Python interno. Irá aprender a dissociar os nomes dos seus atributos Python das chaves JSON utilizando aliases de validação e serialização.
3m 44s
5
Coerção de Dados vs Strict Mode
Assuma o controlo da tendência do Pydantic para a coerção de dados. Irá aprender a impor correspondências de tipo exatas ativando o Strict Mode ao nível do field ou do model.
3m 43s
6
Observabilidade no Mundo Real com Logfire
Traga transparência aos seus pipelines de dados. Irá aprender a integrar o Pydantic com o Logfire para monitorizar validações bem-sucedidas e falhadas em tempo real.
3m 50s
7
Validação de Tipos Arbitrários com TypeAdapter
Aprenda a validar primitivas e listas independentes sem criar um BaseModel. Irá descobrir como o TypeAdapter transforma qualquer tipo Python num alvo de validação completo.
4m 02s
8
Tipos Union e Validação Inteligente
Compreenda as complexidades da validação de tipos Union. Irá aprender como o Smart Mode do Pydantic avalia a exatidão e os fields válidos para escolher a melhor correspondência.
3m 24s
9
Ferramenta Poderosa: Discriminated Unions
Potencie o desempenho da sua validação. Irá aprender a utilizar Discriminated (Tagged) Unions para dizer ao Pydantic exatamente qual schema aplicar com base num field específico.
3m 29s
10
Pré-processamento com Before e Wrap Validators
Lide com dados de entrada desorganizados antes que atinjam o seu schema. Irá aprender a utilizar os field validators Before e Wrap para limpar o input bruto antes que o Pydantic o avalie.
3m 50s
11
Pós-processamento com After e Plain Validators
Imponha regras estritas de lógica de negócio. Irá aprender a utilizar After validators para verificar dados já processados, e Plain validators para contornar o Pydantic por completo.
3m 34s
12
Hooks de Validação ao Nível do Model
Valide interações entre múltiplos fields. Irá aprender a utilizar o decorador model_validator para impor regras que dependem de todo o payload.
3m 16s
13
Serialização: Exportar Dados com Segurança
Controle como os seus dados saem do sistema. Irá aprender as diferenças entre fazer dump para dicts Python versus strings JSON, e como excluir fields não definidos ou com valores por defeito.
3m 39s
14
Personalizar a Lógica de Serialização
Altere a forma como os seus tipos são representados à saída. Irá aprender a escrever serializers personalizados de Field e Model para mutar dados durante a fase de dump.
3m 49s
15
Gerar JSON Schema a partir de Models
Transforme os seus models em contratos de API auto-documentados. Irá aprender a gerar JSON Schemas compatíveis com OpenAPI e a injetar exemplos diretamente no schema.
3m 44s
16
RootModel: Quando o seu Payload não é um Dicionário
Lide com payloads JSON não padronizados de forma elegante. Irá descobrir como o RootModel permite processar arrays e primitivas ao nível da raiz, mantendo os poderes do BaseModel.
3m 09s
17
Dataclasses Standard vs Dataclasses do Pydantic
Traga validação para as suas classes Python nativas. Irá aprender quando utilizar o decorador dataclass do Pydantic para modernizar bases de código legadas sem reescrever tudo.
3m 55s
18
Ajuste Fino da Configuração do Model
Controle o rigor de todo o seu model. Irá aprender a utilizar o ConfigDict para proibir atributos extra, congelar instâncias e validar atribuições.
3m 58s
19
Configuração de Aplicações com Pydantic Settings
Faça a gestão das suas variáveis de ambiente como um profissional. Irá aprender como o pacote pydantic-settings automatiza o processamento de segredos, ficheiros dot-env e prefixos.
3m 38s
20
Nos Bastidores: Custom Core Schemas
Este é o último episódio da série! Assuma o controlo total do motor de validação. Irá aprender a escrever um método __get_pydantic_core_schema__ para ensinar o core em Rust a lidar com objetos Python completamente estranhos.
3m 39s

Episódios

1

A Filosofia do Pydantic: Type Hints como Validação

3m 28s

Este episódio apresenta a premissa central do Pydantic. Irá aprender como os type hints do Python podem ser utilizados para impor schemas e como o core em Rust impulsiona enormes ganhos de desempenho.

Download
Olá, daqui fala o Alex da DEV STORIES DOT EU. Pydantic: Validação de Dados, episódio 1 de 20. A maioria das bibliotecas de data validation obriga-te a aprender uma linguagem completamente nova e específica do domínio apenas para definir um schema. Mas e se a sintaxe nativa do Python já fosse suficiente para impor as tuas regras? A Filosofia Pydantic: Type Hints como Validação resolve exatamente esta tensão. Antes de vermos como funciona, precisamos de esclarecer uma confusão comum. O Pydantic não é um static type checker como o mypy. O mypy analisa o teu source code antes de o correres para detetar erros de lógica. O Pydantic opera em runtime. Ele recebe dados não confiáveis do mundo exterior, como um payload JSON de um API request, e força-os a conformarem-se aos tipos que definiste, exatamente enquanto o teu programa está a correr. A filosofia central aqui é a simplicidade. Tu defines um data model usando type annotations standard do Python. Crias uma class a representar um utilizador, e declaras que o user ID é um integer, e a data de registo é um objeto datetime. Esse é todo o teu schema. Não escreves funções de validação customizadas nem importas field types proprietários. Quando um dictionary confuso chega de um web form, simplesmente passas esse dictionary para a tua class. O Pydantic interceta-o e garante que o objeto resultante adere estritamente a esses tipos. Aqui está o ponto chave. O Pydantic é fundamentalmente uma library de parsing, não apenas um mecanismo de validação estrito. Se um utilizador submeter um web form onde o user ID é a string quarenta e dois, o Pydantic vai reconhecer que o teu model espera um integer. Ele converte essa string num integer nativo do Python automaticamente. Ele tenta fazer com que os dados encaixem no teu schema antes de levantar um erro. Isto lida com a tediosa coerção de dados para que não tenhas de escrever lógica de parsing manual para cada input field. Validar e converter cada pedaço de dados recebido em runtime parece inerentemente lento, especialmente em Python. Para resolver isto, a lógica de execução não corre, na verdade, em Python. O Pydantic delega o trabalho pesado a um core engine dedicado, escrito inteiramente em Rust. Este design dá-te a developer experience rápida de escrever Python puro, combinada com a velocidade de execução bruta de código de sistema compilado. Considera uma background task a fazer parsing de um ficheiro JSON enorme, onde cada registo contém um endereço web. Se escreveres código Python puro para iterar por milhares de dictionaries, extrair cada string, carregar uma library de expressões regulares e verificar se cada string é um URL válido, o teu processo vai rastejar. O Pydantic lida com isto perfeitamente. Basta anotares o address field como um tipo URL e alimentares o JSON bruto ao teu model. O engine em Rust devora o texto, fazendo o parsing e validando os formatos a velocidades que o Python nativo não consegue igualar. O verdadeiro poder desta abordagem é que o autocomplete do teu editor, as tuas ferramentas de static analysis e a tua validação em runtime partilham exatamente a mesma source of truth, que são as tuas type hints standard. Se achas estes episódios úteis e queres ajudar a apoiar o programa, podes procurar por DevStoriesEU no Patreon. É tudo por este episódio. Obrigado por ouvires, e continua a desenvolver!
2

A Anatomia de um BaseModel

3m 48s

Mergulhe no BaseModel, a abstração fundamental do Pydantic. Irá aprender como a instanciação valida dados, como os fields sofrem coerção e como os erros de validação são apresentados.

Download
Olá, daqui é o Alex da DEV STORIES DOT EU. Pydantic: Validação de Dados, episódio 2 de 20. Falamos muitas vezes sobre validação de dados, mas se olhares com atenção para o Pydantic, o seu objetivo principal é, na verdade, a coerção. Ele garante a estrutura do teu output, não do teu input. A anatomia de um BaseModel é o que torna esta distinção possível. A classe BaseModel é a base do Pydantic. Para definires um schema, crias uma classe Python standard e herdas de BaseModel. Assim que o fazes, o Pydantic transforma a tua classe num container de dados estrito. Defines a forma dos teus dados usando type hints standard do Python. Não precisas de funções proprietárias para declarar uma string ou um número. Basta escreveres o nome do atributo, dois pontos e o tipo Python esperado. Considera um modelo User. Dentro da classe, defines um único campo chamado id e dás-lhe o tipo de um integer. Podes também adicionar um campo name com o tipo string. Esta é toda a definição. Aqui está o ponto chave. O verdadeiro trabalho acontece no momento em que instancias o modelo. Crias uma instância passando os teus dados como keyword arguments, correspondendo aos nomes dos campos que definiste. Quando fazes isto, o Pydantic interceta os dados antes de o objeto estar totalmente inicializado. Ele compara os valores recebidos com as tuas type hints. É aqui que a coerção acontece. Se passares o integer um, dois, três para o campo id, o Pydantic aceita-o imediatamente. Mas imagina que estás a receber dados de um web request ou de um ficheiro de texto, e passas a string "123" para esse mesmo campo. O Pydantic não lança um erro imediatamente. Ele reconhece que o tipo de destino é um integer e tenta converter a string. Como os caracteres podem ser convertidos com segurança para um número, o Pydantic faz a conversão silenciosamente. O objeto é criado, e o campo id armazena um verdadeiro integer Python, não uma string. Este comportamento prova que o Pydantic é essencialmente uma library de parsing. Ele transforma os dados recebidos para se ajustarem ao schema estrito que definiste. Claro que esta conversão tem limites lógicos. Se instanciares o modelo User e passares a string "not an int" para o campo id, o Pydantic tenta a conversão e falha. Quando a coerção é impossível, o Pydantic lança um ValidationError. Este erro interrompe a execução imediatamente. Um detalhe crucial sobre o ValidationError é que o Pydantic avalia todos os campos antes de o lançar. Se o teu modelo tiver vários campos com dados inválidos, a exception vai conter os detalhes de todas as falhas, em vez de parar logo no primeiro erro. O erro aponta os campos exatos que causaram o problema, os valores específicos fornecidos, e os motivos pelos quais falharam o parsing. Assim que os teus dados passarem com sucesso pela instanciação, o objeto resultante tem a garantia de corresponder às tuas type hints. Acedes aos dados exatamente como em qualquer objeto Python standard, usando dot notation. Se atribuíste a instância a uma variável chamada user, basta escreveres user ponto id para recuperar o integer. Não são necessários métodos getter ou setter. Estás a interagir com um objeto limpo e strongly typed. O verdadeiro valor de herdar de BaseModel não é apenas rejeitar inputs inválidos, mas sim normalizar com segurança dados externos imprevisíveis para um estado interno altamente previsível. Obrigado por ouvirem. Fiquem bem, pessoal.
3

Restrições de Field e o Padrão Annotated

4m 13s

Aprenda a impor limites para além dos tipos básicos. Irá descobrir como utilizar a função Field e o construto de tipagem Annotated para adicionar restrições como mínimos e comprimentos máximos.

Download
Olá, daqui fala o Alex da DEV STORIES DOT EU. Pydantic: Validação de Dados, episódio 3 de 20. Os type hints standard dizem-te que um campo é um inteiro, mas não te conseguem dizer que tem de ser maior que zero. Quando uma idade negativa ou um username com dez mil caracteres ultrapassa os limites da tua aplicação, o type checking básico já não é suficiente para proteger o teu backend. Para impor limites rígidos aos teus dados, precisas de Field Constraints e do Annotated Pattern. No Pydantic, as constraints permitem-te restringir os valores permitidos para um tipo específico. Em vez de escreveres funções validator customizadas para cada regra menor, podes definir limites matemáticos ou estruturais diretamente no campo. Para tipos numéricos, podes impor limites de maior que ou menor que usando parâmetros como g-t e l-t. Para strings, podes restringir o tamanho do input usando max length e min length. Para aplicar estas regras, o Pydantic fornece uma utility function chamada Field. A maneira tradicional como os developers aplicavam estas constraints era atribuir uma chamada da função Field como o default value de um model attribute. Por exemplo, declararias um atributo age, farias o type hint como um inteiro, e igualarias a Field, passando g-t igual a zero. Esta estrutura funciona, mas introduz fricção. Se precisares de um inteiro positivo em quinze models diferentes, estás a escrever exatamente o mesmo assignment do Field quinze vezes. Pior ainda, como a função Field ocupa o slot de assignment do default value no model, isso complica as coisas quando queres realmente atribuir um default integer real a esse atributo. Aqui está o ponto chave. Não precisas de vincular as tuas regras de validação ao assignment do atributo de todo. Podes incorporá-las diretamente na própria type definition usando o typing dot Annotated do Python. Annotated é uma feature da standard library que te permite anexar metadados arbitrários a um base type hint. O Pydantic foi concebido especificamente para olhar para dentro de um Annotated type, encontrar quaisquer funções Field que tenhas fornecido, e extrair as suas regras de validação automaticamente. Quando usas o Annotated, passas-lhe duas informações distintas. Primeiro, forneces o base type do Python, como um inteiro ou uma string. Segundo, forneces os metadados, que no nosso caso é a função Field do Pydantic contendo as tuas constraints. Vamos criar um age type reutilizável para ver como isto flui. Defines uma nova variável no teu código chamada PositiveInt. Atribuis ao Annotated. Dentro do Annotated, passas integer como o base type, seguido de uma vírgula, e depois a função Field com g-t igual a zero. Acabaste de criar uma type constraint customizada e reutilizável. Agora, sempre que definires um user model ou um employee model, basta fazeres o type hint do teu campo age com PositiveInt. Não precisas de chamar a função Field no model attribute. Esta abordagem separa as tuas type definitions das estruturas do teu model. Os teus models permanecem incrivelmente limpos, lendo-se exatamente como classes Python standard, sem clutter. Se a tua business logic mudar mais tarde e de repente precisares que um campo age seja maior que dezoito em vez de zero, atualizas a definição do PositiveInt em exatamente um lugar. Essa constraint atualizada propaga-se instantaneamente para todos os models que a utilizam. Além disso, como o Annotated é uma feature nativa do Python, os static type checkers entendem perfeitamente que o teu PositiveInt customizado é, em última análise, avaliado como um inteiro standard. Ao fazer o decoupling dos metadados de validação do default value slot, o Annotated pattern transforma as field constraints de boilerplate repetitivo numa shared library de domain types estritos e reutilizáveis. Obrigado por passares uns minutos comigo. Até à próxima, fica bem.
4

Aliases de Field para Validação e Serialização

3m 44s

Resolva o conflito de convenções de nomenclatura entre APIs externas e código Python interno. Irá aprender a dissociar os nomes dos seus atributos Python das chaves JSON utilizando aliases de validação e serialização.

Download
Olá, daqui é o Alex do DEV STORIES DOT EU. Pydantic: Validação de Dados, episódio 4 de 20. Já foste obrigado a dar o nome a uma variável Python em camel case só para fazer o parse de um payload de uma API externa? Sabes que isso quebra as convenções de nomenclatura standard do Python, mas o JSON que recebes dita a key. A solução para isto são Field Aliases para validação e serialização. Quando ingeres dados, as keys nesse payload muitas vezes não correspondem à forma como queres estruturar o teu código Python. Se um serviço de terceiros enviar um perfil de utilizador com a key user N maiúsculo name, vais querer mapear isso para uma variável standard em snake case chamada user underscore name. O Pydantic lida com esta camada de tradução usando a função Field, especificamente através dos seus argumentos de alias. A abordagem mais simples é o argumento alias base. Quando declaras o atributo do teu model, atribuis-lhe um Field e defines o parâmetro alias para a string esperada do mundo exterior. Se definires o alias para a versão em camel case, o Pydantic usa essa string exata tanto para leitura como para escrita. Ao validar os dados recebidos, ele procura pela key em camel case. Quando mais tarde serializares o model para fazer o dump de volta para JSON, ele escreve a key em camel case. O teu código Python interno opera inteiramente no atributo em snake case, completamente isolado da convenção de nomenclatura externa. Isto resolve o caso de dados simétricos, onde o formato de input e o formato de output são idênticos. Agora, a segunda parte disto são os dados assimétricos. O que acontece quando consomes dados de um sistema legacy usando uma convenção de nomenclatura, mas precisas de os servir a um novo client usando outra? É aqui que divides a lógica usando validation aliases e serialization aliases. Estes são argumentos separados que passas à função Field. Um validation alias dita estritamente o que o Pydantic procura ao criar o model. Se forneceres um validation alias, o Pydantic vai usá-lo para extrair o valor do payload recebido, fazendo override a qualquer alias base que possas ter definido. Por outro lado, um serialization alias controla apenas a fase de output. Quando chamas um método para fazer o dump do model para um dicionário ou JSON string, o Pydantic usa o serialization alias como key de output. Aqui está o ponto chave. Podes definir um único field com três identidades distintas. O validation alias apanha a string de input desorganizada da API legacy. O atributo Python guarda a variável limpa, em snake case, que usas na tua business logic. Finalmente, o serialization alias define a key polida e standardizada que é enviada para o teu frontend. Às vezes, o problema não é uma convenção de nomenclatura rígida, mas sim inconsistente. Podes receber payloads onde o identificador do utilizador está ora em camel case, ora numa única palavra sem espaços. Para lidar com isto, o Pydantic fornece um utilitário chamado alias choices. Em vez de passares uma única string ao validation alias, passas este utilitário contendo uma lista de strings. Durante a validação, o Pydantic examina o payload recebido à procura de cada string na ordem em que a forneceste. No momento em que encontra uma key correspondente, extrai o valor, atribui-o ao teu atributo Python e ignora o resto. Ao separar a forma como é feito o parse dos dados da forma como são exportados, os aliases fazem o decouple do design interno dos teus objetos Python das restrições de nomenclatura arbitrárias do mundo exterior. É tudo por este episódio. Obrigado por ouvires, e continua a programar!
5

Coerção de Dados vs Strict Mode

3m 43s

Assuma o controlo da tendência do Pydantic para a coerção de dados. Irá aprender a impor correspondências de tipo exatas ativando o Strict Mode ao nível do field ou do model.

Download
Olá, daqui é o Alex da DEV STORIES DOT EU. Pydantic: Validação de Dados, episódio 5 de 20. A tendência do Pydantic para converter a string "123" num integer é uma killer feature, até esconder silenciosamente um bug de data-type no teu payload JSON. Tu esperas números, recebes strings, e a tua aplicação avança alegremente até um sistema downstream rigoroso fazer crash. O mecanismo que controla este comportamento é o Data Coercion, e dominá-lo exige compreender o Strict Mode. Por omissão, o Pydantic opera naquilo a que a documentação chama de lax mode. Neste modo, o Pydantic age como um data parser, em vez de ser apenas um type checker. Ele tenta ativamente fazer coerce, ou converter, os dados recebidos para o tipo que declaraste. Se definires um campo como integer, e o payload de entrada fornecer a string "123", o Pydantic avalia a string, extrai o número válido e transforma-o num verdadeiro integer. Este comportamento é incrivelmente útil ao processar user input de web forms ou query parameters, onde cada valor recebido é fundamentalmente uma string. No entanto, quando estás a construir APIs machine-to-machine, a conversão silenciosa é muitas vezes perigosa. Se um cliente promete enviar um integer, mas em vez disso envia uma string, está a quebrar o API contract. O lax mode encobre esta violação. É aqui que entra o strict mode. O strict mode desativa o type coercion automático. Quando o ativas, o Pydantic exige que o data type recebido corresponda exatamente à tua type annotation. Passa a string "123" para um campo strict integer, e o Pydantic rejeita-a imediatamente com um validation error. Isto força a data source a respeitar o schema. Tens duas formas de aplicar o strict mode: globalmente em todo o model, ou localmente em campos específicos. Para o forçares globalmente, modificas a configuração do model. Ao definires a configuration flag strict como true, todos os campos dentro desse model param de fazer coerce aos tipos. Um campo boolean só vai aceitar um valor boolean true ou false, e não a string "true" ou o integer um. Um campo integer só vai aceitar integers. Aqui está o ponto chave. A strictness global é muitas vezes demasiado rígida para aplicações do mundo real, onde os dados chegam de fontes variadas. Normalmente, queres bloquear alguns identificadores críticos, enquanto deixas o resto do model flexível. Para conseguir isto, o Pydantic permite strictness local. Podes forçar o strict mode num campo individual usando tipos especializados fornecidos pela library, como StrictInt, StrictStr ou StrictBool. Se definires um campo de user ID usando StrictInt, esse campo específico vai rejeitar representações em string de números, enquanto o resto do teu model continua a operar em lax mode. Também podes conseguir isto passando uma strict flag diretamente na função de definição do campo para qualquer standard type. Considera um serviço a processar um payload JSON para uma transação financeira. O payload contém um account ID. Se for definido como um integer normal, um payload que entregue o account ID como a string "123" passa sem problemas. O Pydantic corrige o data type em memória. Se atualizares esse campo para usar StrictInt, exatamente o mesmo payload JSON falha a validação. O cliente recebe um erro explícito a informar que o input tem de ser um integer válido, apanhando a violação de contrato na fronteira do sistema antes que polua a tua base de dados. O strict mode transforma o Pydantic de um parser prestável que limpa inputs confusos, num enforcer rígido que garante os data contracts. Obrigado por ouvirem. Fiquem bem, pessoal.
6

Observabilidade no Mundo Real com Logfire

3m 50s

Traga transparência aos seus pipelines de dados. Irá aprender a integrar o Pydantic com o Logfire para monitorizar validações bem-sucedidas e falhadas em tempo real.

Download
Olá, daqui é o Alex da DEV STORIES DOT EU. Pydantic: Data Validation, episódio 6 de 20. Quando um payload complexo falha a validação em produção, a stack trace standard por si só raramente te diz exatamente por que motivo os dados foram rejeitados. Sabes que uma request falhou, mas estás completamente às cegas em relação aos valores reais recebidos que causaram o crash. Esse é exatamente o problema que a Real-World Observability com o Logfire resolve. O Logfire é uma plataforma de observabilidade criada pela equipa do Pydantic, e tem integração direta com o próprio Pydantic. O objetivo é dar-te visibilidade sobre o que a tua camada de data validation está realmente a fazer em produção. Em vez de tratar a validação como uma black box que ocasionalmente lança exceptions, esta integração transforma cada verificação de validação em telemetria rastreada. Considera um background worker a processar registos de utilizadores a partir de uma message queue. Centenas de eventos chegam por segundo. De repente, um registo falha com um validation error. Sem a instrumentação adequada, os teus logs mostram um crash genérico. Tens de ir à caça do payload bruto da queue para descobrir que o utilizador forneceu uma idade de menos cinco. Para corrigir isto, importas o package Logfire e chamas uma única função chamada instrument underscore pydantic. Colocas isto logo a seguir a inicializares o teu client Logfire. A partir desse momento, os teus models Pydantic ficam totalmente observáveis. Não precisas de alterar a forma como defines ou instancias os teus models. Aqui está o ponto chave. Uma vez instrumentado, sempre que o Pydantic valida dados, o Logfire cria automaticamente um span. Um span é simplesmente um registo temporal de uma operação. Se o payload de registo for perfeitamente válido, o Logfire regista um span de sucesso a mostrar exatamente quanto tempo a validação demorou. Isto é extremamente útil se tiveres custom validators complexos e precisares de monitorizar bottlenecks de performance. Se o payload for inválido, o Pydantic lança um validation error. O Logfire apanha este evento e anexa os detalhes à trace. Captura o model específico envolvido e os campos exatos que causaram a falha. Quando olhas para o teu dashboard de observabilidade, não vês apenas uma mensagem de erro genérica. Vês os valores exatos rejeitados, como aquela idade negativa ou uma string de email malformada. O setup é totalmente hands-off. Primeiro, configuras o client. Segundo, chamas a função instrument. Terceiro, deixas o teu worker processar os dados. Quando o worker tenta fazer o parse de uma string JSON inválida para o teu model de registo, a telemetria captura o contexto da falha automaticamente. Escreves absolutamente zero blocos de exception customizados para fazer log do bad input. Como o Logfire entende o Pydantic nativamente, respeita as tuas estruturas de dados. Sabe a diferença entre um missing field e um type mismatch, e formata essa telemetria para que a possas consultar mais tarde. Podes filtrar as tuas métricas para descobrir exatamente quantas vezes o campo de email falhou a validação em todo o teu cluster de workers hoje. O verdadeiro valor desta integração é que eleva a data validation de um simples code check para um evento de observabilidade de primeira classe, transformando rejeições de dados silenciosas em telemetria estruturada e acionável. Se quiseres apoiar o programa, podes encontrar-nos se pesquisares por DevStoriesEU no Patreon. É tudo por este episódio. Obrigado por ouvires, e continua a construir!
7

Validação de Tipos Arbitrários com TypeAdapter

4m 02s

Aprenda a validar primitivas e listas independentes sem criar um BaseModel. Irá descobrir como o TypeAdapter transforma qualquer tipo Python num alvo de validação completo.

Download
Olá, daqui é o Alex da DEV STORIES DOT EU. Pydantic: Validação de Dados, episódio 7 de 20. Às vezes, só precisas de validar uma lista simples de strings que vem de um request de API, mas criar uma model class inteira só para guardar essa única lista parece um exagero enorme. Não queres um objeto wrapper, só queres a lista validada. A solução para isto é a Validação de Tipos Arbitrários com o TypeAdapter. No Pydantic, o workflow standard gira em torno da definição de uma classe que herda do base model. Esse model dá-te acesso a métodos poderosos para fazer parsing e serializar dados. Mas o Pydantic é perfeitamente capaz de validar tipos standard de Python, como um dicionário simples, um integer isolado, uma dataclass standard, ou um typed dict. O problema é que estes tipos standard não possuem inerentemente os métodos de validação do Pydantic. Não podes chamar o validate numa lista standard de Python. É aqui que entra o type adapter. Ele atua como uma ponte, fazendo o wrapping de qualquer tipo arbitrário de Python e expondo todos os métodos familiares do model para ele. Considera um endpoint web que aceita um array JSON raw de strings. No passado, podias ter criado um dummy model com um único campo chamado items, só para poderes passar-lhe o payload JSON. Isso força o cliente a enviar um objeto JSON com uma key items, ou força-te a fazer o unpack do model validado mais tarde. Com um type adapter, saltas o dummy model por completo. Primeiro, instancias o adapter e passas-lhe a definição de tipo exata que esperas. Neste caso, passas o type hint de Python para uma lista de strings. Isto cria um objeto adapter configurado especificamente para essa estrutura exata. Agora, tens acesso aos métodos de validação standard. Pegas no payload JSON raw do teu endpoint e passas isso para o método validate json na tua instância do adapter. O Pydantic faz o parsing da byte string raw, verifica se é um array JSON, verifica se cada elemento lá dentro é uma string, e devolve uma lista standard de Python. Se o payload contiver um integer ou um boolean, ele lança um validation error exatamente como um model normal faria. Aqui está o ponto chave. O adapter não se limita a uma validação simples. Ele espelha completamente a core API de um model standard. Isto significa que também o podes usar para serializar dados. Se tiveres um dicionário complexo ou uma dataclass standard de Python e precisares de o converter de volta para uma JSON string, passas esses dados para o método dump json no teu adapter. Ele aplica as mesmas regras de serialização, custom encoders e formatação que o Pydantic aplica aos models normais. Esta feature é particularmente útil quando trabalhas com typed dicts. Um typed dict fornece structural typing para dicionários standard de Python, mas faz zero validação em runtime. Ao passares um typed dict para um adapter, obténs o enforcement total da estrutura do dicionário em runtime. Isto garante que todas as required keys estão presentes e que os valores correspondem aos tipos esperados, sem converter o dicionário numa instância de objeto. O output continua a ser um dicionário simples. Instanciar um adapter requer que o Pydantic construa validation schemas internos. Como este processo de setup consome um pouco de tempo de computação, deves criar as tuas instâncias do adapter ao nível do module, em vez de as reconstruíres dentro de uma função sempre que um endpoint é chamado. Define o adapter uma única vez no topo do teu ficheiro, e reutiliza-o em múltiplos requests. O type adapter dá-te todo o poder do core validation engine para qualquer tipo standard de Python, mantendo as tuas estruturas de dados limpas e livres de wrapper classes desnecessárias. Por hoje é tudo. Obrigado por ouvires — vai construir algo fixe.
8

Tipos Union e Validação Inteligente

3m 24s

Compreenda as complexidades da validação de tipos Union. Irá aprender como o Smart Mode do Pydantic avalia a exatidão e os fields válidos para escolher a melhor correspondência.

Download
Olá, daqui fala o Alex da DEV STORIES DOT EU. Pydantic: Validação de Dados, episódio 8 de 20. Quando um campo é anotado como uma Union de uma string ou de um integer, e passas o integer 123, que validação é que o Pydantic tenta primeiro? Se assumires que ele simplesmente lê o teu código da esquerda para a direita, podes surpreender-te quando os teus dados se comportarem de maneira diferente do esperado. Isto leva-nos aos Union Types e à Smart Validation. Um union type permite que um único campo aceite múltiplos tipos de dados distintos. Validar unions é inerentemente complexo porque o Pydantic tenta ativamente fazer a coerção dos dados para o tipo solicitado. Um integer pode facilmente tornar-se numa string, e uma string contendo dígitos pode ser convertida num integer. Se o motor de validação simplesmente pegasse na primeira correspondência que encontrasse, o teu output mudaria completamente com base na ordem arbitrária em que listaste os tipos no teu código. Este comportamento rígido existe, e chama-se modo Left to Right. Neste modo, o sistema avalia o input em relação ao primeiro tipo definido na union. Se a validação for bem-sucedida, para imediatamente. Se falhar, passa para o segundo tipo. Se o teu campo for tipado como string ou integer, nessa ordem, e passares o integer 123, o modo Left to Right avalia primeiro a condição da string. Como o integer 123 pode sofrer coerção perfeitamente para a string "123", a validação passa. O teu integer é silenciosamente convertido numa string apenas porque a string foi escrita primeiro. Aqui está o ponto-chave. Por defeito, o Pydantic evita esta armadilha usando o Smart Mode. Em vez de parar na primeira correspondência aceitável, o Smart Mode avalia o input em relação a todos os tipos possíveis na union. De seguida, compara as validações bem-sucedidas e escolhe a melhor correspondência com base em critérios de pontuação específicos. O critério principal para tipos simples é a exatidão. O Smart Mode penaliza fortemente a coerção de dados. Voltando ao nosso cenário anterior com um campo tipado como string ou integer. Quando passas o integer 123, o Smart Mode testa ambas as opções. Ele reconhece que o input pode sofrer coerção para uma string válida, mas também percebe que o input já é uma correspondência perfeita e exata para um integer. Como uma correspondência exata supera sempre uma correspondência por coerção, o Smart Mode devolve corretamente o integer 123, independentemente de qual tipo foi escrito primeiro na union. Quando a tua union contém modelos de dados complexos em vez de tipos básicos, o Smart Mode baseia-se numa métrica diferente. Ele conta o número de campos válidos definidos. O motor avalia o dictionary de input em relação a cada modelo na union. Ele calcula quantos campos no input mapeiam exatamente para os campos definidos de cada modelo. O modelo que absorver com sucesso o maior número de campos de input sem lançar erros de validação é declarado o vencedor. Isto impede que um modelo menor e menos específico engula dados que foram claramente destinados a um modelo maior e mais detalhado na mesma union. A Smart Validation garante que os teus dados mantêm a sua forma original precisa sempre que possível, protegendo-te de erros de coerção silenciosos que são notoriamente difíceis de rastrear em produção. Obrigado por ouvirem, happy coding a todos!
9

Ferramenta Poderosa: Discriminated Unions

3m 29s

Potencie o desempenho da sua validação. Irá aprender a utilizar Discriminated (Tagged) Unions para dizer ao Pydantic exatamente qual schema aplicar com base num field específico.

Download
Olá, daqui é o Alex da DEV STORIES DOT EU. Pydantic: Data Validation, episódio 9 de 20. Validar um payload recebido contra vinte data models diferentes por tentativa e erro é um pesadelo de performance. Quando o teu sistema recebe um event genérico, adivinhar qual schema aplicar desperdiça ciclos de CPU e gera mensagens de erro extremamente confusas quando a validação falha. Podes evitar completamente este jogo de adivinhação usando uma ferramenta poderosa: Discriminated Unions. Uma union standard diz ao Pydantic que um field pode ser um de vários models diferentes. Por default, o Pydantic pega nos dados recebidos e testa-os contra o primeiro model. Se isso falhar, tenta o segundo, e assim por diante. Este parsing sequencial é ineficiente. As discriminated unions resolvem isto usando uma tag explícita. Supõe que estás a construir um pipeline de analytics que recebe diferentes event types, como um event de click, um event de scroll e um event de purchase. Cada event requer data fields diferentes. O model de click pode precisar de um element ID, enquanto o model de purchase precisa de um valor de transação. Para configurares uma discriminated union, adicionas um field partilhado a cada model individual desse grupo. Podes chamar a este field event type. A seguir, atribuis um tipo de literal string a este field. O model de click garante que o event type é exatamente a string click. O model de purchase garante estritamente a string purchase. A seguir, crias o teu model de payload principal. Este model tem um único field de event, definido como uma union dos teus event models específicos. É aqui que configuras o discriminator. Envolves a definição da union numa configuração de field do Pydantic, e atribuis a string event type ao argumento discriminator. Aqui está o ponto chave. Quando um payload chega, o Pydantic já não testa os models um a um. Ele olha diretamente para a key event type nos dados recebidos. Se o valor for purchase, o Pydantic encaminha imediatamente todo o payload para o model de purchase. É um lookup direto. Se o valor da transação estiver em falta, a mensagem de erro indica claramente que falta um field obrigatório para um event de purchase, em vez de gerar uma parede de texto enorme a explicar como os dados falharam em corresponder a todos os event types possíveis. Isto cobre uma estrutura limpa onde cada payload partilha uma key de top-level. Às vezes, estás a lidar com dados não estruturados de terceiros, onde a tag de identificação está aninhada dentro de outro object, ou o model correto depende da presença de keys específicas em vez de um único valor dedicado. Para estas situações, o Pydantic fornece callable discriminators. Em vez de passares um nome de field em string para o argumento discriminator, passas uma função customizada. Esta função recebe os dados de input raw e não validados. Escreves a lógica dentro desta função para inspecionar o dictionary raw, encontrar qualquer pista que determine o data type, e retornar uma string tag simples que representa o model correto. O Pydantic executa a tua função primeiro, recebe a string tag de volta, e usa-a para encaminhar os dados para o model preciso na union. Usar uma discriminated union transforma a validação de um jogo de adivinhação sequencial num lookup preciso e de tempo constante. Obrigado por ouvirem, tenham todos um ótimo dia!
10

Pré-processamento com Before e Wrap Validators

3m 50s

Lide com dados de entrada desorganizados antes que atinjam o seu schema. Irá aprender a utilizar os field validators Before e Wrap para limpar o input bruto antes que o Pydantic o avalie.

Download
Olá, daqui fala o Alex da DEV STORIES DOT EU. Pydantic: Validação de Dados, episódio 10 de 20. Às vezes, os dados recebidos são tão desorganizados que o parsing standard falha assim que tocam no teu model. Tens de intercetar e sanitizar o raw input antes mesmo de o framework o tentar ler. É exatamente isso que o pré-processamento com os validadores Before e Wrap te permite fazer. O Pydantic normalmente faz um excelente trabalho a converter os dados para o tipo certo automaticamente. Mas se a estrutura fundamental dos dados estiver completamente errada, a coerção falha imediatamente. Um validador Before foi desenhado para este problema. É uma função associada a um field que é executada antes de o Pydantic fazer qualquer type checking ou conversão. Recebe o raw input intacto, exatamente como foi passado para o model. Considera um cenário em que o teu model define um field que exige estritamente uma lista de inteiros. No entanto, estás a consumir uma API externa que envia incorretamente estes dados como uma única string contínua de números separados por vírgulas, como a string um vírgula dois vírgula três. O Pydantic espera um array, vê uma única string e rejeita-a com um erro de validação. Tu corriges isto ao escreveres um validador Before. Dentro da tua função de validação, olhas para o raw input. Verificas se o valor é uma string. Se for, fazes split dessa string em cada vírgula, o que cria uma lista de caracteres individuais de string. Não tens de converter esses caracteres em inteiros tu mesmo. Simplesmente retornas a lista recém-criada. O Pydantic assume o controlo a partir daí. Vê a lista que estava à espera, executa a sua coerção interna standard e converte esses valores de string para inteiros por ti. Só precisaste de corrigir a forma estrutural dos dados. Isto cobre os inputs que correm antes da lógica principal. O próximo nível de controlo é o validador Wrap. Os validadores Wrap são a ferramenta de validação mais flexível que o Pydantic oferece. Em vez de simplesmente correr antes do passo de validação, um validador Wrap envolve literalmente o motor de validação interno do Pydantic para esse field. Quando escreves um validador Wrap, a tua função recebe dois argumentos. O primeiro é o raw input, tal como no validador Before. O segundo argumento é uma função handler. Este handler representa a lógica central de validação e coerção do Pydantic. É aqui que a coisa fica interessante. Tu decides exatamente quando, ou mesmo se, essa função handler corre. O fluxo lógico está inteiramente nas tuas mãos. Podes inspecionar o raw input e modificá-lo. A seguir, chamas explicitamente o handler, passando-lhe os teus dados limpos. O Pydantic corre o seu type checking interno naquilo que forneceste e retorna o valor totalmente parsed de volta para o teu validador. Podes então modificar esse valor parsed novamente antes de o passares para o model final. Como controlas quando o handler é executado, podes colocá-lo dentro de um bloco try except standard. Se a validação interna do Pydantic lançar um erro, apanhas esse erro logo ali no validador Wrap. Podes fazer log do erro, alterar os dados e tentar novamente, ou simplesmente retornar um valor default seguro. Podes até mesmo escrever lógica que ignore completamente o handler para certos inputs específicos, fazendo bypass à validação standard por completo. Os validadores Before sanitizam formatos de input inválidos para que o Pydantic os consiga ler, enquanto os validadores Wrap te dão autoridade total sobre todo o ciclo de vida de validação à volta de um único field. É tudo por este episódio. Obrigado por ouvires, e continua a programar!
11

Pós-processamento com After e Plain Validators

3m 34s

Imponha regras estritas de lógica de negócio. Irá aprender a utilizar After validators para verificar dados já processados, e Plain validators para contornar o Pydantic por completo.

Download
Olá, daqui fala o Alex da DEV STORIES DOT EU. Pydantic: Validação de Dados, episódio 11 de 20. Verificar se uma string tem o formato de um e-mail é simples. Verificar se os dados cumprem uma business logic rigorosa, como fazer cross-reference com um sistema externo ou impor regras matemáticas específicas, requer um local seguro para correr custom code. É exatamente isso que o post-processing com validadores After e Plain oferece. Quando defines um field num model Pydantic, a library verifica automaticamente o input contra o type hint. Os types só te levam até certo ponto. Um integer é um integer, seja um ou um milhão. Para impor regras para além dos types básicos, adicionas funções de validação custom. O Pydantic permite-te injetar estas funções no lifecycle de validação. O ponto de injeção mais comum é o validador After. Como o nome sugere, este corre depois de o Pydantic terminar o seu parsing interno e type coercion. Aqui está o ponto chave. Quando a tua função custom recebe os dados num validador After, o Pydantic garante que os dados já correspondem ao type do field. Não tens de escrever boilerplate code para lidar com type conversion ou apanhar data types inesperados. Imagina um cenário em que precisas de garantir que um field integer é um número par. Defines um model com um field tipado como integer. A seguir, escreves uma função custom que recebe um value como argumento. Como configuras esta função como um validador After, sabes que o value é absolutamente um integer. Simplesmente usas o operador modulo para verificar se a divisão do value por dois deixa resto. Se o resto não for zero, fazes raise de um ValueError standard do Python com uma mensagem custom. Se o resto for zero, fazes return do value. O Pydantic pega nesse value retornado e atribui-o ao model. A divisão de trabalho é clara. O Pydantic garante o type, e tu garantes a business rule. Às vezes, o parsing default do Pydantic atrapalha. É aí que entra o validador Plain. Um validador Plain substitui completamente a validação interna do Pydantic para um field específico. O Pydantic afasta-se e passa o raw input não validado diretamente para a tua função custom. Usas um validador Plain quando as regras de coercion standard não se adequam ao teu use case, ou quando estás a lidar com uma data structure altamente custom que o Pydantic não entende nativamente. Neste cenário, a tua função é responsável por tudo. Recebe o raw input, faz qualquer type checking necessário, converte os dados e aplica a business logic. Se algo falhar, a tua função tem de fazer raise de um ValueError ou de um AssertionError. Se tiver sucesso, faz return do value final e limpo para o model. Podes associar ambos os validadores a fields usando decorators do Pydantic em class methods, ou adicionando-os como metadata diretamente dentro do type hint usando annotations. A escolha entre eles resume-se a quanto do trabalho queres fazer tu mesmo. Usa um validador After quando quiseres que o Pydantic faça o trabalho pesado da type conversion, e recorre a um validador Plain apenas quando precisares de controlo absoluto sobre o parsing do raw input a partir do zero. Obrigado por ouvires — até à próxima.
12

Hooks de Validação ao Nível do Model

3m 16s

Valide interações entre múltiplos fields. Irá aprender a utilizar o decorador model_validator para impor regras que dependem de todo o payload.

Download
Olá, daqui é o Alex da DEV STORIES DOT EU. Pydantic: Data Validation, episódio 12 de 20. Validar fields isoladamente funciona perfeitamente, até ao momento em que a tua business logic dita que o field B só pode ser definido se o field A tiver um valor específico. Quando a integridade dos dados depende da interação de vários fields, precisas de validation hooks ao nível do model. No Pydantic, lidas com fields interdependentes usando o decorator model validator. Ao contrário dos field validators, que se focam num único dado recebido, um model validator olha para toda a estrutura de dados de uma só vez. O Pydantic oferece três modos para este decorator: before, after e wrap. Eles determinam exatamente quando a tua lógica customizada é executada durante o lifecycle de parsing. Vamos aplicar isto a um model standard de registo de utilizador. Tens dois fields: password e password repeat. Uma verificação ao nível do field pode verificar o comprimento ou a complexidade, mas não consegue comparar os dois. Para isso, usas um model validator no modo after. O modo after é executado assim que o Pydantic faz o parsing e valida com sucesso todos os fields individuais. Nesta fase, a tua função de validação recebe o próprio model instanciado. Simplesmente escreves a lógica que verifica se o atributo password do model é igual ao seu atributo password repeat. Se forem diferentes, fazes raise de um ValueError. Aqui está o ponto crucial. Ao usar o modo after, a tua função tem de retornar explicitamente a instância do model, geralmente chamada de self, no final do método. Se te esqueceres de retornar o self, o Pydantic vai descartar os teus dados validados e não retorna nada. Às vezes, precisas de intercetar os dados mais cedo. É aí que entra o modo before. Um model validator no modo before corre antes de o Pydantic tentar qualquer parsing ou type coercion. Em vez de uma instância de model tipada, a tua função recebe o raw input, que normalmente é um dicionário. Usas este modo quando a estrutura de dados raw é confusa e precisa de ajustes antes mesmo de a validação standard poder começar. Por exemplo, se requests de uma API legacy enviarem configurações de password num dicionário nested, um before validator pode extrair essas strings e fazer flatten para as top-level keys que o teu model Pydantic espera. A função depois retorna o dicionário modificado, passando-o para a frente na chain. O terceiro modo é o wrap. Isto serve para teres controlo total sobre o lifecycle de validação. Um wrap validator recebe os dados de raw input e uma função handler. Corres a tua lógica de pré-processamento, chamas explicitamente o handler para fazer trigger da validação interna do Pydantic, e depois corres o pós-processamento no resultado. Usas isto quando precisas de apanhar erros de validação internos do Pydantic, fazer log deles para um sistema externo, e talvez retornar uma mensagem de erro modificada ou um objeto de fallback default. Escolher o modo certo é apenas uma questão de timing. Usa before para moldar o raw input, after para comparar fields strongly typed, e wrap para controlar a própria execução da validação. Se achas estes episódios úteis e queres apoiar o programa, podes procurar por DevStoriesEU no Patreon. É tudo por este episódio. Até à próxima!
13

Serialização: Exportar Dados com Segurança

3m 39s

Controle como os seus dados saem do sistema. Irá aprender as diferenças entre fazer dump para dicts Python versus strings JSON, e como excluir fields não definidos ou com valores por defeito.

Download
Olá, daqui é o Alex da DEV STORIES DOT EU. Pydantic: Validação de Dados, episódio 13 de 20. Obter dados válidos no teu sistema é apenas metade da batalha. Quando chega a hora de devolver esses dados a um frontend, muitas vezes dás por ti com os teus payloads cheios de campos vazios e valores por defeito que o utilizador nunca chegou a fornecer. A serialização, ou fazer o dump de dados de forma segura, é a forma como limpas esse fluxo de saída. Assim que os teus dados estiverem seguros dentro de um model Pydantic, vais acabar por precisar de os extrair para os enviar para outro lado. Tens duas formas principais de o fazer. A primeira é chamar o model dump. Este método lê o teu model e devolve um dicionário Python simples. A segunda é chamar o model dump json. Este método salta a etapa do dicionário e devolve uma string JSON totalmente formatada, pronta para ser enviada pela rede. A diferença entre estes dois vai um pouco mais fundo do que apenas um dicionário versus uma string. Tudo se resume aos modos de serialização. Por defeito, o model dump opera em modo Python. Se o teu model contiver um tipo complexo, como um objeto datetime, o dicionário resultante continuará a conter um objeto datetime do Python. Por outro lado, o model dump json opera em modo JSON. O JSON não sabe o que é um objeto datetime do Python, por isso o Pydantic converte-o automaticamente numa representação em string standard. Aqui está o ponto chave. Podes mesmo forçar o output do dicionário a usar o modo JSON. Se chamares o model dump e passares o argumento mode definido como json, o Pydantic devolve um dicionário onde todos os tipos complexos já foram traduzidos para formatos básicos e seguros para JSON, como strings e integers. Isso trata dos tipos, mas ainda tens de gerir a forma do payload. Imagina um model de perfil de utilizador a devolver dados a um frontend. O model pode definir vinte campos possíveis. Um novo utilizador regista-se e fornece apenas o seu nome e email. Os outros dezoito campos fazem fallback para strings vazias, nulls ou URLs de avatar por defeito. Se fizeres o dump desse model normalmente, envias todos os vinte campos para o frontend. Para corrigir isto, o Pydantic fornece três keyword arguments específicos que podes passar a qualquer um dos métodos de dump. O mais preciso é o exclude unset. Quando defines o exclude unset como true, o Pydantic rastreia exatamente quais os campos que foram preenchidos quando o model foi criado. Ele fará o dump apenas do nome e do email. Os dezoito campos por defeito ficam completamente de fora do dicionário ou da string JSON. Isto garante que nunca fazes leak de dados de fallback que o utilizador não chegou a submeter. Se quiseres um comportamento ligeiramente diferente, podes usar o exclude defaults. Esta flag diz ao Pydantic para omitir qualquer campo que corresponda atualmente ao seu valor por defeito. Não interessa se o utilizador submeteu explicitamente esse valor por defeito ou se o sistema o preencheu automaticamente. Se o valor corresponder ao valor por defeito, é removido do output. Finalmente, tens o exclude none. Define isto como true, e o Pydantic vai remover qualquer campo onde o valor seja atualmente none. Isto é puramente uma verificação de valor e ignora por completo os defaults ou o tracking de unset. Estas flags de exclusão dão-te um controlo rigoroso sobre o teu tráfego de rede e respostas da API. Mantém os teus models internos completamente abrangentes, mas usa os teus métodos de dump para garantir que os teus payloads externos se mantêm exatamente tão leves quanto precisam de ser. Obrigado por ouvires. Até à próxima!
14

Personalizar a Lógica de Serialização

3m 49s

Altere a forma como os seus tipos são representados à saída. Irá aprender a escrever serializers personalizados de Field e Model para mutar dados durante a fase de dump.

Download
Olá, daqui é o Alex da DEV STORIES DOT EU. Pydantic: Validação de Dados, episódio 14 de 20. E se armazenares uma data internamente como um objeto datetime de Python, mas o contrato da tua API de frontend exigir um Unix timestamp integer bruto? Poderias iterar sobre os teus dados mesmo antes de os enviar, mas isso é confuso e propenso a erros. A maneira mais limpa é personalizares a lógica de serialization diretamente dentro dos teus modelos Pydantic. O Pydantic dá-te decorators para intercetar o momento exato em que um modelo se transforma novamente num dictionary ou JSON. Vamos começar com field serializers. Um field serializer tem como alvo um atributo específico. Para criares um, escreves um método normal dentro da tua model class e colocas o decorator field serializer diretamente por cima dele. Passas ao decorator o nome do field que queres modificar. Vamos usar esse cenário do datetime. Tens um modelo com um atributo chamado created at, tipado como um datetime standard de Python. Dentro do modelo, crias um método chamado serialize created at. O nome do método não importa. Por cima, colocas o decorator field serializer, a apontar para o field created at. O método recebe o valor datetime como input. Dentro do método, chamas a função timestamp standard nesse datetime e retornas o integer resultante. Agora, sempre que o modelo faz dump dos seus dados, o Pydantic interceta o field created at, executa o teu método customizado e devolve um integer limpo em vez de uma string com formatação ISO. Aqui está o ponto chave. Os serializers operam em dois modos distintos: plain e wrap. O modo plain é o default. Quando um serializer está no modo plain, o Pydantic descarta completamente a sua própria lógica interna para esse field e executa apenas o teu código customizado. É um override completo. Mas às vezes precisas de executar a lógica default primeiro, e depois modificar o resultado. Ou talvez queiras fazer catch de erros à volta do comportamento default. É aí que usas o modo wrap. Para o ativares, passas mode igual a wrap para o decorator. No modo wrap, o teu método recebe um segundo argumento chamado handler. Este handler é uma referência à lógica de serialization interna do Pydantic. Podes chamar o handler para obter o output default, inspecioná-lo, modificá-lo, ou fazer fallback para ele caso a tua lógica customizada falhe. Isso cobre fields individuais. Se precisares de alterar a estrutura de todo o output, usas um model serializer. O setup é quase idêntico, mas o decorator fica por cima de um método que opera em toda a instância do modelo. Em vez de receber o valor de um único field, o método acede aos atributos do próprio modelo. Se colocares um model serializer no modo plain, retornas uma estrutura de dictionary completamente nova, criada do zero. Se o colocares no modo wrap, o teu método recebe um argumento handler, tal como o field serializer. Chamas o handler para obter primeiro o dictionary standard do modelo. A seguir, podes adicionar novas top-level keys, remover dados privados, ou fazer flatten de estruturas aninhadas antes de retornar o dictionary final. O aspeto mais poderoso destes decorators é que eles desacoplam os teus tipos Python internos dos teus contratos de API externos, mantendo a validação rigorosa na entrada e a formatação precisa na saída. É tudo por este episódio. Obrigado por ouvires, e continua a desenvolver!
15

Gerar JSON Schema a partir de Models

3m 44s

Transforme os seus models em contratos de API auto-documentados. Irá aprender a gerar JSON Schemas compatíveis com OpenAPI e a injetar exemplos diretamente no schema.

Download
Olá, daqui é o Alex do DEV STORIES DOT EU. Pydantic: Validação de Dados, episódio 15 de 20. Se os teus schemas de API já são estritamente tipados em Python, ter de manter um ficheiro YAML separado para a tua documentação OpenAPI é uma enorme perda de tempo. Acabas por manter duas fontes de verdade que inevitavelmente divergem. Gerar o JSON Schema diretamente a partir dos teus models resolve este problema de sincronização. Cada model Pydantic vem com um método chamado model json schema. Quando chamas este método, o Pydantic inspeciona o teu model. Ele lê os campos, os tipos, os valores por defeito e as restrições de validação. A seguir, traduz toda essa lógica interna de Python para um dicionário JSON Schema standard. Especificamente, o Pydantic emite o Draft 2020-12 da especificação JSON Schema. Esta é a parte que interessa. Como o output segue este standard amplamente aceite, é nativamente compatível com OpenAPI. Defines as tuas regras de validação estritas uma única vez em Python, e a framework fornece automaticamente a definição exata do schema de que os teus consumidores externos precisam. Não é necessária qualquer tradução manual. A geração standard do schema lida perfeitamente com tipos e restrições básicas. Mas, às vezes, precisas de comunicar business logic ou formatos específicos que não podem ser inferidos apenas por um type hint de Python. Considera um cenário em que estás a construir um model Configuration para um novo serviço. O model contém um campo que aceita um dicionário de custom settings. A equipa de frontend precisa de saber exatamente qual é o aspeto de um payload válido, em vez de apenas saber que se trata de um objeto genérico. Para resolver isto, usas uma feature chamada json schema extra. Este parâmetro permite-te injetar custom metadata arbitrária diretamente no JSON Schema gerado. Podes usá-lo para adicionar mock examples, descrições customizadas ou marcadores de keywords específicos que a tua API gateway possa exigir. Podes aplicar o json schema extra a dois níveis distintos. Podes anexá-lo a um campo individual, ou podes aplicá-lo a todo o model. Para fornecer um mock example para esse campo de settings específico, defines o teu model Configuration. Para o atributo de settings complexas, atribuis-lhe uma função Field. Dentro dessa função Field, passas o argumento json schema extra. Passas-lhe um dicionário contendo a chave standard do JSON Schema chamada examples. O valor mapeado para essa chave é uma lista que contém o teu payload exato de mock configuration. Em alternativa, se quiseres documentar o model inteiro em vez de um único campo, defines um dicionário model config na classe. Dentro desse dicionário de configuração, forneces o json schema extra com um exemplo ao nível do schema. Esta abordagem é muito útil quando queres mostrar como vários campos interagem entre si num request body completo. Quando executas o model json schema no teu model Configuration, o Pydantic constrói a árvore standard do schema. Quando chega aos teus campos ou à configuração do model, ele faz merge do teu dicionário de exemplos customizado diretamente no standard output. O tooling de frontend lê este schema, faz parse da propriedade examples, e exibe imediatamente o mock payload aos developers. Eles sabem exatamente o que enviar, e o teu código Python permanece a única fonte de verdade. O verdadeiro poder da geração de schemas do Pydantic é que qualquer ferramenta externa criada para o ecossistema JSON Schema pode consumir imediatamente as tuas regras de validação em Python sem integração customizada. Obrigado por passares uns minutos comigo. Até à próxima, fica bem.
16

RootModel: Quando o seu Payload não é um Dicionário

3m 09s

Lide com payloads JSON não padronizados de forma elegante. Irá descobrir como o RootModel permite processar arrays e primitivas ao nível da raiz, mantendo os poderes do BaseModel.

Download
Olá, daqui é o Alex do DEV STORIES DOT EU. Pydantic: Validação de Dados, episódio 16 de 20. Os modelos standard assumem que o teu payload JSON de entrada é um objeto mapeado com chaves e valores. Mas o que acontece quando um endpoint precisa de aceitar um top-level array diretamente, ou apenas uma string isolada, sem a envolver num dicionário? É exatamente para isso que o RootModel: Quando o Teu Payload Não É um Dicionário foi criado. Quando usas um base model standard, o Pydantic mapeia os atributos da tua classe para chaves JSON. Se enviares uma raw list para um modelo standard, como um array JSON de números, a validação falha. Ele espera uma estrutura de dicionário. Para contornar isto, os developers muitas vezes forçam o cliente a alterar o payload. Eles criam uma dummy key, talvez chamada items, e envolvem o array num objeto. Acabas por distorcer o design da tua API apenas para deixar a tua library de validação feliz. O RootModel elimina essa fricção. É um modelo especial do Pydantic desenhado especificamente para payloads onde a estrutura mais externa é uma lista, um tuplo, ou um tipo primitivo como um inteiro ou uma string. Considera um endpoint de bulk-delete. Queres que o cliente envie um array JSON raw contendo user IDs inteiros, e mais nada. Para lidar com isto, importas o RootModel do Pydantic. Defines uma nova classe, talvez chamada UserIdList, e fazes com que herde de RootModel. Parametrizas essa herança com uma lista de inteiros. Quando o array JSON raw chega ao servidor, passas isso diretamente para o método model validate na tua classe UserIdList. O Pydantic aceita o top-level array nativamente. Ele itera pelo payload, garante que cada item é um inteiro válido, e devolve uma instância do modelo totalmente validada. Aqui está o ponto chave. Mesmo validando uma flat list, um RootModel fornece exatamente a mesma interface que um modelo normal. Continuas a ter acesso aos métodos standard. Podes chamar o model dump para converter os dados de volta para objetos Python, ou o model dump json para gerar uma raw string. Como não há campos nomeados no teu payload, precisas de uma forma de aceder aos dados depois de validados. O Pydantic guarda os dados parsed num único atributo chamado exatamente root. Se quiseres fazer um loop por esses user IDs validados, simplesmente iteras sobre o atributo root na tua instância do modelo. Este mecanismo não se restringe a listas. Podes definir um RootModel para uma única string ou um inteiro. Se receberes um payload de string isolada, mas precisares de o passar por verificações estritas de tamanho ou pattern matching, defini-lo como um RootModel do tipo string permite-te anexar essas regras de validação nativamente. Os dados permanecem uma simples string no payload, mas ganham a proteção total do motor de validação. Sempre que dês por ti a inventar uma dictionary key apenas para o Pydantic ter algo para fazer parse, estás a usar a ferramenta errada. Usa o RootModel para adaptar a tua camada de validação ao teu contrato de API, em vez de alterares o teu contrato de API para satisfazer a tua camada de validação. Obrigado por ouvirem. Fiquem bem, pessoal.
17

Dataclasses Standard vs Dataclasses do Pydantic

3m 55s

Traga validação para as suas classes Python nativas. Irá aprender quando utilizar o decorador dataclass do Pydantic para modernizar bases de código legadas sem reescrever tudo.

Download
Olá, daqui fala o Alex da DEV STORIES DOT EU. Pydantic: Validação de Dados, episódio 17 de 20. Tens uma codebase enorme construída inteiramente com dataclasses standard do Python e percebes que precisas desesperadamente de validação em runtime. Podes pensar que tens de reescrever tudo para herdar de um BaseModel. Mas não precisas. Hoje, vamos analisar as dataclasses standard versus as dataclasses do Pydantic. A standard library do Python fornece um decorator de dataclass que é excelente para reduzir o boilerplate. Ele escreve os métodos de inicialização, representação e igualdade por ti. No entanto, confia cegamente nos teus inputs. Se declarares um atributo de idade como um integer e lhe passares uma string, a dataclass standard simplesmente aceita a string. Fornece type hints para análise estática, mas oferece zero segurança em runtime. O Pydantic resolve isto com o seu próprio decorator de dataclass. Foi desenhado especificamente como um drop-in replacement para a versão da standard library. Manténs exatamente a mesma estrutura de classes. Não adicionas nenhuma classe base. Apenas mudas o teu import para puxar o decorator do módulo pydantic dot dataclasses em vez da standard library. Considera aquela codebase legada construída com dataclasses standard. Encontras uma dataclass a lidar com um objeto de configuração. Trocas o decorator standard pelo decorator do Pydantic. Instantaneamente, sempre que a tua aplicação cria esse objeto de configuração, o Pydantic interceta a inicialização. Lê os teus type hints existentes e aplica-os. Se for passado um tipo inválido, o Pydantic tenta fazer a coerção. Se a coerção falhar, lança imediatamente um erro de validação. Ganhas atribuições estritas e com verificação de tipos, com zero alterações estruturais na tua árvore de herança. Aqui está o ponto chave. Se ambas as opções te dão validação, tens de perceber a diferença entre uma dataclass do Pydantic e um BaseModel standard. Lidam com os dados subjacentes de forma diferente. Um BaseModel é fundamentalmente construído à volta do parsing de dicionários e fornece uma vasta gama de métodos built-in para exportar dados. Uma dataclass do Pydantic continua a ser uma classe Python standard na sua essência, mantendo o seu memory footprint e comportamento tradicionais. Por continuar a ser uma classe standard, a forma como o Pydantic aplica a validação muda. Quando instancias uma dataclass do Pydantic, os argumentos são copiados. Os dados passam pelo engine principal de validação do Pydantic, que faz o parsing e constrói novos objetos para corresponderem aos teus type hints. Não referencia apenas os inputs mutáveis originais que forneceste. Se passares uma lista para uma dataclass do Pydantic, o validador processa-a, valida os elementos internos e atribui uma lista completamente nova à instância. A lista de input original e o atributo na tua dataclass já não são o mesmo objeto na memória. Este comportamento de cópia garante que os teus dados aderem estritamente ao schema sem mutar as variáveis de input originais. A utilidade principal da dataclass do Pydantic é fazer a ponte entre os paradigmas standard do Python e uma validação rigorosa. Se precisares de um caminho de migração limpo para código legado que já usa dataclasses standard, basta trocares o decorator para obteres type safety instantânea, preservando toda a semântica da tua classe existente. Se gostas do podcast e queres apoiar o programa, podes procurar por DevStoriesEU no Patreon. Por este episódio é tudo. Obrigado por ouvires, e continua a programar!
18

Ajuste Fino da Configuração do Model

3m 58s

Controle o rigor de todo o seu model. Irá aprender a utilizar o ConfigDict para proibir atributos extra, congelar instâncias e validar atribuições.

Download
Olá, daqui é o Alex da DEV STORIES DOT EU. Pydantic: Validação de Dados, episódio 18 de 20. Por defeito, o Pydantic ignora silenciosamente quaisquer keys JSON extra que lhe envies. Numa API rigorosa, ignorar dados desconhecidos sem aviso é um enorme risco de segurança. Para corrigir isto, precisas de afinar a configuração do model. Para alterar o comportamento de um model globalmente, defines um atributo de classe chamado model config. Atribuis-lhe um ConfigDict, que é um dicionário tipado importado diretamente do Pydantic. Colocas esta atribuição mesmo dentro do teu model, juntamente com as definições dos teus fields. Como o ConfigDict é tipado, o teu editor de código vai apanhar erros de digitação se tentares passar uma opção de configuração inválida. As regras que colocares neste dicionário vão ditar como todo o model faz o parse, valida e armazena os dados. Vamos construir um model de configurações de segurança rigorosas para uma aplicação. Um cliente malicioso pode enviar um payload JSON com fields inesperados, talvez a tentar injetar uma flag de admin ou a sobrescrever um parâmetro oculto. Por defeito, o Pydantic define o comportamento dos fields extra para ignore. Lê os fields que espera, descarta silenciosamente todos os dados desconhecidos e cria o model. Para fechar esta brecha, adicionas o parâmetro extra ao teu ConfigDict e defines o seu valor para a string forbid. Agora, se um cliente enviar uma key inesperada, o Pydantic lança imediatamente um erro de validação. O request falha logo, rejeitando explicitamente o mau payload antes mesmo que a lógica da tua aplicação o processe. Isto trata da fronteira entre o mundo exterior e o teu sistema. Mas o que acontece dentro do teu sistema depois de o model ser criado? Normalmente, o Pydantic só valida os dados durante a inicialização. Se outro developer escrever código que altere um atributo numa instância de model existente mais tarde, o Pydantic não interfere. Poderias acidentalmente atribuir uma raw string a um field inteiro, e o model aceitaria. Para evitar isto, podes definir validate assignment para true dentro do teu ConfigDict. Com isto ativado, sempre que um atributo for modificado em memória, o Pydantic interceta a alteração e corre exatamente a mesma lógica de validação que usa durante a criação. Às vezes, até mesmo validar mutações é demasiado permissivo para configurações de segurança. Podes querer uma garantia absoluta de que as configurações não podem ser modificadas em memória por nenhuma parte do teu código depois de passarem a verificação inicial. É aqui que a coisa fica interessante. Podes definir o parâmetro frozen para true na configuração do teu model. Isto torna toda a instância do model imutável. Se alguma função downstream tentar atualizar um field, o Pydantic levanta um erro. Um model frozen comporta-se exatamente como um tuple em Python. Como não pode ser alterado, um model frozen é completamente seguro para ser partilhado entre diferentes partes da tua aplicação, e pode até ser usado com segurança como key num dicionário Python ou numa cache em memória. Ao empilhar estas opções de configuração dentro do teu ConfigDict, transformas um model de um parser de dados flexível numa fronteira absoluta e inflexível. É tudo por este episódio. Obrigado por ouvires, e continua a programar!
19

Configuração de Aplicações com Pydantic Settings

3m 38s

Faça a gestão das suas variáveis de ambiente como um profissional. Irá aprender como o pacote pydantic-settings automatiza o processamento de segredos, ficheiros dot-env e prefixos.

Download
Olá, daqui é o Alex da DEV STORIES DOT EU. Pydantic: Data Validation, episódio 19 de 20. Para de extrair strings do sistema operativo e de cruzar os dedos para que façam cast de forma limpa para um integer. Provavelmente já escreveste dezenas de ficheiros utilitários a fazer wrap de chamadas standard de variáveis de ambiente, só para evitar que um valor de configuração em falta faça a tua aplicação ir abaixo em runtime. A configuração da aplicação com Pydantic Settings substitui todo esse boilerplate. Enquanto o Pydantic standard lida com a validação geral de dados, a gestão de variáveis de ambiente requer a instalação do package separado pydantic-settings. Este package fornece uma class específica chamada BaseSettings. Em vez de ires buscar variáveis manualmente e escreveres lógica de parsing custom, declaras uma class que herda de BaseSettings. Defines os teus campos de configuração exatamente como um model Pydantic standard, completo com type hints de Python e valores default. Quando instancias esta class, o Pydantic lê automaticamente as variáveis de ambiente do teu sistema. Ele mapeia os nomes das variáveis para os atributos da tua class, de forma case-insensitive por default. Se definiste um campo de timeout da base de dados como um integer, e a variável de ambiente fornece uma string, o Pydantic faz coerce dessa string para um objeto integer real. Se a variável de ambiente contiver texto arbitrário em vez de um número, o Pydantic faz raise de um erro de validação claro imediatamente no startup da aplicação. O teu programa faz fail fast, em vez de fazer crash de forma imprevisível mais tarde durante uma chamada ativa à base de dados. Em ambientes maiores, os nomes das variáveis globais frequentemente colidem. Podes ter múltiplos services a correr no mesmo host, todos à procura de uma variável chamada simplesmente database URL. O BaseSettings resolve isto ao permitir-te definir um prefixo de ambiente na configuração do model. Se definires o prefixo como app underscore, o Pydantic para de procurar matches exatos de nomes de campo. Em vez disso, para popular um campo chamado database URL, ele aponta especificamente para a variável de ambiente app underscore database URL. O código da tua aplicação Python continua a aceder à property apenas como database URL, escondendo totalmente o prefixo do sistema operativo da tua business logic. Aqui está o ponto chave. Não tens de fazer flatten aos teus objetos Python só para ler variáveis de ambiente. A configuração muitas vezes torna-se complexa, exigindo estruturas de dados nested. Podes ter uma class de settings principal que inclui um sub-model dedicado para settings da base de dados, e outro para logging. O Pydantic suporta a resolução destas estruturas nested usando uma convenção de double underscore. Se a tua class de settings principal tiver um campo chamado database, que por sua vez aponta para um model a conter um campo timeout, o Pydantic vai procurar por uma variável de ambiente chamada database double underscore timeout. Se estiveres a usar um prefixo, ele naturalmente faz prepend disso também, resultando em algo como app underscore database double underscore timeout. Este mecanismo permite-te manter objetos de configuração hierárquicos e strictly typed no teu source code, enquanto continuam a mapear de forma limpa para variáveis de ambiente standard e flat. O verdadeiro valor do BaseSettings não é apenas eliminar boilerplate, é garantir que, se a tua aplicação iniciar com sucesso, todo o seu state de configuração está totalmente presente, explicitly typed, e completamente seguro para consumir. Obrigado por ouvirem, happy coding a todos!
20

Nos Bastidores: Custom Core Schemas

3m 39s

Este é o último episódio da série! Assuma o controlo total do motor de validação. Irá aprender a escrever um método __get_pydantic_core_schema__ para ensinar o core em Rust a lidar com objetos Python completamente estranhos.

Download
Olá, daqui é o Alex da DEV STORIES DOT EU. Pydantic: Data Validation, episódio 20 de 20. Importas uma library rígida e sem documentação de outra equipa, e precisas de passar os objetos dela pelo teu pipeline de validação rigoroso. O objeto não tem qualquer noção do Pydantic, e não podes tocar no seu source code. Quando as annotations e os validators simples não chegam, tens de falar diretamente com o engine — e isso significa abrir o capot para escrever custom core schemas. Normalmente, o Pydantic descobre como validar os teus dados lendo os type hints. Quando lhe entregas um objeto estranho, ele esbarra numa parede. Para resolver isto, defines um método chamado dunder get pydantic core schema. Este método atua como uma camada de tradução direta. Ele ignora os wrappers de alto nível de Python e injeta instruções diretamente no Pydantic Core, o engine de Rust subjacente que lida com a lógica real de validação. Quando implementas este método, ele recebe o source type e um handler. O handler funciona exatamente como um middleware numa web framework. Não tens de escrever o validation schema inteiro do zero. Podes pedir ao handler para gerar o schema default para um tipo específico, e depois envolver a tua própria lógica customizada à volta desse output. Usa o wrapper de ligação à base de dados legacy como exemplo. Imagina que a única forma de inicializar este objeto é passar-lhe um inteiro específico, como um connection ID. Queres que o Pydantic aceite um inteiro de um request de API, o valide, e te devolva o objeto de ligação totalmente instanciado. Como não podes modificar a classe legacy diretamente, defines um custom type usando annotations de Python. Dentro dessa annotation, forneces o teu método de custom core schema. Aqui está o ponto chave. Em vez de escreveres dicionários raw, usas o módulo core schema do Pydantic, que fornece helper functions para construir estas estruturas de forma segura. Primeiro, pedes ao handler para construir um schema de inteiro standard. A seguir, constróis um chain schema. Instruis o engine a correr a validação de inteiro standard primeiro. Se o input for genuinamente um inteiro, o engine passa-o para uma função Python customizada que tu forneces. Esta função recebe o connection ID, inicializa o wrapper da base de dados legacy, e devolve o objeto. Por fim, adicionas um instance check schema à chain, garantindo que o output final é exatamente a classe legacy que esperas. É aqui que a coisa fica interessante. Devolves esta estrutura nested ao Pydantic. Debaixo do capot, o Pydantic pega nestas definições de dicionários nested e compila-as num execution graph nativo em Rust. Programaste o engine de Rust a partir de Python, dizendo-lhe passo a passo como ingerir um inteiro raw, validá-lo, e construir com segurança um objeto estranho à velocidade máxima. Isto representa o nível mais baixo de integração que o Pydantic oferece, concedendo controlo total sobre a validation tree sem sacrificar a performance. Como este é o nosso episódio final, recomendo vivamente que mergulhes na documentação oficial do Pydantic e tentes construir um custom core schema de forma hands-on. É a melhor forma de solidificar a maneira como o engine realmente pensa. Também podes visitar dev stories dot eu para sugerir tópicos que gostarias de ver abordados em séries futuras. É tudo por hoje. Obrigado por ouvires — vai construir algo fixe.