コンテンツにスキップ

Why use Pydantic?

現在、Pydanticは月に何度もダウンロードされており、世界で最も大きく、最も有名な組織によって使用されています。

Pydanticが6年前に開始されて以来、なぜ多くの人がPydanticを採用しているのかを知るのは難しいですが、いくつか考えられることがあります。

Type hints powering schema validation

Pydanticが検証するスキーマは、一般にPythonの型ヒントによって定義されます。

最近のPythonを作成している人であれば、すでに使い方を知っているはずなので、型のヒントはこの目的には最適です。 型ヒントを使用することは、Pydanticがmypyやpyrightのような静的型付けツールやpycharmやvscodeのようなIDEとうまく統合されることも意味します。

Example - just type hints

(This example requires Python 3.9+)

from typing import Annotated, Dict, List, Literal, Tuple

from annotated_types import Gt

from pydantic import BaseModel


class Fruit(BaseModel):
    name: str  # (1)!
    color: Literal['red', 'green']  # (2)!
    weight: Annotated[float, Gt(0)]  # (3)!
    bazam: Dict[str, List[Tuple[int, bool, float]]]  # (4)!


print(
    Fruit(
        name='Apple',
        color='red',
        weight=4.2,
        bazam={'foobar': [(1, True, 0.1)]},
    )
)
#> name='Apple' color='red' weight=4.2 bazam={'foobar': [(1, True, 0.1)]}

  1. The name field is simply annotated with str - any string is allowed.
  2. The Literal type is used to enforce that color is either 'red' or 'green'.
  3. Even when we want to apply constraints not encapsulated in python types, we can use Annotated and annotated-types to enforce constraints without breaking type hints.
  4. I'm not claiming "bazam" is really an attribute of fruit, but rather to show that arbitrarily complex types can easily be validated.

さらなる学習

documentation on supported typesを参照してください。

Performance

Pydanticのコア検証ロジックは、別のパッケージpydantic-coreに実装されており、ほとんどのタイプの検証はRustで実装されています。

その結果、PydanticはPython用の最も高速なデータ検証ライブラリの1つになっています。

Performance Example - Pydantic vs. dedicated code

In general, dedicated code should be much faster than a general-purpose validator, but in this example Pydantic is >300% faster than dedicated code when parsing JSON and validating URLs.

Performance Example
import json
import timeit
from urllib.parse import urlparse

import requests

from pydantic import HttpUrl, TypeAdapter

reps = 7
number = 100
r = requests.get('https://api.github.com/emojis')
r.raise_for_status()
emojis_json = r.content


def emojis_pure_python(raw_data):
    data = json.loads(raw_data)
    output = {}
    for key, value in data.items():
        assert isinstance(key, str)
        url = urlparse(value)
        assert url.scheme in ('https', 'http')
        output[key] = url


emojis_pure_python_times = timeit.repeat(
    'emojis_pure_python(emojis_json)',
    globals={
        'emojis_pure_python': emojis_pure_python,
        'emojis_json': emojis_json,
    },
    repeat=reps,
    number=number,
)
print(f'pure python: {min(emojis_pure_python_times) / number * 1000:0.2f}ms')
#> pure python: 5.32ms

type_adapter = TypeAdapter(dict[str, HttpUrl])
emojis_pydantic_times = timeit.repeat(
    'type_adapter.validate_json(emojis_json)',
    globals={
        'type_adapter': type_adapter,
        'HttpUrl': HttpUrl,
        'emojis_json': emojis_json,
    },
    repeat=reps,
    number=number,
)
print(f'pydantic: {min(emojis_pydantic_times) / number * 1000:0.2f}ms')
#> pydantic: 1.54ms

print(
    f'Pydantic {min(emojis_pure_python_times) / min(emojis_pydantic_times):0.2f}x faster'
)
#> Pydantic 3.45x faster

コンパイル言語で記述された他のパフォーマンス中心のライブラリとは異なり、Pydanticはfunctional validatorsによる検証のカスタマイズにも優れたサポートを提供しています。

さらなる学習

