* refactor: rewrite the whole pydantic dataclass logic * test: add tests for issue 2162 * test: add tests for issue 2383 * test: add tests for issue 2398 * test: add tests for issue 2424 * test: add tests for issue 2541 * test: add tests for issue 2555 * refactor: polish * change default and support 3.6 * fix coverage * fix mypy and text * typos * test: add tests for issue 2594 * fix: forward doc for schema description * add change * chore: small changes from review * refactor: avoid extra __pydantic_run_validation__ parameter * small tweaks * remove wrapper * support 3.6 * fix: mypy * rewrite doc * add docs * wrapper is removed now * a bit more docs * code review * faster dict update * add test for issue 3162 * add test for issue 3011 * feat: add `Config.post_init_after_validation` * allow config via dict * fix cython and TypedDict * chore: typo * move `compiled` in `version.py` * refactor: switch from `Config.post_init_after_validation` to \'post_init_call` * add dataclass isinstance support * avoid multi paragraphs in change file * feat: support `Config.extra` * refactor: simplify a bit code * refactor: avoid creating useless functions * refactor: simplify `is_builtin_dataclass` * support extra in post_init * docs: add warning on config extra * fix #3713 compatibility * update docs Co-authored-by: Samuel Colvin <s@muelcolvin.com>
6.0 KiB
If you don't want to use pydantic's BaseModel you can instead get the same data validation on standard
dataclasses (introduced in Python 3.7).
{!.tmp_examples/dataclasses_main.py!}
(This script is complete, it should run "as is")
!!! note
Keep in mind that pydantic.dataclasses.dataclass is a drop-in replacement for dataclasses.dataclass
with validation, not a replacement for pydantic.BaseModel (with a small difference in how initialization hooks work). There are cases where subclassing
pydantic.BaseModel is the better choice.
For more information and discussion see
[samuelcolvin/pydantic#710](https://github.com/samuelcolvin/pydantic/issues/710).
You can use all the standard pydantic field types, and the resulting dataclass will be identical to the one
created by the standard library dataclass decorator.
The underlying model and its schema can be accessed through __pydantic_model__.
Also, fields that require a default_factory can be specified by either a pydantic.Field or a dataclasses.field.
{!.tmp_examples/dataclasses_default_schema.py!}
(This script is complete, it should run "as is")
pydantic.dataclasses.dataclass's arguments are the same as the standard decorator, except one extra
keyword argument config which has the same meaning as Config.
!!! warning After v1.2, The Mypy plugin must be installed to type check pydantic dataclasses.
For more information about combining validators with dataclasses, see dataclass validators.
Dataclass Config
If you want to modify the Config like you would with a BaseModel, you have three options:
{!.tmp_examples/dataclasses_config.py!}
!!! warning
After v1.10, pydantic dataclasses support Config.extra but some default behaviour of stdlib dataclasses
may prevail. For example, when printing a pydantic dataclass with allowed extra fields, it will still
use the __str__ method of stdlib dataclass and show only the required fields.
This may be improved further in the future.
Nested dataclasses
Nested dataclasses are supported both in dataclasses and normal models.
{!.tmp_examples/dataclasses_nested.py!}
(This script is complete, it should run "as is")
Dataclasses attributes can be populated by tuples, dictionaries or instances of the dataclass itself.
Stdlib dataclasses and pydantic dataclasses
Convert stdlib dataclasses into pydantic dataclasses
Stdlib dataclasses (nested or not) can be easily converted into pydantic dataclasses by just decorating
them with pydantic.dataclasses.dataclass.
Pydantic will enhance the given stdlib dataclass but won't alter the default behaviour (i.e. without validation).
It will instead create a wrapper around it to trigger validation that will act like a plain proxy.
The stdlib dataclass can still be accessed via the __dataclass__ attribute (see example below).
{!.tmp_examples/dataclasses_stdlib_to_pydantic.py!}
(This script is complete, it should run "as is")
Choose when to trigger validation
As soon as your stdlib dataclass has been decorated with pydantic dataclass decorator, magic methods have been added to validate input data. If you want, you can still keep using your dataclass and choose when to trigger it.
{!.tmp_examples/dataclasses_stdlib_run_validation.py!}
(This script is complete, it should run "as is")
Inherit from stdlib dataclasses
Stdlib dataclasses (nested or not) can also be inherited and pydantic will automatically validate all the inherited fields.
{!.tmp_examples/dataclasses_stdlib_inheritance.py!}
(This script is complete, it should run "as is")
Use of stdlib dataclasses with BaseModel
Bear in mind that stdlib dataclasses (nested or not) are automatically converted into pydantic
dataclasses when mixed with BaseModel! Furthermore the generated pydantic dataclass will have
the exact same configuration (order, frozen, ...) as the original one.
{!.tmp_examples/dataclasses_stdlib_with_basemodel.py!}
(This script is complete, it should run "as is")
Use custom types
Since stdlib dataclasses are automatically converted to add validation using
custom types may cause some unexpected behaviour.
In this case you can simply add arbitrary_types_allowed in the config!
{!.tmp_examples/dataclasses_arbitrary_types_allowed.py!}
(This script is complete, it should run "as is")
Initialize hooks
When you initialize a dataclass, it is possible to execute code after validation
with the help of __post_init_post_parse__. This is not the same as __post_init__, which executes
code before validation.
!!! tip
If you use a stdlib dataclass, you may only have __post_init__ available and wish the validation to
be done before. In this case you can set Config.post_init_call = 'after_validation'
{!.tmp_examples/dataclasses_post_init_post_parse.py!}
(This script is complete, it should run "as is")
Since version v1.0, any fields annotated with dataclasses.InitVar are passed to both __post_init__ and
__post_init_post_parse__.
{!.tmp_examples/dataclasses_initvars.py!}
(This script is complete, it should run "as is")
Difference with stdlib dataclasses
Note that the dataclasses.dataclass from Python stdlib implements only the __post_init__ method since it doesn't run a validation step.
When substituting usage of dataclasses.dataclass with pydantic.dataclasses.dataclass, it is recommended to move the code executed in the __post_init__ method to the __post_init_post_parse__ method, and only leave behind part of code which needs to be executed before validation.
JSON Dumping
Pydantic dataclasses do not feature a .json() function. To dump them as JSON, you will need to make use of the pydantic_encoder as follows:
{!.tmp_examples/dataclasses_json_dumps.py!}