跳到主要内容

Architecture

Usage of the Pydantic library can be divided into two parts:

  • Model definition, done in the pydantic package.
  • Model validation and serialization, done in the pydantic-core package

Model definition

Whenever a Pydantic BaseModel is defined, the metaclass will analyze the body of the model to collect a number of elements:

  • Defined annotations to build model fields (collected in the model_fields attribute).
  • Model configuration, set with model_config.
  • Additional validators/serializers.
  • Private attributes, class variables, identification of generic parametrization, etc

Communicating between pydantic and pydantic-core: the core schema

Pydantic uses the concept of a core schema: a structured (and serializable) Python dictionary (represented using TypedDict definitions) describing a specific validation and serialization logic

Customizing the core schema and JSON schema

from typing import Any

from pydantic_core import CoreSchema
from typing import Annotated

from pydantic import GetCoreSchemaHandler, TypeAdapter


class MyStrict:
@classmethod
def __get_pydantic_core_schema__(
cls, source: Any, handler: GetCoreSchemaHandler
) -> CoreSchema:
schema = handler(source)
schema['strict'] = True
return schema


class MyGt:
@classmethod
def __get_pydantic_core_schema__(
cls, source: Any, handler: GetCoreSchemaHandler
) -> CoreSchema:
schema = handler(source)
schema['gt'] = 1
return schema


ta = TypeAdapter(Annotated[int, MyStrict(), MyGt()])

When the GenerateSchema class builds the core schema for Annotated[int, MyStrict(), MyGt()], it will create an instance of a GetCoreSchemaHandler to be passed to the MyGt.__get_pydantic_core_schema__ method.

In the case of our Annotated pattern, the GetCoreSchemaHandler is defined in a nested way. Calling it will recursively call the other __get_pydantic_core_schema__ methods until it reaches the int annotation, where a simple {'type': 'int'} schema is returned

The source argument depends on the core schema generation pattern. In the case of Annotated, the source will be the type being annotated. When defining a custom type, the source will be the actual class where __get_pydantic_core_schema__ is defined