Samuel Colvinのtalk at PyCon 2023は、pydantic-coreがどのように機能し、どのようにPydanticと統合されているか解説しています。

Serialization

Pydanticは、次の3つの方法でモデルをシリアライズする機能を提供します。

  1. Pythonのdictに、関連付けられたPythonオブジェクトに構成する
  2. Pythonのdictに、"jsonable"な型だけで構成する
  3. JSON文字列への変換

3つのモードすべてにおいて、特定のフィールドを除外し、未設定のフィールドを除外し、デフォルト値を除外し、None値を除外することによって、出力をカスタマイズすることができます。

Example - Serialization 3 ways
from datetime import datetime

from pydantic import BaseModel


class Meeting(BaseModel):
    when: datetime
    where: bytes
    why: str = 'No idea'


m = Meeting(when='2020-01-01T12:00', where='home')
print(m.model_dump(exclude_unset=True))
#> {'when': datetime.datetime(2020, 1, 1, 12, 0), 'where': b'home'}
print(m.model_dump(exclude={'where'}, mode='json'))
#> {'when': '2020-01-01T12:00:00', 'why': 'No idea'}
print(m.model_dump_json(exclude_defaults=True))
#> {"when":"2020-01-01T12:00:00","where":"home"}

さらなる学習

documentation on serializationを参照してください。

JSON Schema

JSON Schemaは、任意のPydanticスキーマに対して生成することができ、APIの自己文書化と、JSONスキーマをサポートするさまざまなツールとの統合できます。

Example - JSON Schema
from datetime import datetime

from pydantic import BaseModel


class Address(BaseModel):
    street: str
    city: str
    zipcode: str


class Meeting(BaseModel):
    when: datetime
    where: Address
    why: str = 'No idea'


print(Meeting.model_json_schema())
"""
{
    '$defs': {
        'Address': {
            'properties': {
                'street': {'title': 'Street', 'type': 'string'},
                'city': {'title': 'City', 'type': 'string'},
                'zipcode': {'title': 'Zipcode', 'type': 'string'},
            },
            'required': ['street', 'city', 'zipcode'],
            'title': 'Address',
            'type': 'object',
        }
    },
    'properties': {
        'when': {'format': 'date-time', 'title': 'When', 'type': 'string'},
        'where': {'$ref': '#/$defs/Address'},
        'why': {'default': 'No idea', 'title': 'Why', 'type': 'string'},
    },
    'required': ['when', 'where'],
    'title': 'Meeting',
    'type': 'object',
}
"""

Pydanticは、OpenAPI 3.1と互換性のある標準の最新バージョンであるJSON Schema version 2020-12を生成します。

さらなる額十

documentation on JSON Schemaを参照ください。

Strict mode and data coercion

デフォルトでは、Pydanticは一般的な不正な型に対して耐性があり、データを正しい型に強制します。例えば、intフィールドに渡された数値文字列はintとして解析します。

Pydanticには"strict=True"モードもあります。これは"Strictモード"とも呼ばれ、型が強制されず、入力データがスキーマや型のヒントと正確に一致しない限り、検証エラーが発生します。

しかし、strictモードはJSONデータを検証するときにはほとんど役に立たないでしょう。なぜなら、JSONにはdatetimeUUIDbytesのような多くの一般的なpython型と一致する型がないからです。

これを解決するために、Pydanticは1つのステップでJSONを解析して検証することができます。これにより、RFC3339(別名ISO8601)文字列のような適切なデータ変換をdatetimeオブジェクトにすることができます。JSON解析はRustで実装されているため、非常にパフォーマンスに優れています。

Example - Strict mode that's actually useful
from datetime import datetime

from pydantic import BaseModel, ValidationError


class Meeting(BaseModel):
    when: datetime
    where: bytes


m = Meeting.model_validate({'when': '2020-01-01T12:00', 'where': 'home'})
print(m)
#> when=datetime.datetime(2020, 1, 1, 12, 0) where=b'home'
try:
    m = Meeting.model_validate(
        {'when': '2020-01-01T12:00', 'where': 'home'}, strict=True
    )
