mirror of
https://github.com/kennethreitz/pydantic.git
synced 2026-06-05 23:00:18 +00:00
286 lines
9.7 KiB
ReStructuredText
286 lines
9.7 KiB
ReStructuredText
pydantic
|
|
========
|
|
|
|
.. toctree::
|
|
:maxdepth: 2
|
|
|
|
|pypi| |license|
|
|
|
|
Current Version: |version|
|
|
|
|
Data validation and settings management using python 3.6 type hinting.
|
|
|
|
Define how data should be in pure, canonical python; validate it with *pydantic*.
|
|
|
|
`PEP 484 <https://www.python.org/dev/peps/pep-0484/>`_ introduced type hinting into python 3.5,
|
|
`PEP 526 <https://www.python.org/dev/peps/pep-0526/>`_ extended that with syntax for variable annotation in python 3.6.
|
|
|
|
*pydantic* uses those annotations to validate that untrusted data takes the form you want.
|
|
|
|
Example:
|
|
|
|
.. literalinclude:: examples/example1.py
|
|
|
|
(This script is complete, it should run "as is")
|
|
|
|
What's going on here:
|
|
|
|
* ``id`` is of type int; the annotation only declaration tells pydantic that this field is required. Strings,
|
|
bytes or floats will be coerced to ints if possible, otherwise an exception would be raised.
|
|
* ``name`` is inferred as a string from the default, it is not required as it has a default.
|
|
* ``signup_ts`` is a datetime field which is not required (``None`` if it's not supplied), pydantic will process
|
|
either a unix timestamp int (e.g. ``1496498400``) or a string representing the date & time.
|
|
* ``friends`` uses python's typing system, it is required to be a list of integers, as with ``id`` integer-like objects
|
|
will be converted to integers.
|
|
|
|
If validation fails pydantic with raise an error with a breakdown of what was wrong:
|
|
|
|
.. literalinclude:: examples/example2.py
|
|
|
|
Rationale
|
|
---------
|
|
|
|
So *pydantic* uses some cool new language feature, but why should I actually go an use it?
|
|
|
|
**no brainfuck**
|
|
no new schema definition micro-language to learn. If you know python (and perhaps skim read the
|
|
`type hinting docs <https://docs.python.org/3/library/typing.html>`_) you know how to use pydantic.
|
|
|
|
**plays nicely with your IDE/linter/brain**
|
|
because pydantic data structures are just instances of classes you define; auto-completion, linting,
|
|
:ref:`mypy <usage_mypy>` and your intuition should all work properly with your validated data.
|
|
|
|
**dual use**
|
|
pydantic's :ref:`BaseSettings <settings>` class allows it to be used in both a "validate this request data" context
|
|
and "load my system settings" context. The main difference being that system settings can can have defaults changed
|
|
by environment variables and more complex objects like DSNs and python objects often required.
|
|
|
|
**fast**
|
|
In `benchmarks <https://github.com/samuelcolvin/pydantic/tree/master/benchmarks>`_ pydantic is around twice as
|
|
fast as `trafaret <https://github.com/tailhook/trafaret>`_. Other comparisons to cerberus, marshmallow,
|
|
DRF, jsonmodels etc. to come.
|
|
|
|
**validate complex structures**
|
|
use of recursive pydantic models and ``typing``'s ``List`` and ``Dict`` etc. allow complex data schemas to be
|
|
clearly and easily defined.
|
|
|
|
**extendible**
|
|
pydantic allows custom data types to be defined or you can extend validation with the `clean_*` methods on a model.
|
|
|
|
|
|
Install
|
|
-------
|
|
|
|
Just::
|
|
|
|
pip install pydantic
|
|
|
|
pydantic has no required dependencies except python 3.6+. If you've got python 3.6 and ``pip`` installed -
|
|
you're good to go.
|
|
|
|
If you want *pydantic* to parse msgpack you can add `msgpack-python <https://pypi.python.org/pypi/msgpack-python>`_
|
|
as an optional dependency, same goes for reading json faster with `ujson <https://pypi.python.org/pypi/ujson>`_::
|
|
|
|
pip install pydantic[msgpack]
|
|
# or
|
|
pip install pydantic[ujson]
|
|
# or just
|
|
pip install pydantic[msgpack,ujson]
|
|
|
|
Usage
|
|
-----
|
|
|
|
PEP 484 Types
|
|
.............
|
|
|
|
pydantic uses ``typing`` types to define more complex objects.
|
|
|
|
.. literalinclude:: examples/ex_typing.py
|
|
|
|
(This script is complete, it should run "as is")
|
|
|
|
Choices
|
|
.......
|
|
|
|
pydantic uses python's standard ``enum`` classes to define choices.
|
|
|
|
.. literalinclude:: examples/choices.py
|
|
|
|
(This script is complete, it should run "as is")
|
|
|
|
Recursive Models
|
|
................
|
|
|
|
More complex hierarchical data structures can be defined using models as types in annotations themselves.
|
|
|
|
The ellipsis ``...`` just means "Required" same as annotation only declarations above.
|
|
|
|
.. literalinclude:: examples/recursive.py
|
|
|
|
(This script is complete, it should run "as is")
|
|
|
|
Error Handling
|
|
..............
|
|
|
|
.. literalinclude:: examples/errors.py
|
|
|
|
(This script is complete, it should run "as is")
|
|
|
|
Exotic Types
|
|
............
|
|
|
|
pydantic comes with a number of utilities for parsing or validating common objects.
|
|
|
|
.. literalinclude:: examples/exotic.py
|
|
|
|
(This script is complete, it should run "as is")
|
|
|
|
Helper Functions
|
|
................
|
|
|
|
*Pydantic* provides three ``classmethod`` helper functions on models for parsing data:
|
|
|
|
:parse_obj: this is almost identical to the ``__init__`` method of the model except if the object passed is not
|
|
a dict ``ValidationError`` will be raised (rather than python raising a ``TypeError``).
|
|
:parse_raw: takes a *str* or *bytes* parses it as *json*, *msgpack* or *pickle* data and then passes
|
|
the result to ``parse_obj``. The data type is inferred from the ``content_type`` argument,
|
|
otherwise *json* is assumed.
|
|
:parse_file: reads a file and passes the contents to ``parse_raw``, if ``content_type`` is omitted it is inferred
|
|
from the file's extension.
|
|
|
|
.. literalinclude:: examples/parse.py
|
|
|
|
(This script is complete, it should run "as is" provided ``msgpack-python`` is installed)
|
|
|
|
.. note::
|
|
|
|
Since ``pickle`` allows complex objects to be encoded, to use it you need to explicitly pass ``allow_pickle`` to
|
|
the parsing function.
|
|
|
|
Model Config
|
|
............
|
|
|
|
Behaviour of pydantic can be controlled via the ``Config`` class on a model.
|
|
|
|
Options:
|
|
|
|
:min_anystr_length: min length for str & byte types (default: ``0``)
|
|
:max_anystr_length: max length for str & byte types (default: ``2 ** 16``)
|
|
:min_number_size: min size for numbers (default: ``-2 ** 64``)
|
|
:max_number_size: max size for numbers (default: ``2 ** 64``)
|
|
:validate_all: whether or not to validate field defaults (default: ``False``)
|
|
:ignore_extra: whether to ignore any extra values in input data (default: ``True``)
|
|
:allow_extra: whether or not too allow (and include on the model) any extra values in input data (default: ``False``)
|
|
:allow_mutation: whether or not models are faux-immutable, e.g. __setattr__ fails (default: ``True``)
|
|
:fields: extra information on each field, currently just "alias" is allowed (default: ``None``)
|
|
|
|
.. literalinclude:: examples/config.py
|
|
|
|
(This script is complete, it should run "as is")
|
|
|
|
.. _settings:
|
|
|
|
Settings
|
|
........
|
|
|
|
One of pydantic's most useful applications is to define default settings, allow them to be overridden by
|
|
environment variables or keyword arguments (e.g. in unit tests).
|
|
|
|
This usage example comes last as it uses numerous concepts described above.
|
|
|
|
.. literalinclude:: examples/settings.py
|
|
|
|
(This script is complete, it should run "as is")
|
|
|
|
Here ``redis_port`` could be modified via ``export MY_PREFIX_REDIS_PORT=6380`` or ``auth_key`` by
|
|
``export my_api_key=6380``.
|
|
|
|
.. _usage_mypy:
|
|
|
|
Usage with mypy
|
|
...............
|
|
|
|
Pydantic works with `mypy <http://mypy-lang.org/>`_ provided you use the "annotation only" version of
|
|
required variables:
|
|
|
|
.. literalinclude:: examples/mypy.py
|
|
|
|
(This script is complete, it should run "as is")
|
|
|
|
This script is complete, it should run "as is". You can also run it through mypy with::
|
|
|
|
mypy --ignore-missing-imports --follow-imports=skip --strict-optional pydantic_mypy_test.py
|
|
|
|
Strict Optional
|
|
~~~~~~~~~~~~~~~
|
|
|
|
For your code to pass with ``--strict-optional`` you need to to use ``Optional[]`` or an alias of ``Optional[]``
|
|
for all fields with ``None`` default, this is standard with mypy.
|
|
|
|
Pydantic provides a few useful optional or union types:
|
|
|
|
* ``NoneStr`` aka. ``Optional[str]``
|
|
* ``NoneBytes`` aka. ``Optional[bytes]``
|
|
* ``StrBytes`` aka. ``Union[str, bytes]``
|
|
* ``NoneStrBytes`` aka. ``Optional[StrBytes]``
|
|
|
|
If these aren't sufficient you can of course define your own.
|
|
|
|
Required Fields and mypy
|
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
The ellipsis notation ``...`` will not work with mypy, you need to use annotation only fields as in the example above.
|
|
|
|
.. warning::
|
|
|
|
Be aware that using annotation only fields will alter the order of your fields in metadata and errors:
|
|
annotation only fields will always come first, but still in the order they were defined.
|
|
|
|
To get round this you can use the ``Required`` (via ``from pydantic import Required``) field as an alias for
|
|
ellipses or annotation only.
|
|
|
|
Faux Immutability
|
|
.................
|
|
|
|
Models can be configured to be immutable via ``allow_mutation = False`` this will prevent changing attributes of
|
|
a model.
|
|
|
|
.. warning::
|
|
|
|
Immutability in python is never strict. If developers are determined/stupid they can always
|
|
modify a so-called "immutable" object.
|
|
|
|
.. literalinclude:: examples/mutation.py
|
|
|
|
Trying to change ``a`` caused an error and it remains unchanged, however the dict ``b`` is mutable and the
|
|
immutability of ``foobar`` doesn't stop being changed.
|
|
|
|
Copy and Values
|
|
...............
|
|
|
|
The ``values`` function returns a dict containing the attributes of a model sub-model are recursively
|
|
converted to dicts.
|
|
|
|
While ``copy`` allows models to be duplicated, this is particularly useful for immutable models.
|
|
|
|
Both ``values`` and ``copy`` take the optional ``include`` and ``exclude`` keyword arguments to control which attributes
|
|
are return/copied. ``copy`` allows an extra keyword argument ``update`` allowing attributes to be modified as the model
|
|
is duplicated.
|
|
|
|
.. literalinclude:: examples/copy_values.py
|
|
|
|
Pickle
|
|
......
|
|
|
|
Using the same plumbing as ``copy()`` pydantic models support efficient pickling and unpicking.
|
|
|
|
.. literalinclude:: examples/ex_pickle.py
|
|
|
|
.. include:: ../HISTORY.rst
|
|
|
|
|
|
.. |pypi| image:: https://img.shields.io/pypi/v/pydantic.svg
|
|
:target: https://pypi.python.org/pypi/pydantic
|
|
.. |license| image:: https://img.shields.io/pypi/l/pydantic.svg
|
|
:target: https://github.com/samuelcolvin/pydantic
|