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