|
7 | 7 |
|
8 | 8 | {{ version }}.
|
9 | 9 |
|
10 |
| -Pydantic is the most widely used Python library for data validation and coercion using Python type annotations. |
| 10 | +Pydantic is the most widely used data validation library for Python. |
11 | 11 |
|
12 | 12 | !!! success
|
13 | 13 | Already using Pydantic V1? See the [Migration Guide](migration.md) for notes on upgrading to Pydantic V2 in your applications!
|
14 | 14 |
|
15 |
| -## Why use Pydantic? |
16 |
| - |
17 |
| -Built-in Python type annotations are a useful way to hint about the expected type of data, improving code clarity and supporting development tools. However, Python's type annotations are optional and don't affect the runtime behavior of the program. |
18 |
| - |
19 |
| -Static type checkers like [mypy](https://mypy-lang.org/) use type annotations to catch potential type-related errors before running the program. But static type checkers can't catch all errors, and they don't affect the runtime behavior of the program. |
20 |
| - |
21 |
| -Pydantic, on the other hand, uses type annotations to perform [data validation](usage/validators.md) and [type coercion](usage/conversion_table.md) at runtime, which is particularly useful for ensuring the correctness of user or external data. |
22 |
| - |
23 |
| -Pydantic enables you to convert input data to Python [standard library types and custom types](usage/types/types.md) in a controlled manner, ensuring they meet the specifications you've provided. This eliminates a significant amount of manual data validation and transformation code, making your program more robust and less prone to errors. It's particularly helpful when dealing with untrusted user input such as form data, [JSON documents](usage/json_schema.md), and other data types. |
24 |
| - |
25 |
| -By providing a simple, declarative way of defining how data should be shaped, Pydantic helps you write cleaner, safer, and more reliable code. |
26 |
| - |
27 |
| -## Features of Pydantic |
| 15 | +```py lint="skip" upgrade="skip" title="Pydantic Example" requires="3.10" |
| 16 | +from pydantic import BaseModel |
28 | 17 |
|
29 |
| -Some of the main features of Pydantic include: |
| 18 | +class MyModel(BaseModel): |
| 19 | + a: int |
| 20 | + b: list[str] |
30 | 21 |
|
31 |
| -- [**Data validation**](usage/validators.md): Pydantic validates data as it is assigned to ensure it meets the requirements. It automatically handles a broad range of data types, including custom types and custom validators. |
32 |
| -- [**Standard library and custom data types**](usage/types/types.md): Pydantic supports all of the Python standard library types, and you can define custom data types and specify how they should be validated and converted. |
33 |
| -- [**Conversion types**](usage/conversion_table.md): Pydantic will not only validate data, but also convert it to the appropriate type if possible. For instance, a string containing a number will be converted to the proper numerical type. |
34 |
| -- [**Custom and nested models**](usage/models.md): You can define models (similar to classes) that contain other models, allowing for complex data structures to be neatly and efficiently represented. |
35 |
| -- [**Generic models**](usage/models.md#generic-models): Pydantic supports generic models, which allow the declaration of models that are "parameterized" on one or more fields. |
36 |
| -- [**Dataclasses**](usage/dataclasses.md): Pydantic supports `dataclasses.dataclass`, offering same data validation as using `BaseModel`. |
37 |
| -- [**Model schema generation**](usage/json_schema.md): Pydantic models can be converted to and from a JSON Schema, which can be useful for documentation, code generation, or other purposes. |
38 |
| -- [**Error handling**](errors/errors.md): Pydantic models raise informative errors when invalid data is provided, with the option to create your own [custom errors](errors/errors.md#custom-errors). |
39 |
| -- [**Settings management**](api/pydantic_settings.md): The `BaseSettings` class from [pydantic-settings](https://github.com/pydantic/pydantic-settings) provides a way to validate, document, and provide default values for environment variables. |
| 22 | +m = MyModel(a=123, b=['a', 'b', 'c']) |
| 23 | +print(m.model_dump()) |
| 24 | +#> {'a': 123, 'b': ['a', 'b', 'c']} |
| 25 | +``` |
40 | 26 |
|
41 |
| -Pydantic is simple to use, even when doing complex things, and enables you to define and validate data in pure, canonical Python. |
| 27 | +## Why use Pydantic? |
42 | 28 |
|
43 |
| -[Installing Pydantic](install.md) is as simple as: [`pip install pydantic`](install.md). |
| 29 | +- **Powered by type hints** — with Pydantic, schema validation and serialization are controlled by type annotations; less to learn, less code to write and integration with your IDE and static analysis tools. |
| 30 | +- **Speed** — Pydantic's core validation logic is written in Rust, as a result Pydantic is among the fastest data validation libraries for Python. |
| 31 | +- **JSON Schema** — Pydantic models can emit JSON Schema allowing for easy integration with other tools. |
| 32 | +- **Strict** and **Lax** mode — Pydantic can run in either `strict=True` mode (where data is not converted) or `strict=False` mode where Pydantic tries to coerce data to the correct type where appropriate. |
| 33 | +- **Dataclasses**, **TypedDicts** and more — Pydantic supports validation of many standard library types including `dataclass` and `TypedDict`. |
| 34 | +- **Customisation** — Pydantic allows custom validators and serializers to alter how data is processed in many powerful ways. |
| 35 | +- **Ecosystem** — around 8,000 packages on PyPI use Pydantic, including massively popular libraries like |
| 36 | + [FastAPI](https://github.com/tiangolo/fastapi), |
| 37 | + [huggingface/transformers](https://github.com/huggingface/transformers), |
| 38 | + [Django Ninja](https://github.com/vitalik/django-ninja), |
| 39 | + [SQLModel](https://github.com/tiangolo/sqlmodel), |
| 40 | + and [LangChain](https://github.com/hwchase17/langchain). |
| 41 | +- **Battle tested** — Pydantic is downloaded >70m times/month and is used by all FAANG companies and 20 of the 25 largest companies on NASDAQ — if you're trying to do something with Pydantic, someone else has probably already done it. |
| 42 | + |
| 43 | +[Installing Pydantic](install.md) is as simple as: [`pip install pydantic`](install.md) |
44 | 44 |
|
45 | 45 | ## Pydantic examples
|
46 | 46 |
|
47 | 47 | To see Pydantic at work, let's start with a simple example, creating a custom class that inherits from `BaseModel`:
|
48 | 48 |
|
49 |
| -```py |
| 49 | +```py upgrade="skip" title="Validation Successful" requires="3.10" |
50 | 50 | from datetime import datetime
|
51 |
| -from typing import Optional |
52 | 51 |
|
53 |
| -from pydantic import BaseModel |
| 52 | +from pydantic import BaseModel, PositiveInt |
54 | 53 |
|
55 | 54 |
|
56 | 55 | class User(BaseModel):
|
57 |
| - id: int |
58 |
| - name: str = 'John Doe' |
59 |
| - signup_ts: Optional[datetime] = None |
| 56 | + id: int # (1)! |
| 57 | + name: str = 'John Doe' # (2)! |
| 58 | + signup_ts: datetime | None # (3)! |
| 59 | + tastes: dict[str, PositiveInt] # (4)! |
60 | 60 |
|
61 | 61 |
|
62 | 62 | external_data = {
|
63 |
| - 'id': '123', |
64 |
| - 'signup_ts': '2019-06-01 12:22', |
| 63 | + 'id': 123, |
| 64 | + 'signup_ts': '2019-06-01 12:22', # (5)! |
| 65 | + 'tastes': { |
| 66 | + 'wine': 9, |
| 67 | + b'cheese': 7, # (6)! |
| 68 | + 'cabbage': '1', # (7)! |
| 69 | + }, |
65 | 70 | }
|
66 | 71 |
|
67 |
| -user = User(**external_data) |
68 |
| - |
69 |
| -print(user.model_dump()) |
70 |
| -#> {'id': 123, 'name': 'John Doe', 'signup_ts': datetime.datetime(2019, 6, 1, 12, 22)} |
| 72 | +user = User(**external_data) # (8)! |
| 73 | + |
| 74 | +print(user.id) # (9)! |
| 75 | +#> 123 |
| 76 | +print(user.model_dump()) # (10)! |
| 77 | +""" |
| 78 | +{ |
| 79 | + 'id': 123, |
| 80 | + 'name': 'John Doe', |
| 81 | + 'signup_ts': datetime.datetime(2019, 6, 1, 12, 22), |
| 82 | + 'tastes': {'wine': 9, 'cheese': 7, 'cabbage': 1}, |
| 83 | +} |
| 84 | +""" |
71 | 85 | ```
|
72 | 86 |
|
73 |
| -What's going on here: |
74 |
| - |
75 |
| -* `id` is of type `int`; the annotation-only declaration tells Pydantic that this field is required. Strings, |
| 87 | +1. `id` is of type `int`; the annotation-only declaration tells Pydantic that this field is required. Strings, |
76 | 88 | bytes, or floats will be coerced to ints if possible; otherwise an exception will be raised.
|
77 |
| -* `name` is inferred as a string from the provided default; because it has a default, it is not required. |
78 |
| -* `signup_ts` is a `datetime` field that is not required (and takes the value `None` if a value is not supplied). |
| 89 | +2. `name` is a string; because it has a default, it is not required. |
| 90 | +3. `signup_ts` is a `datetime` field that is required, but the value `None` may be provided; |
79 | 91 | Pydantic will process either a unix timestamp int (e.g. `1496498400`) or a string representing the date and time.
|
| 92 | +4. `tastes` is a dictionary with string keys and positive integer values. The `PositiveInt` type is shorthand for `Annotated[int, annotated_types.Gt(0)]`. |
| 93 | +5. The input here is an ISO8601 formatted datetime, Pydantic will convert it to a `datetime` object. |
| 94 | +6. The key here is `bytes`, but Pydantic will take care of coercing it to a string. |
| 95 | +7. Similarly, Pydantic will coerce the string `'1'` to an integer `1`. |
| 96 | +8. Here we create instance of `User` by passing our external data to `User` as keyword arguments |
| 97 | +9. We can access fields as attributes of the model |
| 98 | +10. We can convert the model to a dictionary with `model_dump()` |
80 | 99 |
|
81 | 100 | If validation fails, Pydantic will raise an error with a breakdown of what was wrong:
|
82 | 101 |
|
83 |
| -```py |
| 102 | +```py upgrade="skip" title="Validation Error" requires="3.10" |
84 | 103 | from datetime import datetime
|
85 |
| -from typing import Optional |
86 | 104 |
|
87 |
| -from pydantic import BaseModel, ValidationError |
| 105 | +from pydantic import BaseModel, PositiveInt, ValidationError |
88 | 106 |
|
89 | 107 |
|
90 | 108 | class User(BaseModel):
|
91 | 109 | id: int
|
92 | 110 | name: str = 'John Doe'
|
93 |
| - signup_ts: Optional[datetime] = None |
| 111 | + signup_ts: datetime | None |
| 112 | + tastes: dict[str, PositiveInt] |
| 113 | + |
94 | 114 |
|
| 115 | +external_data = {'id': 'not an int', 'tastes': {}} # (1)! |
95 | 116 |
|
96 | 117 | try:
|
97 |
| - User(name=1234) |
| 118 | + User(**external_data) # (2)! |
98 | 119 | except ValidationError as e:
|
99 | 120 | print(e.errors())
|
100 | 121 | """
|
101 | 122 | [
|
102 | 123 | {
|
103 |
| - 'type': 'missing', |
| 124 | + 'type': 'int_parsing', |
104 | 125 | 'loc': ('id',),
|
105 |
| - 'msg': 'Field required', |
106 |
| - 'input': {'name': 1234}, |
107 |
| - 'url': 'https://errors.pydantic.dev/2/v/missing', |
| 126 | + 'msg': 'Input should be a valid integer, unable to parse string as an integer', |
| 127 | + 'input': 'not an int', |
| 128 | + 'url': 'https://errors.pydantic.dev/2/v/int_parsing', |
108 | 129 | },
|
109 | 130 | {
|
110 |
| - 'type': 'string_type', |
111 |
| - 'loc': ('name',), |
112 |
| - 'msg': 'Input should be a valid string', |
113 |
| - 'input': 1234, |
114 |
| - 'url': 'https://errors.pydantic.dev/2/v/string_type', |
| 131 | + 'type': 'missing', |
| 132 | + 'loc': ('signup_ts',), |
| 133 | + 'msg': 'Field required', |
| 134 | + 'input': {'id': 'not an int', 'tastes': {}}, |
| 135 | + 'url': 'https://errors.pydantic.dev/2/v/missing', |
115 | 136 | },
|
116 | 137 | ]
|
117 | 138 | """
|
118 | 139 | ```
|
119 | 140 |
|
| 141 | +1. the input data is wrong here — `id` is a valid int, and `signup_ts` is missing |
| 142 | +2. `User(...)` will raise a `ValidationError` with a list of errors |
| 143 | + |
120 | 144 | ## Who is using Pydantic?
|
121 | 145 |
|
122 | 146 | Hundreds of organisations and packages are using Pydantic. Some of the prominent companies and organizations around the world who are using Pydantic include:
|
@@ -294,7 +318,7 @@ for (const company of companies) {
|
294 | 318 | const tile = document.createElement('div');
|
295 | 319 | tile.classList.add('tile');
|
296 | 320 | tile.innerHTML = `
|
297 |
| - <img src="${company.logoUrl}" /> |
| 321 | + <img src="${company.logoUrl}" alt="${company.name}" /> |
298 | 322 | `;
|
299 | 323 | grid.appendChild(tile);
|
300 | 324 | }
|
|
0 commit comments