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