Coverage for pydantic/_internal/_model_construction.py: 98.98%
348 statements
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-05 10:27 +0000
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-05 10:27 +0000
1"""Private logic for creating models."""
3from __future__ import annotations as _annotations 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
5import builtins 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
6import operator 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
7import sys 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
8import typing 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
9import warnings 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
10import weakref 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
11from abc import ABCMeta 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
12from functools import cache, partial, wraps 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
13from types import FunctionType 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
14from typing import Any, Callable, Generic, Literal, NoReturn, cast 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
16from pydantic_core import PydanticUndefined, SchemaSerializer 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
17from typing_extensions import TypeAliasType, dataclass_transform, deprecated, get_args, get_origin 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
18from typing_inspection import typing_objects 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
20from ..errors import PydanticUndefinedAnnotation, PydanticUserError 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
21from ..plugin._schema_validator import create_schema_validator 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
22from ..warnings import GenericBeforeBaseModelWarning, PydanticDeprecatedSince20 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
23from ._config import ConfigWrapper 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
24from ._decorators import DecoratorInfos, PydanticDescriptorProxy, get_attribute_from_bases, unwrap_wrapped_function 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
25from ._fields import collect_model_fields, is_valid_field_name, is_valid_privateattr_name, rebuild_model_fields 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
26from ._generate_schema import GenerateSchema, InvalidSchemaError 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
27from ._generics import PydanticGenericMetadata, get_model_typevars_map 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
28from ._import_utils import import_cached_base_model, import_cached_field_info 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
29from ._mock_val_ser import set_model_mocks 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
30from ._namespace_utils import NsResolver 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
31from ._signature import generate_pydantic_signature 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
32from ._typing_extra import ( 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
33 _make_forward_ref,
34 eval_type_backport,
35 is_classvar_annotation,
36 parent_frame_namespace,
37)
38from ._utils import LazyClassAttribute, SafeGetItemProxy 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
40if typing.TYPE_CHECKING: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
41 from ..fields import Field as PydanticModelField
42 from ..fields import FieldInfo, ModelPrivateAttr
43 from ..fields import PrivateAttr as PydanticModelPrivateAttr
44 from ..main import BaseModel
45else:
46 # See PyCharm issues https://youtrack.jetbrains.com/issue/PY-21915
47 # and https://youtrack.jetbrains.com/issue/PY-51428
48 DeprecationWarning = PydanticDeprecatedSince20 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
49 PydanticModelField = object() 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
50 PydanticModelPrivateAttr = object() 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
52object_setattr = object.__setattr__ 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
55class _ModelNamespaceDict(dict): 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
56 """A dictionary subclass that intercepts attribute setting on model classes and
57 warns about overriding of decorators.
58 """
60 def __setitem__(self, k: str, v: object) -> None: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
61 existing: Any = self.get(k, None) 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
62 if existing and v is not existing and isinstance(existing, PydanticDescriptorProxy): 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
63 warnings.warn(f'`{k}` overrides an existing Pydantic `{existing.decorator_info.decorator_repr}` decorator') 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
65 return super().__setitem__(k, v) 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
68def NoInitField( 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
69 *,
70 init: Literal[False] = False,
71) -> Any:
72 """Only for typing purposes. Used as default value of `__pydantic_fields_set__`,
73 `__pydantic_extra__`, `__pydantic_private__`, so they could be ignored when
74 synthesizing the `__init__` signature.
75 """
78@dataclass_transform(kw_only_default=True, field_specifiers=(PydanticModelField, PydanticModelPrivateAttr, NoInitField)) 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
79class ModelMetaclass(ABCMeta): 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
80 def __new__( 1adeofpqArBCbijsktuDvEFJclmwnxyGzHI
81 mcs,
82 cls_name: str,
83 bases: tuple[type[Any], ...],
84 namespace: dict[str, Any],
85 __pydantic_generic_metadata__: PydanticGenericMetadata | None = None,
86 __pydantic_reset_parent_namespace__: bool = True,
87 _create_model_module: str | None = None,
88 **kwargs: Any,
89 ) -> type:
90 """Metaclass for creating Pydantic models.
92 Args:
93 cls_name: The name of the class to be created.
94 bases: The base classes of the class to be created.
95 namespace: The attribute dictionary of the class to be created.
96 __pydantic_generic_metadata__: Metadata for generic models.
97 __pydantic_reset_parent_namespace__: Reset parent namespace.
98 _create_model_module: The module of the class to be created, if created by `create_model`.
99 **kwargs: Catch-all for any other keyword arguments.
101 Returns:
102 The new class created by the metaclass.
103 """
104 # Note `ModelMetaclass` refers to `BaseModel`, but is also used to *create* `BaseModel`, so we rely on the fact
105 # that `BaseModel` itself won't have any bases, but any subclass of it will, to determine whether the `__new__`
106 # call we're in the middle of is for the `BaseModel` class.
107 if bases: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
108 base_field_names, class_vars, base_private_attributes = mcs._collect_bases_data(bases) 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
110 config_wrapper = ConfigWrapper.for_model(bases, namespace, kwargs) 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
111 namespace['model_config'] = config_wrapper.config_dict 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
112 private_attributes = inspect_namespace( 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
113 namespace, config_wrapper.ignored_types, class_vars, base_field_names
114 )
115 if private_attributes or base_private_attributes: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
116 original_model_post_init = get_model_post_init(namespace, bases) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
117 if original_model_post_init is not None: 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
118 # if there are private_attributes and a model_post_init function, we handle both
120 @wraps(original_model_post_init) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
121 def wrapped_model_post_init(self: BaseModel, context: Any, /) -> None: 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
122 """We need to both initialize private attributes and call the user-defined model_post_init
123 method.
124 """
125 init_private_attributes(self, context) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
126 original_model_post_init(self, context) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
128 namespace['model_post_init'] = wrapped_model_post_init 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
129 else:
130 namespace['model_post_init'] = init_private_attributes 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
132 namespace['__class_vars__'] = class_vars 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
133 namespace['__private_attributes__'] = {**base_private_attributes, **private_attributes} 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
135 cls = cast('type[BaseModel]', super().__new__(mcs, cls_name, bases, namespace, **kwargs)) 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
136 BaseModel_ = import_cached_base_model() 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
138 mro = cls.__mro__ 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
139 if Generic in mro and mro.index(Generic) < mro.index(BaseModel_): 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
140 warnings.warn( 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
141 GenericBeforeBaseModelWarning(
142 'Classes should inherit from `BaseModel` before generic classes (e.g. `typing.Generic[T]`) '
143 'for pydantic generics to work properly.'
144 ),
145 stacklevel=2,
146 )
148 cls.__pydantic_custom_init__ = not getattr(cls.__init__, '__pydantic_base_init__', False) 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
149 cls.__pydantic_post_init__ = ( 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
150 None if cls.model_post_init is BaseModel_.model_post_init else 'model_post_init'
151 )
153 cls.__pydantic_setattr_handlers__ = {} 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
155 cls.__pydantic_decorators__ = DecoratorInfos.build(cls) 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
156 cls.__pydantic_decorators__.update_from_config(config_wrapper) 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
158 # Use the getattr below to grab the __parameters__ from the `typing.Generic` parent class
159 if __pydantic_generic_metadata__: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
160 cls.__pydantic_generic_metadata__ = __pydantic_generic_metadata__ 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
161 else:
162 parent_parameters = getattr(cls, '__pydantic_generic_metadata__', {}).get('parameters', ()) 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
163 parameters = getattr(cls, '__parameters__', None) or parent_parameters 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
164 if parameters and parent_parameters and not all(x in parameters for x in parent_parameters): 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
165 from ..root_model import RootModelRootType 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
167 missing_parameters = tuple(x for x in parameters if x not in parent_parameters) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
168 if RootModelRootType in parent_parameters and RootModelRootType not in parameters: 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
169 # This is a special case where the user has subclassed `RootModel`, but has not parametrized
170 # RootModel with the generic type identifiers being used. Ex:
171 # class MyModel(RootModel, Generic[T]):
172 # root: T
173 # Should instead just be:
174 # class MyModel(RootModel[T]):
175 # root: T
176 parameters_str = ', '.join([x.__name__ for x in missing_parameters]) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
177 error_message = ( 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
178 f'{cls.__name__} is a subclass of `RootModel`, but does not include the generic type identifier(s) '
179 f'{parameters_str} in its parameters. '
180 f'You should parametrize RootModel directly, e.g., `class {cls.__name__}(RootModel[{parameters_str}]): ...`.'
181 )
182 else:
183 combined_parameters = parent_parameters + missing_parameters 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
184 parameters_str = ', '.join([str(x) for x in combined_parameters]) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
185 generic_type_label = f'typing.Generic[{parameters_str}]' 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
186 error_message = ( 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
187 f'All parameters must be present on typing.Generic;'
188 f' you should inherit from {generic_type_label}.'
189 )
190 if Generic not in bases: # pragma: no cover 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
191 # We raise an error here not because it is desirable, but because some cases are mishandled.
192 # It would be nice to remove this error and still have things behave as expected, it's just
193 # challenging because we are using a custom `__class_getitem__` to parametrize generic models,
194 # and not returning a typing._GenericAlias from it.
195 bases_str = ', '.join([x.__name__ for x in bases] + [generic_type_label]) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
196 error_message += ( 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
197 f' Note: `typing.Generic` must go last: `class {cls.__name__}({bases_str}): ...`)'
198 )
199 raise TypeError(error_message) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
201 cls.__pydantic_generic_metadata__ = { 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
202 'origin': None,
203 'args': (),
204 'parameters': parameters,
205 }
207 cls.__pydantic_complete__ = False # Ensure this specific class gets completed 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
209 # preserve `__set_name__` protocol defined in https://peps.python.org/pep-0487
210 # for attributes not in `new_namespace` (e.g. private attributes)
211 for name, obj in private_attributes.items(): 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
212 obj.__set_name__(cls, name) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
214 if __pydantic_reset_parent_namespace__: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
215 cls.__pydantic_parent_namespace__ = build_lenient_weakvaluedict(parent_frame_namespace()) 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
216 parent_namespace: dict[str, Any] | None = getattr(cls, '__pydantic_parent_namespace__', None) 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
217 if isinstance(parent_namespace, dict): 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
218 parent_namespace = unpack_lenient_weakvaluedict(parent_namespace) 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
220 ns_resolver = NsResolver(parent_namespace=parent_namespace) 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
222 set_model_fields(cls, config_wrapper=config_wrapper, ns_resolver=ns_resolver) 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
224 # This is also set in `complete_model_class()`, after schema gen because they are recreated.
225 # We set them here as well for backwards compatibility:
226 cls.__pydantic_computed_fields__ = { 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
227 k: v.info for k, v in cls.__pydantic_decorators__.computed_fields.items()
228 }
230 if config_wrapper.defer_build: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
231 set_model_mocks(cls) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
232 else:
233 # Any operation that requires accessing the field infos instances should be put inside
234 # `complete_model_class()`:
235 complete_model_class( 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
236 cls,
237 config_wrapper,
238 ns_resolver,
239 raise_errors=False,
240 create_model_module=_create_model_module,
241 )
243 if config_wrapper.frozen and '__hash__' not in namespace: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
244 set_default_hash_func(cls, bases) 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
246 # using super(cls, cls) on the next line ensures we only call the parent class's __pydantic_init_subclass__
247 # I believe the `type: ignore` is only necessary because mypy doesn't realize that this code branch is
248 # only hit for _proper_ subclasses of BaseModel
249 super(cls, cls).__pydantic_init_subclass__(**kwargs) # type: ignore[misc] 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
250 return cls 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
251 else:
252 # These are instance variables, but have been assigned to `NoInitField` to trick the type checker.
253 for instance_slot in '__pydantic_fields_set__', '__pydantic_extra__', '__pydantic_private__': 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
254 namespace.pop( 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
255 instance_slot,
256 None, # In case the metaclass is used with a class other than `BaseModel`.
257 )
258 namespace.get('__annotations__', {}).clear() 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
259 return super().__new__(mcs, cls_name, bases, namespace, **kwargs) 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
261 if not typing.TYPE_CHECKING: # pragma: no branch 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
262 # We put `__getattr__` in a non-TYPE_CHECKING block because otherwise, mypy allows arbitrary attribute access
264 def __getattr__(self, item: str) -> Any: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
265 """This is necessary to keep attribute access working for class attribute access."""
266 private_attributes = self.__dict__.get('__private_attributes__') 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
267 if private_attributes and item in private_attributes: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
268 return private_attributes[item] 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
269 raise AttributeError(item) 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
271 @classmethod 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
272 def __prepare__(cls, *args: Any, **kwargs: Any) -> dict[str, object]: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
273 return _ModelNamespaceDict() 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
275 def __instancecheck__(self, instance: Any) -> bool: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
276 """Avoid calling ABC _abc_instancecheck unless we're pretty sure.
278 See #3829 and python/cpython#92810
279 """
280 return hasattr(instance, '__pydantic_decorators__') and super().__instancecheck__(instance) 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
282 def __subclasscheck__(self, subclass: type[Any]) -> bool: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
283 """Avoid calling ABC _abc_subclasscheck unless we're pretty sure.
285 See #3829 and python/cpython#92810
286 """
287 return hasattr(subclass, '__pydantic_decorators__') and super().__subclasscheck__(subclass) 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
289 @staticmethod 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
290 def _collect_bases_data(bases: tuple[type[Any], ...]) -> tuple[set[str], set[str], dict[str, ModelPrivateAttr]]: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
291 BaseModel = import_cached_base_model() 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
293 field_names: set[str] = set() 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
294 class_vars: set[str] = set() 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
295 private_attributes: dict[str, ModelPrivateAttr] = {} 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
296 for base in bases: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
297 if issubclass(base, BaseModel) and base is not BaseModel: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
298 # model_fields might not be defined yet in the case of generics, so we use getattr here:
299 field_names.update(getattr(base, '__pydantic_fields__', {}).keys()) 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
300 class_vars.update(base.__class_vars__) 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
301 private_attributes.update(base.__private_attributes__) 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
302 return field_names, class_vars, private_attributes 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
304 @property 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
305 @deprecated('The `__fields__` attribute is deprecated, use `model_fields` instead.', category=None) 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
306 def __fields__(self) -> dict[str, FieldInfo]: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
307 warnings.warn( 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
308 'The `__fields__` attribute is deprecated, use `model_fields` instead.',
309 PydanticDeprecatedSince20,
310 stacklevel=2,
311 )
312 return getattr(self, '__pydantic_fields__', {}) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
314 @property 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
315 def __pydantic_fields_complete__(self) -> bool: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
316 """Whether the fields where successfully collected (i.e. type hints were successfully resolves).
318 This is a private attribute, not meant to be used outside Pydantic.
319 """
320 if not hasattr(self, '__pydantic_fields__'): 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
321 return False 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
323 field_infos = cast('dict[str, FieldInfo]', self.__pydantic_fields__) # pyright: ignore[reportAttributeAccessIssue] 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
325 return all(field_info._complete for field_info in field_infos.values()) 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
327 def __dir__(self) -> list[str]: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
328 attributes = list(super().__dir__()) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
329 if '__fields__' in attributes: 329 ↛ 331line 329 didn't jump to line 331 because the condition on line 329 was always true1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
330 attributes.remove('__fields__') 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
331 return attributes 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
334def init_private_attributes(self: BaseModel, context: Any, /) -> None: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
335 """This function is meant to behave like a BaseModel method to initialise private attributes.
337 It takes context as an argument since that's what pydantic-core passes when calling it.
339 Args:
340 self: The BaseModel instance.
341 context: The context.
342 """
343 if getattr(self, '__pydantic_private__', None) is None: 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
344 pydantic_private = {} 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
345 for name, private_attr in self.__private_attributes__.items(): 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
346 default = private_attr.get_default() 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
347 if default is not PydanticUndefined: 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
348 pydantic_private[name] = default 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
349 object_setattr(self, '__pydantic_private__', pydantic_private) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
352def get_model_post_init(namespace: dict[str, Any], bases: tuple[type[Any], ...]) -> Callable[..., Any] | None: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
353 """Get the `model_post_init` method from the namespace or the class bases, or `None` if not defined."""
354 if 'model_post_init' in namespace: 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
355 return namespace['model_post_init'] 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
357 BaseModel = import_cached_base_model() 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
359 model_post_init = get_attribute_from_bases(bases, 'model_post_init') 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
360 if model_post_init is not BaseModel.model_post_init: 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
361 return model_post_init 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
364def inspect_namespace( # noqa C901 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
365 namespace: dict[str, Any],
366 ignored_types: tuple[type[Any], ...],
367 base_class_vars: set[str],
368 base_class_fields: set[str],
369) -> dict[str, ModelPrivateAttr]:
370 """Iterate over the namespace and:
371 * gather private attributes
372 * check for items which look like fields but are not (e.g. have no annotation) and warn.
374 Args:
375 namespace: The attribute dictionary of the class to be created.
376 ignored_types: A tuple of ignore types.
377 base_class_vars: A set of base class class variables.
378 base_class_fields: A set of base class fields.
380 Returns:
381 A dict contains private attributes info.
383 Raises:
384 TypeError: If there is a `__root__` field in model.
385 NameError: If private attribute name is invalid.
386 PydanticUserError:
387 - If a field does not have a type annotation.
388 - If a field on base class was overridden by a non-annotated attribute.
389 """
390 from ..fields import ModelPrivateAttr, PrivateAttr 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
392 FieldInfo = import_cached_field_info() 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
394 all_ignored_types = ignored_types + default_ignored_types() 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
396 private_attributes: dict[str, ModelPrivateAttr] = {} 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
397 raw_annotations = namespace.get('__annotations__', {}) 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
399 if '__root__' in raw_annotations or '__root__' in namespace: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
400 raise TypeError("To define root models, use `pydantic.RootModel` rather than a field called '__root__'") 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
402 ignored_names: set[str] = set() 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
403 for var_name, value in list(namespace.items()): 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
404 if var_name == 'model_config' or var_name == '__pydantic_extra__': 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
405 continue 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
406 elif ( 1adeofpghbijsktclmwnx
407 isinstance(value, type)
408 and value.__module__ == namespace['__module__']
409 and '__qualname__' in namespace
410 and value.__qualname__.startswith(f'{namespace["__qualname__"]}.')
411 ):
412 # `value` is a nested type defined in this namespace; don't error
413 continue 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
414 elif isinstance(value, all_ignored_types) or value.__class__.__module__ == 'functools': 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
415 ignored_names.add(var_name) 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
416 continue 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
417 elif isinstance(value, ModelPrivateAttr): 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
418 if var_name.startswith('__'): 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
419 raise NameError( 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
420 'Private attributes must not use dunder names;'
421 f' use a single underscore prefix instead of {var_name!r}.'
422 )
423 elif is_valid_field_name(var_name): 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
424 raise NameError( 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
425 'Private attributes must not use valid field names;'
426 f' use sunder names, e.g. {"_" + var_name!r} instead of {var_name!r}.'
427 )
428 private_attributes[var_name] = value 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
429 del namespace[var_name] 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
430 elif isinstance(value, FieldInfo) and not is_valid_field_name(var_name): 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
431 suggested_name = var_name.lstrip('_') or 'my_field' # don't suggest '' for all-underscore name 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
432 raise NameError( 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
433 f'Fields must not use names with leading underscores;'
434 f' e.g., use {suggested_name!r} instead of {var_name!r}.'
435 )
437 elif var_name.startswith('__'): 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
438 continue 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
439 elif is_valid_privateattr_name(var_name): 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
440 if var_name not in raw_annotations or not is_classvar_annotation(raw_annotations[var_name]): 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
441 private_attributes[var_name] = cast(ModelPrivateAttr, PrivateAttr(default=value)) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
442 del namespace[var_name] 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
443 elif var_name in base_class_vars: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
444 continue 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
445 elif var_name not in raw_annotations: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
446 if var_name in base_class_fields: 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
447 raise PydanticUserError( 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
448 f'Field {var_name!r} defined on a base class was overridden by a non-annotated attribute. '
449 f'All field definitions, including overrides, require a type annotation.',
450 code='model-field-overridden',
451 )
452 elif isinstance(value, FieldInfo): 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
453 raise PydanticUserError( 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
454 f'Field {var_name!r} requires a type annotation', code='model-field-missing-annotation'
455 )
456 else:
457 raise PydanticUserError( 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
458 f'A non-annotated attribute was detected: `{var_name} = {value!r}`. All model fields require a '
459 f'type annotation; if `{var_name}` is not meant to be a field, you may be able to resolve this '
460 f"error by annotating it as a `ClassVar` or updating `model_config['ignored_types']`.",
461 code='model-field-missing-annotation',
462 )
464 for ann_name, ann_type in raw_annotations.items(): 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
465 if ( 1adeofpghbijsktclmwnx
466 is_valid_privateattr_name(ann_name)
467 and ann_name not in private_attributes
468 and ann_name not in ignored_names
469 # This condition can be a false negative when `ann_type` is stringified,
470 # but it is handled in most cases in `set_model_fields`:
471 and not is_classvar_annotation(ann_type)
472 and ann_type not in all_ignored_types
473 and getattr(ann_type, '__module__', None) != 'functools'
474 ):
475 if isinstance(ann_type, str): 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
476 # Walking up the frames to get the module namespace where the model is defined
477 # (as the model class wasn't created yet, we unfortunately can't use `cls.__module__`):
478 frame = sys._getframe(2) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
479 if frame is not None: 479 ↛ 489line 479 didn't jump to line 489 because the condition on line 479 was always true1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
480 try: 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
481 ann_type = eval_type_backport( 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
482 _make_forward_ref(ann_type, is_argument=False, is_class=True),
483 globalns=frame.f_globals,
484 localns=frame.f_locals,
485 )
486 except (NameError, TypeError): 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
487 pass 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
489 if typing_objects.is_annotated(get_origin(ann_type)): 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
490 _, *metadata = get_args(ann_type) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
491 private_attr = next((v for v in metadata if isinstance(v, ModelPrivateAttr)), None) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
492 if private_attr is not None: 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
493 private_attributes[ann_name] = private_attr 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
494 continue 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
495 private_attributes[ann_name] = PrivateAttr() 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
497 return private_attributes 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
500def set_default_hash_func(cls: type[BaseModel], bases: tuple[type[Any], ...]) -> None: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
501 base_hash_func = get_attribute_from_bases(bases, '__hash__') 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
502 new_hash_func = make_hash_func(cls) 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
503 if base_hash_func in {None, object.__hash__} or getattr(base_hash_func, '__code__', None) == new_hash_func.__code__: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
504 # If `__hash__` is some default, we generate a hash function.
505 # It will be `None` if not overridden from BaseModel.
506 # It may be `object.__hash__` if there is another
507 # parent class earlier in the bases which doesn't override `__hash__` (e.g. `typing.Generic`).
508 # It may be a value set by `set_default_hash_func` if `cls` is a subclass of another frozen model.
509 # In the last case we still need a new hash function to account for new `model_fields`.
510 cls.__hash__ = new_hash_func 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
513def make_hash_func(cls: type[BaseModel]) -> Any: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
514 getter = operator.itemgetter(*cls.__pydantic_fields__.keys()) if cls.__pydantic_fields__ else lambda _: 0 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
516 def hash_func(self: Any) -> int: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
517 try: 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
518 return hash(getter(self.__dict__)) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
519 except KeyError: 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
520 # In rare cases (such as when using the deprecated copy method), the __dict__ may not contain
521 # all model fields, which is how we can get here.
522 # getter(self.__dict__) is much faster than any 'safe' method that accounts for missing keys,
523 # and wrapping it in a `try` doesn't slow things down much in the common case.
524 return hash(getter(SafeGetItemProxy(self.__dict__))) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
526 return hash_func 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
529def set_model_fields( 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
530 cls: type[BaseModel],
531 config_wrapper: ConfigWrapper,
532 ns_resolver: NsResolver | None,
533) -> None:
534 """Collect and set `cls.__pydantic_fields__` and `cls.__class_vars__`.
536 Args:
537 cls: BaseModel or dataclass.
538 config_wrapper: The config wrapper instance.
539 ns_resolver: Namespace resolver to use when getting model annotations.
540 """
541 typevars_map = get_model_typevars_map(cls) 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
542 fields, class_vars = collect_model_fields(cls, config_wrapper, ns_resolver, typevars_map=typevars_map) 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
544 cls.__pydantic_fields__ = fields 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
545 cls.__class_vars__.update(class_vars) 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
547 for k in class_vars: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
548 # Class vars should not be private attributes
549 # We remove them _here_ and not earlier because we rely on inspecting the class to determine its classvars,
550 # but private attributes are determined by inspecting the namespace _prior_ to class creation.
551 # In the case that a classvar with a leading-'_' is defined via a ForwardRef (e.g., when using
552 # `__future__.annotations`), we want to remove the private attribute which was detected _before_ we knew it
553 # evaluated to a classvar
555 value = cls.__private_attributes__.pop(k, None) 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
556 if value is not None and value.default is not PydanticUndefined: 556 ↛ 557line 556 didn't jump to line 557 because the condition on line 556 was never true1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
557 setattr(cls, k, value.default)
560def complete_model_class( 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
561 cls: type[BaseModel],
562 config_wrapper: ConfigWrapper,
563 ns_resolver: NsResolver,
564 *,
565 raise_errors: bool = True,
566 call_on_complete_hook: bool = True,
567 create_model_module: str | None = None,
568) -> bool:
569 """Finish building a model class.
571 This logic must be called after class has been created since validation functions must be bound
572 and `get_type_hints` requires a class object.
574 Args:
575 cls: BaseModel or dataclass.
576 config_wrapper: The config wrapper instance.
577 ns_resolver: The namespace resolver instance to use during schema building.
578 raise_errors: Whether to raise errors.
579 call_on_complete_hook: Whether to call the `__pydantic_on_complete__` hook.
580 create_model_module: The module of the class to be created, if created by `create_model`.
582 Returns:
583 `True` if the model is successfully completed, else `False`.
585 Raises:
586 PydanticUndefinedAnnotation: If `PydanticUndefinedAnnotation` occurs in`__get_pydantic_core_schema__`
587 and `raise_errors=True`.
588 """
589 typevars_map = get_model_typevars_map(cls) 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
591 if not cls.__pydantic_fields_complete__: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
592 # Note: when coming from `ModelMetaclass.__new__()`, this results in fields being built twice.
593 # We do so a second time here so that we can get the `NameError` for the specific undefined annotation.
594 # Alternatively, we could let `GenerateSchema()` raise the error, but there are cases where incomplete
595 # fields are inherited in `collect_model_fields()` and can actually have their annotation resolved in the
596 # generate schema process. As we want to avoid having `__pydantic_fields_complete__` set to `False`
597 # when `__pydantic_complete__` is `True`, we rebuild here:
598 try: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
599 cls.__pydantic_fields__ = rebuild_model_fields( 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
600 cls,
601 config_wrapper=config_wrapper,
602 ns_resolver=ns_resolver,
603 typevars_map=typevars_map,
604 )
605 except NameError as e: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
606 exc = PydanticUndefinedAnnotation.from_name_error(e) 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
607 set_model_mocks(cls, f'`{exc.name}`') 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
608 if raise_errors: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
609 raise exc from e 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
611 if not raise_errors and not cls.__pydantic_fields_complete__: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
612 # No need to continue with schema gen, it is guaranteed to fail
613 return False 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
615 assert cls.__pydantic_fields_complete__ 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
617 gen_schema = GenerateSchema( 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
618 config_wrapper,
619 ns_resolver,
620 typevars_map,
621 )
623 try: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
624 schema = gen_schema.generate_schema(cls) 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
625 except PydanticUndefinedAnnotation as e: 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
626 if raise_errors: 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
627 raise 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
628 set_model_mocks(cls, f'`{e.name}`') 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
629 return False 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
631 core_config = config_wrapper.core_config(title=cls.__name__) 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
633 try: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
634 schema = gen_schema.clean_schema(schema) 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
635 except InvalidSchemaError: 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
636 set_model_mocks(cls) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
637 return False 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
639 # This needs to happen *after* model schema generation, as the return type
640 # of the properties are evaluated and the `ComputedFieldInfo` are recreated:
641 cls.__pydantic_computed_fields__ = {k: v.info for k, v in cls.__pydantic_decorators__.computed_fields.items()} 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
643 set_deprecated_descriptors(cls) 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
645 cls.__pydantic_core_schema__ = schema 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
647 cls.__pydantic_validator__ = create_schema_validator( 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
648 schema,
649 cls,
650 create_model_module or cls.__module__,
651 cls.__qualname__,
652 'create_model' if create_model_module else 'BaseModel',
653 core_config,
654 config_wrapper.plugin_settings,
655 )
656 cls.__pydantic_serializer__ = SchemaSerializer(schema, core_config) 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
658 # set __signature__ attr only for model class, but not for its instances
659 # (because instances can define `__call__`, and `inspect.signature` shouldn't
660 # use the `__signature__` attribute and instead generate from `__call__`).
661 cls.__signature__ = LazyClassAttribute( 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
662 '__signature__',
663 partial(
664 generate_pydantic_signature,
665 init=cls.__init__,
666 fields=cls.__pydantic_fields__,
667 validate_by_name=config_wrapper.validate_by_name,
668 extra=config_wrapper.extra,
669 ),
670 )
672 cls.__pydantic_complete__ = True 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
674 if call_on_complete_hook: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
675 cls.__pydantic_on_complete__() 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
677 return True 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
680def set_deprecated_descriptors(cls: type[BaseModel]) -> None: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
681 """Set data descriptors on the class for deprecated fields."""
682 for field, field_info in cls.__pydantic_fields__.items(): 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
683 if (msg := field_info.deprecation_message) is not None: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
684 desc = _DeprecatedFieldDescriptor(msg) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
685 desc.__set_name__(cls, field) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
686 setattr(cls, field, desc) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
688 for field, computed_field_info in cls.__pydantic_computed_fields__.items(): 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
689 if ( 1adghbicl
690 (msg := computed_field_info.deprecation_message) is not None
691 # Avoid having two warnings emitted:
692 and not hasattr(unwrap_wrapped_function(computed_field_info.wrapped_property), '__deprecated__')
693 ):
694 desc = _DeprecatedFieldDescriptor(msg, computed_field_info.wrapped_property) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
695 desc.__set_name__(cls, field) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
696 setattr(cls, field, desc) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
699class _DeprecatedFieldDescriptor: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
700 """Read-only data descriptor used to emit a runtime deprecation warning before accessing a deprecated field.
702 Attributes:
703 msg: The deprecation message to be emitted.
704 wrapped_property: The property instance if the deprecated field is a computed field, or `None`.
705 field_name: The name of the field being deprecated.
706 """
708 field_name: str 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
710 def __init__(self, msg: str, wrapped_property: property | None = None) -> None: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
711 self.msg = msg 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
712 self.wrapped_property = wrapped_property 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
714 def __set_name__(self, cls: type[BaseModel], name: str) -> None: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
715 self.field_name = name 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
717 def __get__(self, obj: BaseModel | None, obj_type: type[BaseModel] | None = None) -> Any: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
718 if obj is None: 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
719 if self.wrapped_property is not None: 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
720 return self.wrapped_property.__get__(None, obj_type) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
721 raise AttributeError(self.field_name) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
723 warnings.warn(self.msg, builtins.DeprecationWarning, stacklevel=2) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
725 if self.wrapped_property is not None: 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
726 return self.wrapped_property.__get__(obj, obj_type) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
727 return obj.__dict__[self.field_name] 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
729 # Defined to make it a data descriptor and take precedence over the instance's dictionary.
730 # Note that it will not be called when setting a value on a model instance
731 # as `BaseModel.__setattr__` is defined and takes priority.
732 def __set__(self, obj: Any, value: Any) -> NoReturn: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
733 raise AttributeError(self.field_name)
736class _PydanticWeakRef: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
737 """Wrapper for `weakref.ref` that enables `pickle` serialization.
739 Cloudpickle fails to serialize `weakref.ref` objects due to an arcane error related
740 to abstract base classes (`abc.ABC`). This class works around the issue by wrapping
741 `weakref.ref` instead of subclassing it.
743 See https://github.com/pydantic/pydantic/issues/6763 for context.
745 Semantics:
746 - If not pickled, behaves the same as a `weakref.ref`.
747 - If pickled along with the referenced object, the same `weakref.ref` behavior
748 will be maintained between them after unpickling.
749 - If pickled without the referenced object, after unpickling the underlying
750 reference will be cleared (`__call__` will always return `None`).
751 """
753 def __init__(self, obj: Any): 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
754 if obj is None: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
755 # The object will be `None` upon deserialization if the serialized weakref
756 # had lost its underlying object.
757 self._wr = None 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
758 else:
759 self._wr = weakref.ref(obj) 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
761 def __call__(self) -> Any: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
762 if self._wr is None: 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
763 return None 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
764 else:
765 return self._wr() 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
767 def __reduce__(self) -> tuple[Callable, tuple[weakref.ReferenceType | None]]: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
768 return _PydanticWeakRef, (self(),) 1aefqrghbjkuvcmnyz
771def build_lenient_weakvaluedict(d: dict[str, Any] | None) -> dict[str, Any] | None: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
772 """Takes an input dictionary, and produces a new value that (invertibly) replaces the values with weakrefs.
774 We can't just use a WeakValueDictionary because many types (including int, str, etc.) can't be stored as values
775 in a WeakValueDictionary.
777 The `unpack_lenient_weakvaluedict` function can be used to reverse this operation.
778 """
779 if d is None: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
780 return None 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
781 result = {} 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
782 for k, v in d.items(): 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
783 try: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
784 proxy = _PydanticWeakRef(v) 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
785 except TypeError: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
786 proxy = v 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
787 result[k] = proxy 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
788 return result 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
791def unpack_lenient_weakvaluedict(d: dict[str, Any] | None) -> dict[str, Any] | None: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
792 """Inverts the transform performed by `build_lenient_weakvaluedict`."""
793 if d is None: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
794 return None 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
796 result = {} 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
797 for k, v in d.items(): 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
798 if isinstance(v, _PydanticWeakRef): 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
799 v = v() 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
800 if v is not None: 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
801 result[k] = v 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI
802 else:
803 result[k] = v 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
804 return result 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
807@cache 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
808def default_ignored_types() -> tuple[type[Any], ...]: 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
809 from ..fields import ComputedFieldInfo 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
811 ignored_types = [ 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
812 FunctionType,
813 property,
814 classmethod,
815 staticmethod,
816 PydanticDescriptorProxy,
817 ComputedFieldInfo,
818 TypeAliasType, # from `typing_extensions`
819 ]
821 if sys.version_info >= (3, 12): 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI
822 ignored_types.append(typing.TypeAliasType) 1qArBCuDvEFJyGzHI
824 return tuple(ignored_types) 1adeofpqArBCghbijsktuDvEFJclmwnxyGzHI