コンテンツにスキップ

JSON

🚧 Work in Progress

This page is a work in progress.

このページは、翻訳時点(2024/08)では本家では作成途中です。

Json Parsing

API Documentation

pydantic.main.BaseModel.model_validate_json pydantic.type_adapter.TypeAdapter.validate_json pydantic_core.from_json

Pydanticは組み込みのJSON解析を提供し、次のことを実現するのに役立ちます。

  • サードパーティ製ライブラリを使用せずに、パフォーマンスが大幅に向上
  • カスタムエラーのサポート
  • "厳密な"仕様のサポート

以下は、model_validate_jsonメソッドによるPydanticの組み込みJSON解析の例で、モデルの型アノテーションと一致しないJSONデータを解析する際のstrict仕様のサポートを示しています。

from datetime import date
from typing import Tuple

from pydantic import BaseModel, ConfigDict, ValidationError


class Event(BaseModel):
    model_config = ConfigDict(strict=True)

    when: date
    where: Tuple[int, int]


json_data = '{"when": "1987-01-28", "where": [51, -1]}'
print(Event.model_validate_json(json_data))  # (1)!
#> when=datetime.date(1987, 1, 28) where=(51, -1)

try:
    Event.model_validate({'when': '1987-01-28', 'where': [51, -1]})  # (2)!
except ValidationError as e:
    print(e)
    """
    2 validation errors for Event
    when
      Input should be a valid date [type=date_type, input_value='1987-01-28', input_type=str]
    where
      Input should be a valid tuple [type=tuple_type, input_value=[51, -1], input_type=list]
    """
  1. JSONにはdate型もタプル型もありませんが、Pydanticはそれを知っているので、JSONを直接解析するときには文字列と配列をそれぞれ入力として使用できます。
  1. 同じ値をmodel_validateメソッドに渡した場合、strict設定が有効になっているため、Pydanticは検証エラーを発生します。

v2.5.0以降では、Pydanticは高速で反復可能なJSONパーサーであるjiterを使用してJSONデータを解析します。 serdeと比較してjeterを使用すると、将来さらに良くなるであろう適度なパフォーマンスの改善が得られます。

jeterJSONパーサーはserdeJSONパーサーとほぼ完全に互換性がありますが、注目すべき改良点の1つはjeterinf値とNaN値のデシリアライズをサポートしていることです。 将来、jeterは、サポート検証エラーが、無効な値を含む元のJSON入力内の場所を含むことを可能にすることを意図しています。

Partial JSON Parsing

v2.7.0から、PydanticのJSON parserは、pydantic_core.from_jsonで公開されている部分的なJSON解析をサポートしています。この機能の動作例を次に示します。

from pydantic_core import from_json

partial_json_data = '["aa", "bb", "c'  # (1)!

try:
    result = from_json(partial_json_data, allow_partial=False)
except ValueError as e:
    print(e)  # (2)!
    #> EOF while parsing a string at line 1 column 15

result = from_json(partial_json_data, allow_partial=True)
print(result)  # (3)!
#> ['aa', 'bb']
  1. JSONリストが不完全です - "]で閉じられていません。
  1. allow_partialFalse(デフォルト)に設定されている場合、解析エラーが発生します。
  1. allow_partialTrueに設定されている場合、入力の一部が正常にデシリアライズされます。

これは、部分的な辞書をデシリアライズする場合にも有効です。

from pydantic_core import from_json

partial_dog_json = '{"breed": "lab", "name": "fluffy", "friends": ["buddy", "spot", "rufus"], "age'
dog_dict = from_json(partial_dog_json, allow_partial=True)
print(dog_dict)
#> {'breed': 'lab', 'name': 'fluffy', 'friends': ['buddy', 'spot', 'rufus']}

Validating LLM Output

この機能は、LLM出力の検証に特に有効です。 私たちはこのトピックについていくつかのブログ記事を書いており、ここで見ることができます。

Pydanticの将来のバージョンでは、Pydanticの他のJSON検証関数(pydantic.main.BaseModel.model_validate_jsonおよびpydantic.type_adapter.TypeAdapter.validate_json)またはモデル構成のいずれかを使用して、この機能のサポートを拡張する予定です🚀!

