विषय पर बढ़ें

??? एपीआई "एपीआई दस्तावेज़ीकरण" pydantic.dataclasses.dataclass

यदि आप पाइडेंटिक के BaseModel उपयोग नहीं करना चाहते हैं तो आप इसके बजाय मानक डेटाक्लासेस (पायथन 3.7 में प्रस्तुत) पर समान डेटा सत्यापन प्राप्त कर सकते हैं।

from datetime import datetime

from pydantic.dataclasses import dataclass


@dataclass
class User:
    id: int
    name: str = 'John Doe'
    signup_ts: datetime = None


user = User(id='42', signup_ts='2032-06-21T12:00')
print(user)
"""
User(id=42, name='John Doe', signup_ts=datetime.datetime(2032, 6, 21, 12, 0))
"""

!!! नोट इसका ध्यान रखें pydantic.dataclasses.dataclass pydantic.BaseModel का प्रतिस्थापन नहीं है। pydantic.dataclasses.dataclass Pydantic सत्यापन के अतिरिक्त dataclasses.dataclass को समान कार्यक्षमता प्रदान करता है। ऐसे मामले हैं जहां pydantic.BaseModel उपवर्गित करना बेहतर विकल्प है।

For more information and discussion see
[pydantic/pydantic#710](https://github.com/pydantic/pydantic/issues/710).

पाइडेंटिक डेटाक्लास और BaseModel के बीच कुछ अंतरों में शामिल हैं:

आप सभी मानक पाइडेंटिक फ़ील्ड प्रकारों का उपयोग कर सकते हैं। हालाँकि, ध्यान दें कि कन्स्ट्रक्टर को दिए गए तर्कों को सत्यापन करने के लिए और, जहां आवश्यक हो, जबरदस्ती करने के लिए कॉपी किया जाएगा।

पाइडेंटिक डेटाक्लास पर सत्यापन करने या JSON स्कीमा उत्पन्न करने के लिए, अब आपको डेटाक्लास को TypeAdapter के साथ लपेटना चाहिए और इसके तरीकों का उपयोग करना चाहिए।

जिन फ़ील्ड के लिए default_factory आवश्यकता होती है, उन्हें pydantic.Field या dataclasses.field द्वारा निर्दिष्ट किया जा सकता है।

import dataclasses
from typing import List, Optional

from pydantic import Field, TypeAdapter
from pydantic.dataclasses import dataclass


@dataclass
class User:
    id: int
    name: str = 'John Doe'
    friends: List[int] = dataclasses.field(default_factory=lambda: [0])
    age: Optional[int] = dataclasses.field(
        default=None,
        metadata=dict(title='The age of the user', description='do not lie!'),
    )
    height: Optional[int] = Field(None, title='The height in cm', ge=50, le=300)


user = User(id='42')
print(TypeAdapter(User).json_schema())
"""
{
    'properties': {
        'id': {'title': 'Id', 'type': 'integer'},
        'name': {'default': 'John Doe', 'title': 'Name', 'type': 'string'},
        'friends': {
            'items': {'type': 'integer'},
            'title': 'Friends',
            'type': 'array',
        },
        'age': {
            'anyOf': [{'type': 'integer'}, {'type': 'null'}],
            'default': None,
            'description': 'do not lie!',
            'title': 'The age of the user',
        },
        'height': {
            'anyOf': [
                {'maximum': 300, 'minimum': 50, 'type': 'integer'},
                {'type': 'null'},
            ],
            'default': None,
            'title': 'The height in cm',
        },
    },
    'required': ['id'],
    'title': 'User',
    'type': 'object',
}
"""

pydantic.dataclasses.dataclass के तर्क मानक डेकोरेटर के समान हैं, सिवाय एक अतिरिक्त कीवर्ड तर्क config , जिसका अर्थ model_config के समान है।

!!! चेतावनी v1.2 के बाद, चेक पाइडेंटिक डेटाक्लासेस टाइप करने के लिए Mypy प्लगइन स्थापित किया जाना चाहिए।

डेटाक्लास के साथ सत्यापनकर्ताओं के संयोजन के बारे में अधिक जानकारी के लिए, डेटाक्लास सत्यापनकर्ता देखें।

डेटाक्लास कॉन्फ़िगरेशन

यदि आप config उसी तरह संशोधित करना चाहते हैं जैसे आप BaseModel के साथ करेंगे, तो आपके पास दो विकल्प हैं:

  • डेटाक्लास डेकोरेटर पर एक निर्देश के रूप में कॉन्फ़िगरेशन लागू करें
  • कॉन्फिग के रूप में ConfigDict उपयोग करें

    from pydantic import ConfigDict from pydantic.dataclasses import dataclass

    Option 1 - use directly a dict

    Note: mypy will still raise typo error

    @dataclass(config=dict(validate_assignment=True)) # (1)! class MyDataclass1: a: int

    Option 2 - use ConfigDict

    (same as before at runtime since it's a TypedDict but with intellisense)

    @dataclass(config=ConfigDict(validate_assignment=True)) class MyDataclass2: a: int

  • आप एपीआई संदर्भ में validate_assignment के बारे में अधिक पढ़ सकते हैं।

!!! नोट पाइडेंटिक डेटाक्लासेस extra कॉन्फ़िगरेशन को ignore , forbid , या इनिशियलाइज़र को अतिरिक्त फ़ील्ड पास allow का समर्थन करता है। हालाँकि, stdlib डेटाक्लास का कुछ डिफ़ॉल्ट व्यवहार प्रबल हो सकता है। उदाहरण के लिए, extra='allow' का उपयोग करके पाइडेंटिक डेटाक्लास पर मौजूद कोई भी अतिरिक्त फ़ील्ड डेटाक्लास के print पर छोड़ दिया जाता है।

नेस्टेड डेटाक्लासेस

नेस्टेड डेटाक्लास डेटाक्लास और सामान्य मॉडल दोनों में समर्थित हैं।

from pydantic import AnyUrl
from pydantic.dataclasses import dataclass


@dataclass
class NavbarButton:
    href: AnyUrl


@dataclass
class Navbar:
    button: NavbarButton


navbar = Navbar(button={'href': 'https://example.com'})
print(navbar)
#> Navbar(button=NavbarButton(href=Url('https://example.com/')))

जब फ़ील्ड के रूप में उपयोग किया जाता है, तो डेटाक्लास (पाइडेंटिक या वेनिला) को सत्यापन इनपुट के रूप में डिक्ट्स का उपयोग करना चाहिए।

सामान्य डेटाक्लास

पाइडेंटिक जेनेरिक डेटाक्लास का समर्थन करता है, जिसमें टाइप वेरिएबल वाले डेटाक्लास भी शामिल हैं।

from typing import Generic, TypeVar

from pydantic import TypeAdapter
from pydantic.dataclasses import dataclass

T = TypeVar('T')


@dataclass
class GenericDataclass(Generic[T]):
    x: T


validator = TypeAdapter(GenericDataclass)

assert validator.validate_python({'x': None}).x is None
assert validator.validate_python({'x': 1}).x == 1
assert validator.validate_python({'x': 'a'}).x == 'a'

ध्यान दें, यदि आप डेटाक्लास को BaseModel के फ़ील्ड के रूप में या फास्टएपीआई के माध्यम से उपयोग करते हैं तो आपको TypeAdapter आवश्यकता नहीं है।

Stdlib डेटाक्लास और पाइडेंटिक डेटाक्लास

stdlib डेटाक्लास से इनहेरिट करें

Stdlib डेटाक्लासेस (नेस्टेड या नहीं) को भी इनहेरिट किया जा सकता है और Pydantic स्वचालित रूप से सभी इनहेरिट किए गए फ़ील्ड को मान्य कर देगा।

import dataclasses

import pydantic


@dataclasses.dataclass
class Z:
    z: int


@dataclasses.dataclass
class Y(Z):
    y: int = 0


@pydantic.dataclasses.dataclass
class X(Y):
    x: int = 0


foo = X(x=b'1', y='2', z='3')
print(foo)
#> X(z=3, y=2, x=1)

try:
    X(z='pika')
except pydantic.ValidationError as e:
    print(e)
    """
    1 validation error for X
    z
      Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='pika', input_type=str]
    """

BaseModel के साथ stdlib डेटाक्लास का उपयोग

ध्यान रखें कि BaseModel के साथ मिश्रित होने पर stdlib डेटाक्लास (नेस्टेड या नहीं) स्वचालित रूप से पाइडेंटिक डेटाक्लास में परिवर्तित हो जाते हैं! इसके अलावा जेनरेट किए गए पाइडेंटिक डेटाक्लास में मूल कॉन्फ़िगरेशन ( order , frozen , ...) जैसा ही होगा।

import dataclasses
from datetime import datetime
from typing import Optional

from pydantic import BaseModel, ConfigDict, ValidationError


@dataclasses.dataclass(frozen=True)
class User:
    name: str


@dataclasses.dataclass
class File:
    filename: str
    last_modification_time: Optional[datetime] = None


class Foo(BaseModel):
    # Required so that pydantic revalidates the model attributes
    model_config = ConfigDict(revalidate_instances='always')

    file: File
    user: Optional[User] = None


file = File(
    filename=['not', 'a', 'string'],
    last_modification_time='2020-01-01T00:00',
)  # nothing is validated as expected
print(file)
"""
File(filename=['not', 'a', 'string'], last_modification_time='2020-01-01T00:00')
"""

try:
    Foo(file=file)
except ValidationError as e:
    print(e)
    """
    1 validation error for Foo
    file.filename
      Input should be a valid string [type=string_type, input_value=['not', 'a', 'string'], input_type=list]
    """

foo = Foo(file=File(filename='myfile'), user=User(name='pika'))
try:
    foo.user.name = 'bulbi'
except dataclasses.FrozenInstanceError as e:
    print(e)
    #> cannot assign to field 'name'

कस्टम प्रकार का प्रयोग करें

चूंकि stdlib डेटाक्लास स्वचालित रूप से सत्यापन जोड़ने के लिए परिवर्तित हो जाते हैं, कस्टम प्रकारों का उपयोग करने से कुछ अप्रत्याशित व्यवहार हो सकता है। इस मामले में आप कॉन्फिगरेशन में मनमाने ढंग arbitrary_types_allowed जोड़ सकते हैं!

import dataclasses

from pydantic import BaseModel, ConfigDict
from pydantic.errors import PydanticSchemaGenerationError


class ArbitraryType:
    def __init__(self, value):
        self.value = value

    def __repr__(self):
        return f'ArbitraryType(value={self.value!r})'


@dataclasses.dataclass
class DC:
    a: ArbitraryType
    b: str


# valid as it is a builtin dataclass without validation
my_dc = DC(a=ArbitraryType(value=3), b='qwe')

try:

    class Model(BaseModel):
        dc: DC
        other: str

    # invalid as it is now a pydantic dataclass
    Model(dc=my_dc, other='other')
except PydanticSchemaGenerationError as e:
    print(e.message)
    """
    Unable to generate pydantic-core schema for <class '__main__.ArbitraryType'>. Set `arbitrary_types_allowed=True` in the model_config to ignore this error or implement `__get_pydantic_core_schema__` on your type to fully support it.

    If you got this error by calling handler(<some type>) within `__get_pydantic_core_schema__` then you likely need to call `handler.generate_schema(<some type>)` since we do not call `__get_pydantic_core_schema__` on `<some type>` otherwise to avoid infinite recursion.
    """


class Model(BaseModel):
    model_config = ConfigDict(arbitrary_types_allowed=True)

    dc: DC
    other: str


m = Model(dc=my_dc, other='other')
print(repr(m))
#> Model(dc=DC(a=ArbitraryType(value=3), b='qwe'), other='other')

जाँच कर रहा है कि क्या डेटाक्लास एक पाइडेंटिक डेटाक्लास है

पाइडेंटिक डेटाक्लास को अभी भी डेटाक्लास माना जाता है, इसलिए dataclasses.is_dataclass उपयोग करने पर True वापस आ जाएगा। यह जांचने के लिए कि क्या कोई प्रकार विशेष रूप से एक पाइडेंटिक डेटाक्लास है, आप इसका उपयोग कर सकते हैं pydantic.dataclasses.is_pydantic_dataclass .

import dataclasses

import pydantic


@dataclasses.dataclass
class StdLibDataclass:
    id: int


PydanticDataclass = pydantic.dataclasses.dataclass(StdLibDataclass)

print(dataclasses.is_dataclass(StdLibDataclass))
#> True
print(pydantic.dataclasses.is_pydantic_dataclass(StdLibDataclass))
#> False

print(dataclasses.is_dataclass(PydanticDataclass))
#> True
print(pydantic.dataclasses.is_pydantic_dataclass(PydanticDataclass))
#> True

आरंभीकरण हुक

जब आप डेटाक्लास प्रारंभ करते हैं, तो @model_validator डेकोरेटर mode पैरामीटर की सहायता से सत्यापन से पहले या बाद में कोड निष्पादित करना संभव है।

from typing import Any, Dict

from typing_extensions import Self

from pydantic import model_validator
from pydantic.dataclasses import dataclass


@dataclass
class Birth:
    year: int
    month: int
    day: int


@dataclass
class User:
    birth: Birth

    @model_validator(mode='before')
    @classmethod
    def pre_root(cls, values: Dict[str, Any]) -> Dict[str, Any]:
        print(f'First: {values}')
        """
        First: ArgsKwargs((), {'birth': {'year': 1995, 'month': 3, 'day': 2}})
        """
        return values

    @model_validator(mode='after')
    def post_root(self) -> Self:
        print(f'Third: {self}')
        #> Third: User(birth=Birth(year=1995, month=3, day=2))
        return self

    def __post_init__(self):
        print(f'Second: {self.birth}')
        #> Second: Birth(year=1995, month=3, day=2)


user = User(**{'birth': {'year': 1995, 'month': 3, 'day': 2}})

पाइडेंटिक डेटाक्लास में __post_init__ सत्यापनकर्ताओं के बीच में कहा जाता है। यहाँ आदेश है:

  • model_validator(mode='before')
  • field_validator(mode='before')
  • field_validator(mode='after')
  • आंतरिक सत्यापनकर्ता। उदाहरण के लिए int , str , ... जैसे प्रकारों के लिए सत्यापन
  • __post_init__
  • model_validator(mode='after')

    from dataclasses import InitVar from pathlib import Path from typing import Optional

    from pydantic.dataclasses import dataclass

    @dataclass class PathData: path: Path base_path: InitVar[Optional[Path]]

    def __post_init__(self, base_path):
        print(f'Received path={self.path!r}, base_path={base_path!r}')
        #> Received path=PosixPath('world'), base_path=PosixPath('/hello')
        if base_path is not None:
            self.path = base_path / self.path
    

    path_data = PathData('world', base_path='/hello')

    Received path='world', base_path='/hello'

    assert path_data.path == Path('/hello/world')

stdlib डेटाक्लास के साथ अंतर

ध्यान दें कि Python stdlib से dataclasses.dataclass केवल __post_init__ विधि लागू करता है क्योंकि यह सत्यापन चरण नहीं चलाता है।

JSON डंपिंग

पाइडेंटिक डेटाक्लास में .model_dump_json() फ़ंक्शन की सुविधा नहीं है। उन्हें JSON के रूप में डंप करने के लिए, आपको निम्नानुसार RootModel का उपयोग करना होगा:

import dataclasses
from typing import List

from pydantic import RootModel
from pydantic.dataclasses import dataclass


@dataclass
class User:
    id: int
    name: str = 'John Doe'
    friends: List[int] = dataclasses.field(default_factory=lambda: [0])


user = User(id='42')
print(RootModel[User](User(id='42')).model_dump_json(indent=4))
"""
{
    "id": 42,
    "name": "John Doe",
    "friends": [
        0
    ]
}
"""

本文总阅读量