except ValidationError as e:
    print(e)
    """
    2 validation errors for Meeting
    when
      Input should be a valid datetime [type=datetime_type, input_value='2020-01-01T12:00', input_type=str]
    where
      Input should be a valid bytes [type=bytes_type, input_value='home', input_type=str]
    """

m_json = Meeting.model_validate_json(
    '{"when": "2020-01-01T12:00", "where": "home"}'
)
print(m_json)
#> when=datetime.datetime(2020, 1, 1, 12, 0) where=b'home'

さらなる学習

documentation on strict modeを参照してください。

Dataclasses, TypedDicts, and more

Pydanticは、スキーマを作成し、検証とシリアライズを実行するための4つの方法を提供しています。

  1. BaseModel — Pydantic独自のスーパークラスには、インスタンスメソッドを介して利用できる多くの共通ユーティリティがあります。
  2. pydantic.dataclasses.dataclass — データクラスの初期化時に検証を実行する標準データクラスのラッパです。
  3. TypeAdapter — 任意の型を検証とシリアライゼーションに適応させる一般的な方法です。これにより、TypedDictNamedTupleのような型を検証することができます。また、inttimedeltaall typesサポートをTypeAdapterで使用することもできます。
  4. validate_call — 関数を呼び出すときに検証を実行するデコレータです。
Example - schema based on TypedDict
from datetime import datetime

from typing_extensions import NotRequired, TypedDict

from pydantic import TypeAdapter


class Meeting(TypedDict):
    when: datetime
    where: bytes
    why: NotRequired[str]


meeting_adapter = TypeAdapter(Meeting)
m = meeting_adapter.validate_python(  # (1)!
    {'when': '2020-01-01T12:00', 'where': 'home'}
)
print(m)
#> {'when': datetime.datetime(2020, 1, 1, 12, 0), 'where': b'home'}
meeting_adapter.dump_python(m, exclude={'where'})  # (2)!

print(meeting_adapter.json_schema())  # (3)!
"""
{
    'properties': {
        'when': {'format': 'date-time', 'title': 'When', 'type': 'string'},
        'where': {'format': 'binary', 'title': 'Where', 'type': 'string'},
        'why': {'title': 'Why', 'type': 'string'},
    },
    'required': ['when', 'where'],
    'title': 'Meeting',
    'type': 'object',
}
"""

1. TypeAdapterTypedDictが検証を行うためのもので、validate_jsonを使ってJSONデータを直接検証することもできます。 2. dump_pythonTypedDictをpythonオブジェクトにシリアライズしますが、dump_jsonでJSONにシリアライズすることもできます。 3. TypeAdapterはJSONスキーマも生成できます。

Customisation

関数型バリデーターとシリアライザ、そしてカスタム型用の強力なプロトコルは、Pydanticの動作方法をフィールド単位または型単位でカスタマイズできます。

Customisation Example - wrap validators

"wrap validators" are new in Pydantic V2 and are one of the most powerful ways to customize Pydantic validation.

from datetime import datetime, timezone

from pydantic import BaseModel, field_validator


class Meeting(BaseModel):
    when: datetime

    @field_validator('when', mode='wrap')
    def when_now(cls, input_value, handler):
        if input_value == 'now':
            return datetime.now()
        when = handler(input_value)
        # in this specific application we know tz naive datetimes are in UTC
        if when.tzinfo is None:
            when = when.replace(tzinfo=timezone.utc)
        return when


print(Meeting(when='2020-01-01T12:00+01:00'))
#> when=datetime.datetime(2020, 1, 1, 12, 0, tzinfo=TzInfo(+01:00))
print(Meeting(when='now'))
#> when=datetime.datetime(2032, 1, 2, 3, 4, 5, 6)
print(Meeting(when='2020-01-01T12:00'))
#> when=datetime.datetime(2020, 1, 1, 12, 0, tzinfo=datetime.timezone.utc)

さらなる学習

validators, custom serializers, and custom typesを参照ください。

Ecosystem

この記事の執筆時点で、GitHubには214,100のリポジトリがあり、PyPIにはPydanticに依存する8,119のパッケージがあります。

Pydanticに依存している注目すべきライブラリをいくつか紹介します。