今のところ、pydantic_core.from_jsonpydantic.main.BaseModel.model_validateと組み合わせて使用しても同じ結果が得られます。以下に例を示します。

from pydantic_core import from_json

from pydantic import BaseModel


class Dog(BaseModel):
    breed: str
    name: str
    friends: list


partial_dog_json = '{"breed": "lab", "name": "fluffy", "friends": ["buddy", "spot", "rufus"], "age'
dog = Dog.model_validate(from_json(partial_dog_json, allow_partial=True))
print(repr(dog))
#> Dog(breed='lab', name='fluffy', friends=['buddy', 'spot', 'rufus'])

Tip

部分的なJSON解析が確実に動作するためには、モデル上のすべてのフィールドにデフォルト値が必要です。

部分的なJSON解析でデフォルト値を使用する方法の詳細については、次の例を参照してください。

Using default values with partial JSON parsing

from typing import Any, Optional, Tuple

import pydantic_core
from typing_extensions import Annotated

from pydantic import BaseModel, ValidationError, WrapValidator


def default_on_error(v, handler) -> Any:
    """
    Raise a PydanticUseDefault exception if the value is missing.

    This is useful for avoiding errors from partial
    JSON preventing successful validation.
    """
    try:
        return handler(v)
    except ValidationError as exc:
        # there might be other types of errors resulting from partial JSON parsing
        # that you allow here, feel free to customize as needed
        if all(e['type'] == 'missing' for e in exc.errors()):
            raise pydantic_core.PydanticUseDefault()
        else:
            raise


class NestedModel(BaseModel):
    x: int
    y: str


class MyModel(BaseModel):
    foo: Optional[str] = None
    bar: Annotated[
        Optional[Tuple[str, int]], WrapValidator(default_on_error)
    ] = None
    nested: Annotated[
        Optional[NestedModel], WrapValidator(default_on_error)
    ] = None


m = MyModel.model_validate(
    pydantic_core.from_json('{"foo": "x", "bar": ["world",', allow_partial=True)
)
print(repr(m))
#> MyModel(foo='x', bar=None, nested=None)


m = MyModel.model_validate(
    pydantic_core.from_json(
        '{"foo": "x", "bar": ["world", 1], "nested": {"x":', allow_partial=True
    )
)
print(repr(m))
#> MyModel(foo='x', bar=('world', 1), nested=None)

Caching Strings

v2.7.0から、PydanticのJSONパーサは、JSONの解析と検証中にPython文字列をキャッシュする方法の設定をサポートしています(Python検証中にPython文字列がRust文字列から構築される場合、例えばstrip_whitespace=Trueの後など)。

cache_stringsの設定は、model configpydantic_core.from_jsonの両方で公開されています。

cache_strings設定には、次のいずれかの値を指定できます。

  • Trueまたは'all'(デフォルト): すべての文字列をキャッシュします。
  • 'keys': 辞書キーのみをキャッシュします。これはpydantic_core.from_jsonと一緒に使用する場合、またはJsonを使用してJSONを解析する場合にのみ適用されます。
  • Falseまたは'none': キャッシュしない

文字列キャッシング機能を使用すると、パフォーマンスが向上しますが、メモリ使用量が若干増加します。

String Caching Details

1. 文字列は、サイズ16,384のフルアソシアティブ方式を使用してキャッシュされます。 2. len(string)<64の文字列のみがキャッシュされます。 3. キャッシュの検索には多少のオーバーヘッドがありますが、これは通常、文字列の構築を避けるために行う価値があります。ただし、データ内に繰り返される文字列がほとんどないことがわかっている場合は、cache_strings=Falseでこの設定を無効にすることでパフォーマンスが向上する可能性があります。

JSON Serialization

API Documentation

pydantic.main.BaseModel.model_dump_json
pydantic.type_adapter.TypeAdapter.dump_json
pydantic_core.to_json

JSONシリアライゼーションの詳細については、Serialization Conceptsページを参照してください。