Coverage for pydantic/_internal/_dataclasses.py: 95.59%
62 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-16 14:56 +0000
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-16 14:56 +0000
1"""Private logic for creating pydantic dataclasses."""
3from __future__ import annotations as _annotations 1abcdefghijkHIlmnopqrstuvJwxyzABCDEFG
5import typing 1abcdefghijkHIlmnopqrstuvJwxyzABCDEFG
6import warnings 1abcdefghijkHIlmnopqrstuvJwxyzABCDEFG
7from functools import partial 1abcdefghijkHIlmnopqrstuvJwxyzABCDEFG
8from typing import Any, ClassVar 1abcdefghijkHIlmnopqrstuvJwxyzABCDEFG
10from pydantic_core import ( 1abcdefghijkHIlmnopqrstuvJwxyzABCDEFG
11 ArgsKwargs,
12 SchemaSerializer,
13 SchemaValidator,
14 core_schema,
15)
16from typing_extensions import TypeIs 1abcdefghijkHIlmnopqrstuvJwxyzABCDEFG
18from ..errors import PydanticUndefinedAnnotation 1abcdefghijkHIlmnopqrstuvJwxyzABCDEFG
19from ..plugin._schema_validator import PluggableSchemaValidator, create_schema_validator 1abcdefghijkHIlmnopqrstuvJwxyzABCDEFG
20from ..warnings import PydanticDeprecatedSince20 1abcdefghijkHIlmnopqrstuvJwxyzABCDEFG
21from . import _config, _decorators 1abcdefghijkHIlmnopqrstuvJwxyzABCDEFG
22from ._fields import collect_dataclass_fields 1abcdefghijkHIlmnopqrstuvJwxyzABCDEFG
23from ._generate_schema import GenerateSchema, InvalidSchemaError 1abcdefghijkHIlmnopqrstuvJwxyzABCDEFG
24from ._generics import get_standard_typevars_map 1abcdefghijkHIlmnopqrstuvJwxyzABCDEFG
25from ._mock_val_ser import set_dataclass_mocks 1abcdefghijkHIlmnopqrstuvJwxyzABCDEFG
26from ._namespace_utils import NsResolver 1abcdefghijkHIlmnopqrstuvJwxyzABCDEFG
27from ._signature import generate_pydantic_signature 1abcdefghijkHIlmnopqrstuvJwxyzABCDEFG
28from ._utils import LazyClassAttribute 1abcdefghijkHIlmnopqrstuvJwxyzABCDEFG
30if typing.TYPE_CHECKING: 1abcdefghijkHIlmnopqrstuvJwxyzABCDEFG
31 from _typeshed import DataclassInstance as StandardDataclass
33 from ..config import ConfigDict
34 from ..fields import FieldInfo
36 class PydanticDataclass(StandardDataclass, typing.Protocol):
37 """A protocol containing attributes only available once a class has been decorated as a Pydantic dataclass.
39 Attributes:
40 __pydantic_config__: Pydantic-specific configuration settings for the dataclass.
41 __pydantic_complete__: Whether dataclass building is completed, or if there are still undefined fields.
42 __pydantic_core_schema__: The pydantic-core schema used to build the SchemaValidator and SchemaSerializer.
43 __pydantic_decorators__: Metadata containing the decorators defined on the dataclass.
44 __pydantic_fields__: Metadata about the fields defined on the dataclass.
45 __pydantic_serializer__: The pydantic-core SchemaSerializer used to dump instances of the dataclass.
46 __pydantic_validator__: The pydantic-core SchemaValidator used to validate instances of the dataclass.
47 """
49 __pydantic_config__: ClassVar[ConfigDict]
50 __pydantic_complete__: ClassVar[bool]
51 __pydantic_core_schema__: ClassVar[core_schema.CoreSchema]
52 __pydantic_decorators__: ClassVar[_decorators.DecoratorInfos]
53 __pydantic_fields__: ClassVar[dict[str, FieldInfo]]
54 __pydantic_serializer__: ClassVar[SchemaSerializer]
55 __pydantic_validator__: ClassVar[SchemaValidator | PluggableSchemaValidator]
57 @classmethod
58 def __pydantic_fields_complete__(self) -> bool: ...
60else:
61 # See PyCharm issues https://youtrack.jetbrains.com/issue/PY-21915
62 # and https://youtrack.jetbrains.com/issue/PY-51428
63 DeprecationWarning = PydanticDeprecatedSince20 1abcdefghijkHIlmnopqrstuvJwxyzABCDEFG
66def set_dataclass_fields( 1abcdefghijklmnopqrstuvJwxyzABCDEFG
67 cls: type[StandardDataclass],
68 config_wrapper: _config.ConfigWrapper,
69 ns_resolver: NsResolver | None = None,
70) -> None:
71 """Collect and set `cls.__pydantic_fields__`.
73 Args:
74 cls: The class.
75 config_wrapper: The config wrapper instance.
76 ns_resolver: Namespace resolver to use when getting dataclass annotations.
77 """
78 typevars_map = get_standard_typevars_map(cls) 1abcdefghijkHIlmnopqrstuvJwxyzABCDEFG
79 fields = collect_dataclass_fields( 1abcdefghijkHIlmnopqrstuvJwxyzABCDEFG
80 cls, ns_resolver=ns_resolver, typevars_map=typevars_map, config_wrapper=config_wrapper
81 )
83 cls.__pydantic_fields__ = fields # type: ignore 1abcdefghijkHIlmnopqrstuvJwxyzABCDEFG
86def complete_dataclass( 1abcdefghijkHIlmnopqrstuvJwxyzABCDEFG
87 cls: type[Any],
88 config_wrapper: _config.ConfigWrapper,
89 *,
90 raise_errors: bool = True,
91 ns_resolver: NsResolver | None = None,
92 _force_build: bool = False,
93) -> bool:
94 """Finish building a pydantic dataclass.
96 This logic is called on a class which has already been wrapped in `dataclasses.dataclass()`.
98 This is somewhat analogous to `pydantic._internal._model_construction.complete_model_class`.
100 Args:
101 cls: The class.
102 config_wrapper: The config wrapper instance.
103 raise_errors: Whether to raise errors, defaults to `True`.
104 ns_resolver: The namespace resolver instance to use when collecting dataclass fields
105 and during schema building.
106 _force_build: Whether to force building the dataclass, no matter if
107 [`defer_build`][pydantic.config.ConfigDict.defer_build] is set.
109 Returns:
110 `True` if building a pydantic dataclass is successfully completed, `False` otherwise.
112 Raises:
113 PydanticUndefinedAnnotation: If `raise_error` is `True` and there is an undefined annotations.
114 """
115 original_init = cls.__init__ 1abcdefghijkHIlmnopqrstuvJwxyzABCDEFG
117 # dataclass.__init__ must be defined here so its `__qualname__` can be changed since functions can't be copied,
118 # and so that the mock validator is used if building was deferred:
119 def __init__(__dataclass_self__: PydanticDataclass, *args: Any, **kwargs: Any) -> None: 1abcdefghijkHIlmnopqrstuvJwxyzABCDEFG
120 __tracebackhide__ = True 1abcdefghijkHIlmnopqrstuvJwxyzABCDEFG
121 s = __dataclass_self__ 1abcdefghijkHIlmnopqrstuvJwxyzABCDEFG
122 s.__pydantic_validator__.validate_python(ArgsKwargs(args, kwargs), self_instance=s) 1abcdefghijkHIlmnopqrstuvJwxyzABCDEFG
124 __init__.__qualname__ = f'{cls.__qualname__}.__init__' 1abcdefghijkHIlmnopqrstuvJwxyzABCDEFG
126 cls.__init__ = __init__ # type: ignore 1abcdefghijkHIlmnopqrstuvJwxyzABCDEFG
127 cls.__pydantic_config__ = config_wrapper.config_dict # type: ignore 1abcdefghijkHIlmnopqrstuvJwxyzABCDEFG
129 set_dataclass_fields(cls, config_wrapper=config_wrapper, ns_resolver=ns_resolver) 1abcdefghijkHIlmnopqrstuvJwxyzABCDEFG
131 if not _force_build and config_wrapper.defer_build: 1abcdefghijkHIlmnopqrstuvJwxyzABCDEFG
132 set_dataclass_mocks(cls) 1abcdefghijkHIlmnopqrstuvwxyzABCDEFG
133 return False 1abcdefghijkHIlmnopqrstuvwxyzABCDEFG
135 if hasattr(cls, '__post_init_post_parse__'): 1abcdefghijkHIlmnopqrstuvJwxyzABCDEFG
136 warnings.warn( 1abcdefghijkHIlmnopqrstuvwxyzABCDEFG
137 'Support for `__post_init_post_parse__` has been dropped, the method will not be called', DeprecationWarning
138 )
140 typevars_map = get_standard_typevars_map(cls) 1abcdefghijkHIlmnopqrstuvJwxyzABCDEFG
141 gen_schema = GenerateSchema( 1abcdefghijkHIlmnopqrstuvJwxyzABCDEFG
142 config_wrapper,
143 ns_resolver=ns_resolver,
144 typevars_map=typevars_map,
145 )
147 # set __signature__ attr only for the class, but not for its instances
148 # (because instances can define `__call__`, and `inspect.signature` shouldn't
149 # use the `__signature__` attribute and instead generate from `__call__`).
150 cls.__signature__ = LazyClassAttribute( 1abcdefghijkHIlmnopqrstuvJwxyzABCDEFG
151 '__signature__',
152 partial(
153 generate_pydantic_signature,
154 # It's important that we reference the `original_init` here,
155 # as it is the one synthesized by the stdlib `dataclass` module:
156 init=original_init,
157 fields=cls.__pydantic_fields__, # type: ignore
158 validate_by_name=config_wrapper.validate_by_name,
159 extra=config_wrapper.extra,
160 is_dataclass=True,
161 ),
162 )
164 try: 1abcdefghijkHIlmnopqrstuvJwxyzABCDEFG
165 schema = gen_schema.generate_schema(cls) 1abcdefghijkHIlmnopqrstuvJwxyzABCDEFG
166 except PydanticUndefinedAnnotation as e: 1abcdefghijkHIlmnopqrstuvwxyzABCDEFG
167 if raise_errors: 1abcdefghijkHIlmnopqrstuvwxyzABCDEFG
168 raise 1abcdefghijkHIlmnopqrstuvwxyzABCDEFG
169 set_dataclass_mocks(cls, f'`{e.name}`') 1abcdefghijkHIlmnopqrstuvwxyzABCDEFG
170 return False 1abcdefghijkHIlmnopqrstuvwxyzABCDEFG
172 core_config = config_wrapper.core_config(title=cls.__name__) 1abcdefghijkHIlmnopqrstuvJwxyzABCDEFG
174 try: 1abcdefghijkHIlmnopqrstuvJwxyzABCDEFG
175 schema = gen_schema.clean_schema(schema) 1abcdefghijkHIlmnopqrstuvJwxyzABCDEFG
176 except InvalidSchemaError:
177 set_dataclass_mocks(cls)
178 return False
180 # We are about to set all the remaining required properties expected for this cast;
181 # __pydantic_decorators__ and __pydantic_fields__ should already be set
182 cls = typing.cast('type[PydanticDataclass]', cls) 1abcdefghijkHIlmnopqrstuvJwxyzABCDEFG
184 cls.__pydantic_core_schema__ = schema 1abcdefghijkHIlmnopqrstuvJwxyzABCDEFG
185 cls.__pydantic_validator__ = create_schema_validator( 1abcdefghijkHIlmnopqrstuvJwxyzABCDEFG
186 schema, cls, cls.__module__, cls.__qualname__, 'dataclass', core_config, config_wrapper.plugin_settings
187 )
188 cls.__pydantic_serializer__ = SchemaSerializer(schema, core_config) 1abcdefghijkHIlmnopqrstuvJwxyzABCDEFG
189 cls.__pydantic_complete__ = True 1abcdefghijkHIlmnopqrstuvJwxyzABCDEFG
190 return True 1abcdefghijkHIlmnopqrstuvJwxyzABCDEFG
193def is_stdlib_dataclass(cls: type[Any], /) -> TypeIs[type[StandardDataclass]]: 1abcdefghijkHIlmnopqrstuvJwxyzABCDEFG
194 """Returns `True` if the class is a stdlib dataclass and *not* a Pydantic dataclass.
196 Unlike the stdlib `dataclasses.is_dataclass()` function, this does *not* include subclasses
197 of a dataclass that are themselves not dataclasses.
199 Args:
200 cls: The class.
202 Returns:
203 `True` if the class is a stdlib dataclass, `False` otherwise.
204 """
205 return '__dataclass_fields__' in cls.__dict__ and not hasattr(cls, '__pydantic_validator__') 1abcdefghijkHIlmnopqrstuvJwxyzABCDEFG