私家版訳注

以下は、翻訳時点のものです。(2024/07)

Pydanticを使用している他のライブラリは、Kludex/awesome-pydanticにあります。

Pydanticを使用している組織

Pydanticを使用しているいくつかの有名な企業や組織と、彼らがPydanticを使用していることを私たちが知っている理由/方法についてコメントします。

以下の組織は、以下の基準の1つ以上に一致しています。

  • pydanticをパブリックリポジトリの依存関係として使用していること。
  • 組織からpydanticドキュメントサイトへの参照トラフィック-一般的にパブリックドメインではないため、内部のドメイン固有の参照者は含まれません。
  • 組織内でのPydanticの使用に関する、Pydanticチームと組織に属するエンジニアとの間で直接的なコミュニケーションを行っていること

We've included some extra detail where appropriate and already in the public domain. 必要に応じて詳細を追加しましたが、すでにパブリック・ドメインになっています。

私家版訳注

以下は、翻訳時点のものです。(2024/07)

Adobe

adobe/dy-sql uses Pydantic.

Amazon and AWS

Anthropic

anthropics/anthropic-sdk-python uses Pydantic.

Apple

(Based on the criteria described above)

ASML

(Based on the criteria described above)

AstraZeneca

Multiple repos in the AstraZeneca GitHub org depend on Pydantic.

Cisco Systems

Comcast

(Based on the criteria described above)

Datadog

  • Extensive use of Pydantic in DataDog/integrations-core and other repos
  • Communication with engineers from Datadog about how they use Pydantic.

Facebook

Multiple repos in the facebookresearch GitHub org depend on Pydantic.

GitHub

GitHub sponsored Pydantic $750 in 2022

Google

Extensive use of Pydantic in google/turbinia and other repos.

HSBC

(Based on the criteria described above)

IBM

Multiple repos in the IBM GitHub org depend on Pydantic.

Intel

(Based on the criteria described above)

Intuit

(Based on the criteria described above)

Intergovernmental Panel on Climate Change

Tweet explaining how the IPCC use Pydantic.

JPMorgan

(Based on the criteria described above)

Jupyter

  • The developers of the Jupyter notebook are using Pydantic for subprojects
  • Through the FastAPI-based Jupyter server Jupyverse
  • FPS's configuration management.

Microsoft

  • DeepSpeed deep learning optimisation library uses Pydantic extensively
  • Multiple repos in the microsoft GitHub org depend on Pydantic, in particular their
  • Pydantic is also used in the Azure GitHub org
  • Comments on GitHub show Microsoft engineers using Pydantic as part of Windows and Office

Molecular Science Software Institute

Multiple repos in the MolSSI GitHub org depend on Pydantic.

NASA

Multiple repos in the NASA GitHub org depend on Pydantic.

NASA are also using Pydantic via FastAPI in their JWST project to process images from the James Webb Space Telescope, see this tweet.

Netflix

Multiple repos in the Netflix GitHub org depend on Pydantic.

NSA

The nsacyber/WALKOFF repo depends on Pydantic.

NVIDIA

Mupltiple repos in the NVIDIA GitHub org depend on Pydantic.

Their "Omniverse Services" depends on Pydantic according to their documentation.

OpenAI

OpenAI use Pydantic for their ChatCompletions API, as per this discussion on GitHub.

Anecdotally, OpenAI use Pydantic extensively for their internal services.

Oracle

(Based on the criteria described above)

Palantir

(Based on the criteria described above)

Qualcomm

(Based on the criteria described above)

Red Hat

(Based on the criteria described above)

Revolut

Anecdotally, all internal services at Revolut are built with FastAPI and therefore Pydantic.

Robusta

The robusta-dev/robusta repo depends on Pydantic.

Salesforce

Salesforce sponsored Samuel Colvin $10,000 to work on Pydantic in 2022.

Starbucks

(Based on the criteria described above)

Texas Instruments

(Based on the criteria described above)

Twilio

(Based on the criteria described above)

Twitter

Twitter's the-algorithm repo where they open sourced their recommendation engine uses Pydantic.

UK Home Office

(Based on the criteria described above)