Coverage for /pythoncovmergedfiles/medio/medio/src/pydantic/pydantic/dataclasses.py: 43%
60 statements
« prev ^ index » next coverage.py v7.2.3, created at 2023-04-27 07:38 +0000
« prev ^ index » next coverage.py v7.2.3, created at 2023-04-27 07:38 +0000
1"""
2Provide an enhanced dataclass that performs validation.
3"""
4from __future__ import annotations as _annotations
6import dataclasses
7import sys
8import types
9from typing import TYPE_CHECKING, Any, Callable, Generic, TypeVar, overload
11from typing_extensions import Literal, dataclass_transform
13from ._internal import _config, _decorators
14from ._internal import _dataclasses as _pydantic_dataclasses
15from ._internal._dataclasses import is_builtin_dataclass
16from ._migration import getattr_migration
17from .config import ConfigDict
18from .fields import Field
20if TYPE_CHECKING:
21 from ._internal._dataclasses import PydanticDataclass
23__all__ = ('dataclass',)
25_T = TypeVar('_T')
27if sys.version_info >= (3, 10):
29 @dataclass_transform(field_specifiers=(dataclasses.field, Field))
30 @overload
31 def dataclass(
32 *,
33 init: Literal[False] = False,
34 repr: bool = True,
35 eq: bool = True,
36 order: bool = False,
37 unsafe_hash: bool = False,
38 frozen: bool = False,
39 config: ConfigDict | type[object] | None = None,
40 validate_on_init: bool | None = None,
41 kw_only: bool = ...,
42 ) -> Callable[[type[_T]], type[PydanticDataclass]]: # type: ignore
43 """Overload for `dataclass`."""
44 ...
46 @dataclass_transform(field_specifiers=(dataclasses.field, Field))
47 @overload
48 def dataclass(
49 _cls: type[_T], # type: ignore
50 *,
51 init: Literal[False] = False,
52 repr: bool = True,
53 eq: bool = True,
54 order: bool = False,
55 unsafe_hash: bool = False,
56 frozen: bool = False,
57 config: ConfigDict | type[object] | None = None,
58 validate_on_init: bool | None = None,
59 kw_only: bool = ...,
60 ) -> type[PydanticDataclass]:
61 """Overload for `dataclass`."""
62 ...
64else:
66 @dataclass_transform(field_specifiers=(dataclasses.field, Field))
67 @overload
68 def dataclass(
69 *,
70 init: Literal[False] = False,
71 repr: bool = True,
72 eq: bool = True,
73 order: bool = False,
74 unsafe_hash: bool = False,
75 frozen: bool = False,
76 config: ConfigDict | type[object] | None = None,
77 validate_on_init: bool | None = None,
78 ) -> Callable[[type[_T]], type[PydanticDataclass]]: # type: ignore
79 """Overload for `dataclass`."""
80 ...
82 @dataclass_transform(field_specifiers=(dataclasses.field, Field))
83 @overload
84 def dataclass(
85 _cls: type[_T], # type: ignore
86 *,
87 init: Literal[False] = False,
88 repr: bool = True,
89 eq: bool = True,
90 order: bool = False,
91 unsafe_hash: bool = False,
92 frozen: bool = False,
93 config: ConfigDict | type[object] | None = None,
94 validate_on_init: bool | None = None,
95 ) -> type[PydanticDataclass]:
96 """Overload for `dataclass`."""
97 ...
100@dataclass_transform(field_specifiers=(dataclasses.field, Field))
101def dataclass(
102 _cls: type[_T] | None = None,
103 *,
104 init: Literal[False] = False,
105 repr: bool = True,
106 eq: bool = True,
107 order: bool = False,
108 unsafe_hash: bool = False,
109 frozen: bool = False,
110 config: ConfigDict | type[object] | None = None,
111 validate_on_init: bool | None = None,
112 kw_only: bool = False,
113) -> Callable[[type[_T]], type[PydanticDataclass]] | type[PydanticDataclass]:
114 """
115 A decorator used to create a Pydantic-enhanced dataclass, similar to the standard Python `dataclasses`,
116 but with added validation.
118 Args:
119 _cls (type[_T] | None): The target dataclass.
120 init (Literal[False]): If set to `False`, the `dataclass` will not generate an `__init__`,
121 and you will need to provide one. Defaults to `False`.
122 repr (bool): Determines if a `__repr__` should be generated for the class. Defaults to `True`.
123 eq (bool): Determines if a `__eq__` should be generated for the class. Defaults to `True`.
124 order (bool): Determines if comparison magic methods should be generated, such as `__lt__`, but
125 not `__eq__`. Defaults to `False`.
126 unsafe_hash (bool): Determines if an unsafe hashing function should be included in the class.
127 frozen (bool): Determines if the generated class should be a 'frozen' dataclass, which does not allow its
128 attributes to be modified from its constructor. Defaults to `False`.
129 config (ConfigDict | type[object] | None): A configuration for the `dataclass` generation. Defaults to `None`.
130 validate_on_init (bool | None): Determines whether the `dataclass` will be validated upon creation.
131 kw_only (bool): Determines if keyword-only parameters should be used on the `__init__` method. Defaults
132 to `False`.
134 Returns:
135 A callable that takes a `type` as its argument, and returns a `type` of `PydanticDataclass`. This can
136 also return a `tyoe` of `PydanticDataclass` directly.
138 Raises:
139 AssertionError: Raised if `init` is not `False`.
140 """
141 assert init is False, 'pydantic.dataclasses.dataclass only supports init=False'
143 if sys.version_info >= (3, 10):
144 kwargs = dict(kw_only=kw_only)
145 else:
146 kwargs = {}
148 def create_dataclass(cls: type[Any]) -> type[PydanticDataclass]:
149 """Create a Pydantic dataclass from a regular dataclass.
151 Args:
152 cls (type[Any]): The class to create the Pydantic dataclass from.
154 Returns:
155 type[PydanticDataclass]: A Pydantic dataclass.
157 Raises:
158 TypeError: If a non-class value is provided.
159 """
161 config_wrapper = _config.ConfigWrapper(config)
162 decorators = _decorators.DecoratorInfos.build(cls)
164 # Keep track of the original __doc__ so that we can restore it after applying the dataclasses decorator
165 # Otherwise, classes with no __doc__ will have their signature added into the JSON schema description,
166 # since dataclasses.dataclass will set this as the __doc__
167 original_doc = cls.__doc__
169 if is_builtin_dataclass(cls):
170 # Don't preserve the docstring for vanilla dataclasses, as it may include the signature
171 # This matches v1 behavior, and there was an explicit test for it
172 original_doc = None
174 # We don't want to add validation to the existing std lib dataclass, so we will subclass it
175 # If the class is generic, we need to make sure the subclass also inherits from Generic
176 # with all the same parameters.
177 bases = (cls,)
178 if issubclass(cls, Generic): # type: ignore
179 generic_base = Generic[cls.__parameters__] # type: ignore
180 bases = bases + (generic_base,)
181 cls = types.new_class(cls.__name__, bases)
183 cls = dataclasses.dataclass( # type: ignore[call-overload]
184 cls,
185 init=init,
186 repr=repr,
187 eq=eq,
188 order=order,
189 unsafe_hash=unsafe_hash,
190 frozen=frozen,
191 **kwargs,
192 )
194 cls.__pydantic_decorators__ = decorators # type: ignore
195 _pydantic_dataclasses.set_dataclass_fields(cls)
196 _pydantic_dataclasses.complete_dataclass(cls, config_wrapper)
197 cls.__doc__ = original_doc
198 return cls
200 if _cls is None:
201 return create_dataclass
203 return create_dataclass(_cls)
206__getattr__ = getattr_migration(__name__)