Coverage for pydantic/_internal/_model_construction.py: 98.93%
333 statements
« prev ^ index » next coverage.py v7.6.12, created at 2025-02-13 19:35 +0000
« prev ^ index » next coverage.py v7.6.12, created at 2025-02-13 19:35 +0000
1"""Private logic for creating models."""
3from __future__ import annotations as _annotations 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
5import builtins 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
6import operator 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
7import sys 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
8import typing 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
9import warnings 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
10import weakref 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
11from abc import ABCMeta 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
12from functools import cache, partial, wraps 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
13from types import FunctionType 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
14from typing import Any, Callable, Generic, Literal, NoReturn, cast 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
16from pydantic_core import PydanticUndefined, SchemaSerializer 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
17from typing_extensions import TypeAliasType, dataclass_transform, deprecated, get_args 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
19from ..errors import PydanticUndefinedAnnotation, PydanticUserError 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
20from ..plugin._schema_validator import create_schema_validator 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
21from ..warnings import GenericBeforeBaseModelWarning, PydanticDeprecatedSince20 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
22from ._config import ConfigWrapper 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
23from ._decorators import DecoratorInfos, PydanticDescriptorProxy, get_attribute_from_bases, unwrap_wrapped_function 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
24from ._fields import collect_model_fields, is_valid_field_name, is_valid_privateattr_name 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
25from ._generate_schema import GenerateSchema, InvalidSchemaError 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
26from ._generics import PydanticGenericMetadata, get_model_typevars_map 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
27from ._import_utils import import_cached_base_model, import_cached_field_info 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
28from ._mock_val_ser import set_model_mocks 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
29from ._namespace_utils import NsResolver 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
30from ._signature import generate_pydantic_signature 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
31from ._typing_extra import ( 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
32 _make_forward_ref,
33 eval_type_backport,
34 is_annotated,
35 is_classvar_annotation,
36 parent_frame_namespace,
37)
38from ._utils import LazyClassAttribute, SafeGetItemProxy 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
40if typing.TYPE_CHECKING: 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
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 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
49 PydanticModelField = object() 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
50 PydanticModelPrivateAttr = object() 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
52object_setattr = object.__setattr__ 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
55class _ModelNamespaceDict(dict): 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
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: 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
61 existing: Any = self.get(k, None) 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
62 if existing and v is not existing and isinstance(existing, PydanticDescriptorProxy): 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
63 warnings.warn(f'`{k}` overrides an existing Pydantic `{existing.decorator_info.decorator_repr}` decorator') 1adeofpqArBghbijsktuCvDclmwnxyEzF
65 return super().__setitem__(k, v) 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
68def NoInitField( 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
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)) 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
79class ModelMetaclass(ABCMeta): 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
80 def __new__( 1adeofpqArBbijsktuCvDGHIJKLMclmwnxyEzF
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: 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
108 base_field_names, class_vars, base_private_attributes = mcs._collect_bases_data(bases) 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
110 config_wrapper = ConfigWrapper.for_model(bases, namespace, kwargs) 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
111 namespace['model_config'] = config_wrapper.config_dict 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
112 private_attributes = inspect_namespace( 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
113 namespace, config_wrapper.ignored_types, class_vars, base_field_names
114 )
115 if private_attributes or base_private_attributes: 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
116 original_model_post_init = get_model_post_init(namespace, bases) 1adeofpqArBghbijsktuCvDclmwnxyEzF
117 if original_model_post_init is not None: 1adeofpqArBghbijsktuCvDclmwnxyEzF
118 # if there are private_attributes and a model_post_init function, we handle both
120 @wraps(original_model_post_init) 1adeofpqArBghbijsktuCvDclmwnxyEzF
121 def wrapped_model_post_init(self: BaseModel, context: Any, /) -> None: 1adeofpqArBghbijsktuCvDclmwnxyEzF
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) 1adeofpqArBghbijsktuCvDclmwnxyEzF
126 original_model_post_init(self, context) 1adeofpqArBghbijsktuCvDclmwnxyEzF
128 namespace['model_post_init'] = wrapped_model_post_init 1adeofpqArBghbijsktuCvDclmwnxyEzF
129 else:
130 namespace['model_post_init'] = init_private_attributes 1adeofpqArBghbijsktuCvDclmwnxyEzF
132 namespace['__class_vars__'] = class_vars 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
133 namespace['__private_attributes__'] = {**base_private_attributes, **private_attributes} 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
135 cls = cast('type[BaseModel]', super().__new__(mcs, cls_name, bases, namespace, **kwargs)) 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
136 BaseModel_ = import_cached_base_model() 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
138 mro = cls.__mro__ 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
139 if Generic in mro and mro.index(Generic) < mro.index(BaseModel_): 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
140 warnings.warn( 1adeofpqArBghbijsktuCvDclmwnxyEzF
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) 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
149 cls.__pydantic_post_init__ = ( 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
150 None if cls.model_post_init is BaseModel_.model_post_init else 'model_post_init'
151 )
153 cls.__pydantic_setattr_handlers__ = {} 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
155 cls.__pydantic_decorators__ = DecoratorInfos.build(cls) 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
157 # Use the getattr below to grab the __parameters__ from the `typing.Generic` parent class
158 if __pydantic_generic_metadata__: 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
159 cls.__pydantic_generic_metadata__ = __pydantic_generic_metadata__ 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
160 else:
161 parent_parameters = getattr(cls, '__pydantic_generic_metadata__', {}).get('parameters', ()) 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
162 parameters = getattr(cls, '__parameters__', None) or parent_parameters 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
163 if parameters and parent_parameters and not all(x in parameters for x in parent_parameters): 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
164 from ..root_model import RootModelRootType 1adeofpqArBghbijsktuCvDclmwnxyEzF
166 missing_parameters = tuple(x for x in parameters if x not in parent_parameters) 1adeofpqArBghbijsktuCvDclmwnxyEzF
167 if RootModelRootType in parent_parameters and RootModelRootType not in parameters: 1adeofpqArBghbijsktuCvDclmwnxyEzF
168 # This is a special case where the user has subclassed `RootModel`, but has not parametrized
169 # RootModel with the generic type identifiers being used. Ex:
170 # class MyModel(RootModel, Generic[T]):
171 # root: T
172 # Should instead just be:
173 # class MyModel(RootModel[T]):
174 # root: T
175 parameters_str = ', '.join([x.__name__ for x in missing_parameters]) 1adeofpqArBghbijsktuCvDclmwnxyEzF
176 error_message = ( 1adeofpqArBghbijsktuCvDclmwnxyEzF
177 f'{cls.__name__} is a subclass of `RootModel`, but does not include the generic type identifier(s) '
178 f'{parameters_str} in its parameters. '
179 f'You should parametrize RootModel directly, e.g., `class {cls.__name__}(RootModel[{parameters_str}]): ...`.'
180 )
181 else:
182 combined_parameters = parent_parameters + missing_parameters 1adeofpqArBghbijsktuCvDclmwnxyEzF
183 parameters_str = ', '.join([str(x) for x in combined_parameters]) 1adeofpqArBghbijsktuCvDclmwnxyEzF
184 generic_type_label = f'typing.Generic[{parameters_str}]' 1adeofpqArBghbijsktuCvDclmwnxyEzF
185 error_message = ( 1adeofpqArBghbijsktuCvDclmwnxyEzF
186 f'All parameters must be present on typing.Generic;'
187 f' you should inherit from {generic_type_label}.'
188 )
189 if Generic not in bases: # pragma: no cover 1adeofpqArBghbijsktuCvDclmwnxyEzF
190 # We raise an error here not because it is desirable, but because some cases are mishandled.
191 # It would be nice to remove this error and still have things behave as expected, it's just
192 # challenging because we are using a custom `__class_getitem__` to parametrize generic models,
193 # and not returning a typing._GenericAlias from it.
194 bases_str = ', '.join([x.__name__ for x in bases] + [generic_type_label]) 1adeofpqArBghbijsktuCvDclmwnxyEzF
195 error_message += ( 1adeofpqArBghbijsktuCvDclmwnxyEzF
196 f' Note: `typing.Generic` must go last: `class {cls.__name__}({bases_str}): ...`)'
197 )
198 raise TypeError(error_message) 1adeofpqArBghbijsktuCvDclmwnxyEzF
200 cls.__pydantic_generic_metadata__ = { 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
201 'origin': None,
202 'args': (),
203 'parameters': parameters,
204 }
206 cls.__pydantic_complete__ = False # Ensure this specific class gets completed 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
208 # preserve `__set_name__` protocol defined in https://peps.python.org/pep-0487
209 # for attributes not in `new_namespace` (e.g. private attributes)
210 for name, obj in private_attributes.items(): 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
211 obj.__set_name__(cls, name) 1adeofpqArBghbijsktuCvDclmwnxyEzF
213 if __pydantic_reset_parent_namespace__: 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
214 cls.__pydantic_parent_namespace__ = build_lenient_weakvaluedict(parent_frame_namespace()) 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
215 parent_namespace: dict[str, Any] | None = getattr(cls, '__pydantic_parent_namespace__', None) 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
216 if isinstance(parent_namespace, dict): 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
217 parent_namespace = unpack_lenient_weakvaluedict(parent_namespace) 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
219 ns_resolver = NsResolver(parent_namespace=parent_namespace) 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
221 set_model_fields(cls, config_wrapper=config_wrapper, ns_resolver=ns_resolver) 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
223 # This is also set in `complete_model_class()`, after schema gen because they are recreated.
224 # We set them here as well for backwards compatibility:
225 cls.__pydantic_computed_fields__ = { 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
226 k: v.info for k, v in cls.__pydantic_decorators__.computed_fields.items()
227 }
229 if config_wrapper.defer_build: 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
230 # TODO we can also stop there if `__pydantic_fields_complete__` is False.
231 # However, `set_model_fields()` is currently lenient and we don't have access to the `NameError`.
232 # (which is useful as we can provide the name in the error message: `set_model_mock(cls, e.name)`)
233 set_model_mocks(cls) 1adeofpqArBghbijsktuCvDclmwnxyEzF
234 else:
235 # Any operation that requires accessing the field infos instances should be put inside
236 # `complete_model_class()`:
237 complete_model_class( 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
238 cls,
239 config_wrapper,
240 raise_errors=False,
241 ns_resolver=ns_resolver,
242 create_model_module=_create_model_module,
243 )
245 if config_wrapper.frozen and '__hash__' not in namespace: 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
246 set_default_hash_func(cls, bases) 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
248 # using super(cls, cls) on the next line ensures we only call the parent class's __pydantic_init_subclass__
249 # I believe the `type: ignore` is only necessary because mypy doesn't realize that this code branch is
250 # only hit for _proper_ subclasses of BaseModel
251 super(cls, cls).__pydantic_init_subclass__(**kwargs) # type: ignore[misc] 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
252 return cls 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
253 else:
254 # These are instance variables, but have been assigned to `NoInitField` to trick the type checker.
255 for instance_slot in '__pydantic_fields_set__', '__pydantic_extra__', '__pydantic_private__': 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
256 namespace.pop( 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
257 instance_slot,
258 None, # In case the metaclass is used with a class other than `BaseModel`.
259 )
260 namespace.get('__annotations__', {}).clear() 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
261 return super().__new__(mcs, cls_name, bases, namespace, **kwargs) 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
263 if not typing.TYPE_CHECKING: # pragma: no branch 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
264 # We put `__getattr__` in a non-TYPE_CHECKING block because otherwise, mypy allows arbitrary attribute access
266 def __getattr__(self, item: str) -> Any: 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
267 """This is necessary to keep attribute access working for class attribute access."""
268 private_attributes = self.__dict__.get('__private_attributes__') 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
269 if private_attributes and item in private_attributes: 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
270 return private_attributes[item] 1adeofpqArBghbijsktuCvDclmwnxyEzF
271 raise AttributeError(item) 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
273 @classmethod 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
274 def __prepare__(cls, *args: Any, **kwargs: Any) -> dict[str, object]: 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
275 return _ModelNamespaceDict() 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
277 def __instancecheck__(self, instance: Any) -> bool: 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
278 """Avoid calling ABC _abc_instancecheck unless we're pretty sure.
280 See #3829 and python/cpython#92810
281 """
282 return hasattr(instance, '__pydantic_decorators__') and super().__instancecheck__(instance) 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
284 def __subclasscheck__(self, subclass: type[Any]) -> bool: 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
285 """Avoid calling ABC _abc_subclasscheck unless we're pretty sure.
287 See #3829 and python/cpython#92810
288 """
289 return hasattr(subclass, '__pydantic_decorators__') and super().__subclasscheck__(subclass) 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
291 @staticmethod 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
292 def _collect_bases_data(bases: tuple[type[Any], ...]) -> tuple[set[str], set[str], dict[str, ModelPrivateAttr]]: 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
293 BaseModel = import_cached_base_model() 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
295 field_names: set[str] = set() 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
296 class_vars: set[str] = set() 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
297 private_attributes: dict[str, ModelPrivateAttr] = {} 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
298 for base in bases: 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
299 if issubclass(base, BaseModel) and base is not BaseModel: 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
300 # model_fields might not be defined yet in the case of generics, so we use getattr here:
301 field_names.update(getattr(base, '__pydantic_fields__', {}).keys()) 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
302 class_vars.update(base.__class_vars__) 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
303 private_attributes.update(base.__private_attributes__) 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
304 return field_names, class_vars, private_attributes 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
306 @property 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
307 @deprecated('The `__fields__` attribute is deprecated, use `model_fields` instead.', category=None) 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
308 def __fields__(self) -> dict[str, FieldInfo]: 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
309 warnings.warn( 1adeofpqArBghbijsktuCvDclmwnxyEzF
310 'The `__fields__` attribute is deprecated, use `model_fields` instead.',
311 PydanticDeprecatedSince20,
312 stacklevel=2,
313 )
314 return getattr(self, '__pydantic_fields__', {}) 1adeofpqArBghbijsktuCvDclmwnxyEzF
316 @property 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
317 def __pydantic_fields_complete__(self) -> bool: 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
318 """Whether the fields where successfully collected (i.e. type hints were successfully resolves).
320 This is a private attribute, not meant to be used outside Pydantic.
321 """
322 if not hasattr(self, '__pydantic_fields__'): 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
323 return False 1adeofpqArBghbijsktuCvDclmwnxyEzF
325 field_infos = cast('dict[str, FieldInfo]', self.__pydantic_fields__) # pyright: ignore[reportAttributeAccessIssue] 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
327 return all(field_info._complete for field_info in field_infos.values()) 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
329 def __dir__(self) -> list[str]: 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
330 attributes = list(super().__dir__()) 1adeofpqArBghbijsktuCvDclmwnxyEzF
331 if '__fields__' in attributes: 331 ↛ 333line 331 didn't jump to line 333 because the condition on line 331 was always true1adeofpqArBghbijsktuCvDclmwnxyEzF
332 attributes.remove('__fields__') 1adeofpqArBghbijsktuCvDclmwnxyEzF
333 return attributes 1adeofpqArBghbijsktuCvDclmwnxyEzF
336def init_private_attributes(self: BaseModel, context: Any, /) -> None: 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
337 """This function is meant to behave like a BaseModel method to initialise private attributes.
339 It takes context as an argument since that's what pydantic-core passes when calling it.
341 Args:
342 self: The BaseModel instance.
343 context: The context.
344 """
345 if getattr(self, '__pydantic_private__', None) is None: 1adeofpqArBghbijsktuCvDclmwnxyEzF
346 pydantic_private = {} 1adeofpqArBghbijsktuCvDclmwnxyEzF
347 for name, private_attr in self.__private_attributes__.items(): 1adeofpqArBghbijsktuCvDclmwnxyEzF
348 default = private_attr.get_default() 1adeofpqArBghbijsktuCvDclmwnxyEzF
349 if default is not PydanticUndefined: 1adeofpqArBghbijsktuCvDclmwnxyEzF
350 pydantic_private[name] = default 1adeofpqArBghbijsktuCvDclmwnxyEzF
351 object_setattr(self, '__pydantic_private__', pydantic_private) 1adeofpqArBghbijsktuCvDclmwnxyEzF
354def get_model_post_init(namespace: dict[str, Any], bases: tuple[type[Any], ...]) -> Callable[..., Any] | None: 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
355 """Get the `model_post_init` method from the namespace or the class bases, or `None` if not defined."""
356 if 'model_post_init' in namespace: 1adeofpqArBghbijsktuCvDclmwnxyEzF
357 return namespace['model_post_init'] 1adeofpqArBghbijsktuCvDclmwnxyEzF
359 BaseModel = import_cached_base_model() 1adeofpqArBghbijsktuCvDclmwnxyEzF
361 model_post_init = get_attribute_from_bases(bases, 'model_post_init') 1adeofpqArBghbijsktuCvDclmwnxyEzF
362 if model_post_init is not BaseModel.model_post_init: 1adeofpqArBghbijsktuCvDclmwnxyEzF
363 return model_post_init 1adeofpqArBghbijsktuCvDclmwnxyEzF
366def inspect_namespace( # noqa C901 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
367 namespace: dict[str, Any],
368 ignored_types: tuple[type[Any], ...],
369 base_class_vars: set[str],
370 base_class_fields: set[str],
371) -> dict[str, ModelPrivateAttr]:
372 """Iterate over the namespace and:
373 * gather private attributes
374 * check for items which look like fields but are not (e.g. have no annotation) and warn.
376 Args:
377 namespace: The attribute dictionary of the class to be created.
378 ignored_types: A tuple of ignore types.
379 base_class_vars: A set of base class class variables.
380 base_class_fields: A set of base class fields.
382 Returns:
383 A dict contains private attributes info.
385 Raises:
386 TypeError: If there is a `__root__` field in model.
387 NameError: If private attribute name is invalid.
388 PydanticUserError:
389 - If a field does not have a type annotation.
390 - If a field on base class was overridden by a non-annotated attribute.
391 """
392 from ..fields import ModelPrivateAttr, PrivateAttr 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
394 FieldInfo = import_cached_field_info() 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
396 all_ignored_types = ignored_types + default_ignored_types() 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
398 private_attributes: dict[str, ModelPrivateAttr] = {} 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
399 raw_annotations = namespace.get('__annotations__', {}) 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
401 if '__root__' in raw_annotations or '__root__' in namespace: 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
402 raise TypeError("To define root models, use `pydantic.RootModel` rather than a field called '__root__'") 1adeofpqArBghbijsktuCvDclmwnxyEzF
404 ignored_names: set[str] = set() 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
405 for var_name, value in list(namespace.items()): 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
406 if var_name == 'model_config' or var_name == '__pydantic_extra__': 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
407 continue 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
408 elif ( 1adeofpghbijsktGHIclmwnx
409 isinstance(value, type)
410 and value.__module__ == namespace['__module__']
411 and '__qualname__' in namespace
412 and value.__qualname__.startswith(namespace['__qualname__'])
413 ):
414 # `value` is a nested type defined in this namespace; don't error
415 continue 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
416 elif isinstance(value, all_ignored_types) or value.__class__.__module__ == 'functools': 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
417 ignored_names.add(var_name) 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
418 continue 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
419 elif isinstance(value, ModelPrivateAttr): 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
420 if var_name.startswith('__'): 1adeofpqArBghbijsktuCvDclmwnxyEzF
421 raise NameError( 1adeofpqArBghbijsktuCvDclmwnxyEzF
422 'Private attributes must not use dunder names;'
423 f' use a single underscore prefix instead of {var_name!r}.'
424 )
425 elif is_valid_field_name(var_name): 1adeofpqArBghbijsktuCvDclmwnxyEzF
426 raise NameError( 1adeofpqArBghbijsktuCvDclmwnxyEzF
427 'Private attributes must not use valid field names;'
428 f' use sunder names, e.g. {"_" + var_name!r} instead of {var_name!r}.'
429 )
430 private_attributes[var_name] = value 1adeofpqArBghbijsktuCvDclmwnxyEzF
431 del namespace[var_name] 1adeofpqArBghbijsktuCvDclmwnxyEzF
432 elif isinstance(value, FieldInfo) and not is_valid_field_name(var_name): 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
433 suggested_name = var_name.lstrip('_') or 'my_field' # don't suggest '' for all-underscore name 1adeofpqArBghbijsktuCvDclmwnxyEzF
434 raise NameError( 1adeofpqArBghbijsktuCvDclmwnxyEzF
435 f'Fields must not use names with leading underscores;'
436 f' e.g., use {suggested_name!r} instead of {var_name!r}.'
437 )
439 elif var_name.startswith('__'): 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
440 continue 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
441 elif is_valid_privateattr_name(var_name): 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
442 if var_name not in raw_annotations or not is_classvar_annotation(raw_annotations[var_name]): 1adeofpqArBghbijsktuCvDclmwnxyEzF
443 private_attributes[var_name] = cast(ModelPrivateAttr, PrivateAttr(default=value)) 1adeofpqArBghbijsktuCvDclmwnxyEzF
444 del namespace[var_name] 1adeofpqArBghbijsktuCvDclmwnxyEzF
445 elif var_name in base_class_vars: 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
446 continue 1adeofpqArBghbijsktuCvDclmwnxyEzF
447 elif var_name not in raw_annotations: 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
448 if var_name in base_class_fields: 1adeofpqArBghbijsktuCvDclmwnxyEzF
449 raise PydanticUserError( 1adeofpqArBghbijsktuCvDclmwnxyEzF
450 f'Field {var_name!r} defined on a base class was overridden by a non-annotated attribute. '
451 f'All field definitions, including overrides, require a type annotation.',
452 code='model-field-overridden',
453 )
454 elif isinstance(value, FieldInfo): 1adeofpqArBghbijsktuCvDclmwnxyEzF
455 raise PydanticUserError( 1adeofpqArBghbijsktuCvDclmwnxyEzF
456 f'Field {var_name!r} requires a type annotation', code='model-field-missing-annotation'
457 )
458 else:
459 raise PydanticUserError( 1adeofpqArBghbijsktuCvDclmwnxyEzF
460 f'A non-annotated attribute was detected: `{var_name} = {value!r}`. All model fields require a '
461 f'type annotation; if `{var_name}` is not meant to be a field, you may be able to resolve this '
462 f"error by annotating it as a `ClassVar` or updating `model_config['ignored_types']`.",
463 code='model-field-missing-annotation',
464 )
466 for ann_name, ann_type in raw_annotations.items(): 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
467 if ( 1adeofpghbijsktGHIclmwnx
468 is_valid_privateattr_name(ann_name)
469 and ann_name not in private_attributes
470 and ann_name not in ignored_names
471 # This condition can be a false negative when `ann_type` is stringified,
472 # but it is handled in most cases in `set_model_fields`:
473 and not is_classvar_annotation(ann_type)
474 and ann_type not in all_ignored_types
475 and getattr(ann_type, '__module__', None) != 'functools'
476 ):
477 if isinstance(ann_type, str): 1adeofpqArBghbijsktuCvDclmwnxyEzF
478 # Walking up the frames to get the module namespace where the model is defined
479 # (as the model class wasn't created yet, we unfortunately can't use `cls.__module__`):
480 frame = sys._getframe(2) 1adeofpqArBghbijsktuCvDclmwnxyEzF
481 if frame is not None: 481 ↛ 491line 481 didn't jump to line 491 because the condition on line 481 was always true1adeofpqArBghbijsktuCvDclmwnxyEzF
482 try: 1adeofpqArBghbijsktuCvDclmwnxyEzF
483 ann_type = eval_type_backport( 1adeofpqArBghbijsktuCvDclmwnxyEzF
484 _make_forward_ref(ann_type, is_argument=False, is_class=True),
485 globalns=frame.f_globals,
486 localns=frame.f_locals,
487 )
488 except (NameError, TypeError): 1adeofpqArBghbijsktuCvDclmwnxyEzF
489 pass 1adeofpqArBghbijsktuCvDclmwnxyEzF
491 if is_annotated(ann_type): 1adeofpqArBghbijsktuCvDclmwnxyEzF
492 _, *metadata = get_args(ann_type) 1adeofpqArBghbijsktuCvDclmwnxyEzF
493 private_attr = next((v for v in metadata if isinstance(v, ModelPrivateAttr)), None) 1adeofpqArBghbijsktuCvDclmwnxyEzF
494 if private_attr is not None: 1adeofpqArBghbijsktuCvDclmwnxyEzF
495 private_attributes[ann_name] = private_attr 1adeofpqArBghbijsktuCvDclmwnxyEzF
496 continue 1adeofpqArBghbijsktuCvDclmwnxyEzF
497 private_attributes[ann_name] = PrivateAttr() 1adeofpqArBghbijsktuCvDclmwnxyEzF
499 return private_attributes 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
502def set_default_hash_func(cls: type[BaseModel], bases: tuple[type[Any], ...]) -> None: 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
503 base_hash_func = get_attribute_from_bases(bases, '__hash__') 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
504 new_hash_func = make_hash_func(cls) 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
505 if base_hash_func in {None, object.__hash__} or getattr(base_hash_func, '__code__', None) == new_hash_func.__code__: 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
506 # If `__hash__` is some default, we generate a hash function.
507 # It will be `None` if not overridden from BaseModel.
508 # It may be `object.__hash__` if there is another
509 # parent class earlier in the bases which doesn't override `__hash__` (e.g. `typing.Generic`).
510 # It may be a value set by `set_default_hash_func` if `cls` is a subclass of another frozen model.
511 # In the last case we still need a new hash function to account for new `model_fields`.
512 cls.__hash__ = new_hash_func 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
515def make_hash_func(cls: type[BaseModel]) -> Any: 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
516 getter = operator.itemgetter(*cls.__pydantic_fields__.keys()) if cls.__pydantic_fields__ else lambda _: 0 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
518 def hash_func(self: Any) -> int: 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
519 try: 1adeofpqArBghbijsktuCvDclmwnxyEzF
520 return hash(getter(self.__dict__)) 1adeofpqArBghbijsktuCvDclmwnxyEzF
521 except KeyError: 1adeofpqArBghbijsktuCvDclmwnxyEzF
522 # In rare cases (such as when using the deprecated copy method), the __dict__ may not contain
523 # all model fields, which is how we can get here.
524 # getter(self.__dict__) is much faster than any 'safe' method that accounts for missing keys,
525 # and wrapping it in a `try` doesn't slow things down much in the common case.
526 return hash(getter(SafeGetItemProxy(self.__dict__))) 1adeofpqArBghbijsktuCvDclmwnxyEzF
528 return hash_func 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
531def set_model_fields( 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
532 cls: type[BaseModel],
533 config_wrapper: ConfigWrapper,
534 ns_resolver: NsResolver | None,
535) -> None:
536 """Collect and set `cls.__pydantic_fields__` and `cls.__class_vars__`.
538 Args:
539 cls: BaseModel or dataclass.
540 config_wrapper: The config wrapper instance.
541 ns_resolver: Namespace resolver to use when getting model annotations.
542 """
543 typevars_map = get_model_typevars_map(cls) 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
544 fields, class_vars = collect_model_fields(cls, config_wrapper, ns_resolver, typevars_map=typevars_map) 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
546 cls.__pydantic_fields__ = fields 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
547 cls.__class_vars__.update(class_vars) 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
549 for k in class_vars: 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
550 # Class vars should not be private attributes
551 # We remove them _here_ and not earlier because we rely on inspecting the class to determine its classvars,
552 # but private attributes are determined by inspecting the namespace _prior_ to class creation.
553 # In the case that a classvar with a leading-'_' is defined via a ForwardRef (e.g., when using
554 # `__future__.annotations`), we want to remove the private attribute which was detected _before_ we knew it
555 # evaluated to a classvar
557 value = cls.__private_attributes__.pop(k, None) 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
558 if value is not None and value.default is not PydanticUndefined: 558 ↛ 559line 558 didn't jump to line 559 because the condition on line 558 was never true1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
559 setattr(cls, k, value.default)
562def complete_model_class( 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
563 cls: type[BaseModel],
564 config_wrapper: ConfigWrapper,
565 *,
566 raise_errors: bool = True,
567 ns_resolver: NsResolver | None = None,
568 create_model_module: str | None = None,
569) -> bool:
570 """Finish building a model class.
572 This logic must be called after class has been created since validation functions must be bound
573 and `get_type_hints` requires a class object.
575 Args:
576 cls: BaseModel or dataclass.
577 config_wrapper: The config wrapper instance.
578 raise_errors: Whether to raise errors.
579 ns_resolver: The namespace resolver instance to use during schema building.
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) 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
590 gen_schema = GenerateSchema( 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
591 config_wrapper,
592 ns_resolver,
593 typevars_map,
594 )
596 try: 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
597 schema = gen_schema.generate_schema(cls) 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
598 except PydanticUndefinedAnnotation as e: 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
599 if raise_errors: 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
600 raise 1adeofpqArBghbijsktuCvDclmwnxyEzF
601 set_model_mocks(cls, f'`{e.name}`') 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
602 return False 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
604 core_config = config_wrapper.core_config(title=cls.__name__) 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
606 try: 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
607 schema = gen_schema.clean_schema(schema) 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
608 except InvalidSchemaError: 1adeofpqArBghbijsktuCvDclmwnxyEzF
609 set_model_mocks(cls) 1adeofpqArBghbijsktuCvDclmwnxyEzF
610 return False 1adeofpqArBghbijsktuCvDclmwnxyEzF
612 # This needs to happen *after* model schema generation, as the return type
613 # of the properties are evaluated and the `ComputedFieldInfo` are recreated:
614 cls.__pydantic_computed_fields__ = {k: v.info for k, v in cls.__pydantic_decorators__.computed_fields.items()} 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
616 set_deprecated_descriptors(cls) 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
618 cls.__pydantic_core_schema__ = schema 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
620 cls.__pydantic_validator__ = create_schema_validator( 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
621 schema,
622 cls,
623 create_model_module or cls.__module__,
624 cls.__qualname__,
625 'create_model' if create_model_module else 'BaseModel',
626 core_config,
627 config_wrapper.plugin_settings,
628 )
629 cls.__pydantic_serializer__ = SchemaSerializer(schema, core_config) 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
630 cls.__pydantic_complete__ = True 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
632 # set __signature__ attr only for model class, but not for its instances
633 # (because instances can define `__call__`, and `inspect.signature` shouldn't
634 # use the `__signature__` attribute and instead generate from `__call__`).
635 cls.__signature__ = LazyClassAttribute( 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
636 '__signature__',
637 partial(
638 generate_pydantic_signature,
639 init=cls.__init__,
640 fields=cls.__pydantic_fields__,
641 populate_by_name=config_wrapper.populate_by_name,
642 extra=config_wrapper.extra,
643 ),
644 )
645 return True 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
648def set_deprecated_descriptors(cls: type[BaseModel]) -> None: 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
649 """Set data descriptors on the class for deprecated fields."""
650 for field, field_info in cls.__pydantic_fields__.items(): 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
651 if (msg := field_info.deprecation_message) is not None: 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
652 desc = _DeprecatedFieldDescriptor(msg) 1adeofpqArBghbijsktuCvDclmwnxyEzF
653 desc.__set_name__(cls, field) 1adeofpqArBghbijsktuCvDclmwnxyEzF
654 setattr(cls, field, desc) 1adeofpqArBghbijsktuCvDclmwnxyEzF
656 for field, computed_field_info in cls.__pydantic_computed_fields__.items(): 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
657 if ( 1adghbicl
658 (msg := computed_field_info.deprecation_message) is not None
659 # Avoid having two warnings emitted:
660 and not hasattr(unwrap_wrapped_function(computed_field_info.wrapped_property), '__deprecated__')
661 ):
662 desc = _DeprecatedFieldDescriptor(msg, computed_field_info.wrapped_property) 1adeofpqArBghbijsktuCvDclmwnxyEzF
663 desc.__set_name__(cls, field) 1adeofpqArBghbijsktuCvDclmwnxyEzF
664 setattr(cls, field, desc) 1adeofpqArBghbijsktuCvDclmwnxyEzF
667class _DeprecatedFieldDescriptor: 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
668 """Read-only data descriptor used to emit a runtime deprecation warning before accessing a deprecated field.
670 Attributes:
671 msg: The deprecation message to be emitted.
672 wrapped_property: The property instance if the deprecated field is a computed field, or `None`.
673 field_name: The name of the field being deprecated.
674 """
676 field_name: str 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
678 def __init__(self, msg: str, wrapped_property: property | None = None) -> None: 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
679 self.msg = msg 1adeofpqArBghbijsktuCvDclmwnxyEzF
680 self.wrapped_property = wrapped_property 1adeofpqArBghbijsktuCvDclmwnxyEzF
682 def __set_name__(self, cls: type[BaseModel], name: str) -> None: 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
683 self.field_name = name 1adeofpqArBghbijsktuCvDclmwnxyEzF
685 def __get__(self, obj: BaseModel | None, obj_type: type[BaseModel] | None = None) -> Any: 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
686 if obj is None: 1adeofpqArBghbijsktuCvDclmwnxyEzF
687 if self.wrapped_property is not None: 1adeofpqArBghbijsktuCvDclmwnxyEzF
688 return self.wrapped_property.__get__(None, obj_type) 1adeofpqArBghbijsktuCvDclmwnxyEzF
689 raise AttributeError(self.field_name) 1adeofpqArBghbijsktuCvDclmwnxyEzF
691 warnings.warn(self.msg, builtins.DeprecationWarning, stacklevel=2) 1adeofpqArBghbijsktuCvDclmwnxyEzF
693 if self.wrapped_property is not None: 1adeofpqArBghbijsktuCvDclmwnxyEzF
694 return self.wrapped_property.__get__(obj, obj_type) 1adeofpqArBghbijsktuCvDclmwnxyEzF
695 return obj.__dict__[self.field_name] 1adeofpqArBghbijsktuCvDclmwnxyEzF
697 # Defined to make it a data descriptor and take precedence over the instance's dictionary.
698 # Note that it will not be called when setting a value on a model instance
699 # as `BaseModel.__setattr__` is defined and takes priority.
700 def __set__(self, obj: Any, value: Any) -> NoReturn: 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
701 raise AttributeError(self.field_name)
704class _PydanticWeakRef: 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
705 """Wrapper for `weakref.ref` that enables `pickle` serialization.
707 Cloudpickle fails to serialize `weakref.ref` objects due to an arcane error related
708 to abstract base classes (`abc.ABC`). This class works around the issue by wrapping
709 `weakref.ref` instead of subclassing it.
711 See https://github.com/pydantic/pydantic/issues/6763 for context.
713 Semantics:
714 - If not pickled, behaves the same as a `weakref.ref`.
715 - If pickled along with the referenced object, the same `weakref.ref` behavior
716 will be maintained between them after unpickling.
717 - If pickled without the referenced object, after unpickling the underlying
718 reference will be cleared (`__call__` will always return `None`).
719 """
721 def __init__(self, obj: Any): 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
722 if obj is None: 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
723 # The object will be `None` upon deserialization if the serialized weakref
724 # had lost its underlying object.
725 self._wr = None 1adeofpqArBghbijsktuCvDclmwnxyEzF
726 else:
727 self._wr = weakref.ref(obj) 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
729 def __call__(self) -> Any: 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
730 if self._wr is None: 1adeofpqArBghbijsktuCvDclmwnxyEzF
731 return None 1adeofpqArBghbijsktuCvDclmwnxyEzF
732 else:
733 return self._wr() 1adeofpqArBghbijsktuCvDclmwnxyEzF
735 def __reduce__(self) -> tuple[Callable, tuple[weakref.ReferenceType | None]]: 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
736 return _PydanticWeakRef, (self(),) 1aefqrghbjkuvcmnyz
739def build_lenient_weakvaluedict(d: dict[str, Any] | None) -> dict[str, Any] | None: 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
740 """Takes an input dictionary, and produces a new value that (invertibly) replaces the values with weakrefs.
742 We can't just use a WeakValueDictionary because many types (including int, str, etc.) can't be stored as values
743 in a WeakValueDictionary.
745 The `unpack_lenient_weakvaluedict` function can be used to reverse this operation.
746 """
747 if d is None: 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
748 return None 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
749 result = {} 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
750 for k, v in d.items(): 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
751 try: 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
752 proxy = _PydanticWeakRef(v) 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
753 except TypeError: 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
754 proxy = v 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
755 result[k] = proxy 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
756 return result 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
759def unpack_lenient_weakvaluedict(d: dict[str, Any] | None) -> dict[str, Any] | None: 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
760 """Inverts the transform performed by `build_lenient_weakvaluedict`."""
761 if d is None: 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
762 return None 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
764 result = {} 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
765 for k, v in d.items(): 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
766 if isinstance(v, _PydanticWeakRef): 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
767 v = v() 1adeofpqArBghbijsktuCvDclmwnxyEzF
768 if v is not None: 1adeofpqArBghbijsktuCvDclmwnxyEzF
769 result[k] = v 1adeofpqArBghbijsktuCvDclmwnxyEzF
770 else:
771 result[k] = v 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
772 return result 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
775@cache 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
776def default_ignored_types() -> tuple[type[Any], ...]: 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
777 from ..fields import ComputedFieldInfo 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
779 ignored_types = [ 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
780 FunctionType,
781 property,
782 classmethod,
783 staticmethod,
784 PydanticDescriptorProxy,
785 ComputedFieldInfo,
786 TypeAliasType, # from `typing_extensions`
787 ]
789 if sys.version_info >= (3, 12): 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF
790 ignored_types.append(typing.TypeAliasType) 1qArBuCvDJKLMyEzF
792 return tuple(ignored_types) 1adeofpqArBghbijsktuCvDGHIJKLMclmwnxyEzF