How does mypy
know the signature of the pydantic
model in this manner?
from pydantic import BaseModel
class Model(BaseModel):
a: int
Model(a='asd') # error: Argument "a" to "Model" has incompatible type "str"; expected "int"
How can pydantic
BaseModel
's metaclass change the __init__
signature?
Pydantic uses PEP681 dataclass_transform
on model metaclass to achieve behaviour similar to native dataclasses.dataclass
decorator in order to generate an __init__
method for type checkers. Reading the source:
@typing_extensions.dataclass_transform(kw_only_default=True, field_specifiers=(Field,))
class ModelMetaclass(ABCMeta):
... # [omitted by me]
class BaseModel(_repr.Representation, metaclass=ModelMetaclass):
... # [omitted by me]
In PEP:
If
dataclass_transform
is applied to a class, dataclass-like semantics will be assumed for any class that directly or indirectly derives from the decorated class or uses the decorated class as a metaclass.
PEP example (very similar to what pydantic does):
# The ``ModelMeta`` metaclass and ``ModelBase`` class are defined by
# a library. This could be in a type stub or inline.
@typing.dataclass_transform()
class ModelMeta(type): ...
class ModelBase(metaclass=ModelMeta): ...
# The ``ModelBase`` class can now be used to create new model
# subclasses, like this:
class CustomerModel(ModelBase):
id: int
name: str