Coverage for pydantic/_internal/_model_construction.py: 99.01%

355 statements  

« prev     ^ index     » next       coverage.py v7.10.0, created at 2025-07-26 11:49 +0000

1"""Private logic for creating models.""" 

2 

3from __future__ import annotations as _annotations 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

4 

5import builtins 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

6import operator 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

7import sys 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

8import typing 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

9import warnings 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

10import weakref 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

11from abc import ABCMeta 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

12from functools import cache, partial, wraps 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

13from types import FunctionType 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

14from typing import Any, Callable, Generic, Literal, NoReturn, cast 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

15 

16from pydantic_core import PydanticUndefined, SchemaSerializer 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

17from typing_extensions import TypeAliasType, dataclass_transform, deprecated, get_args, get_origin 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

18from typing_inspection import typing_objects 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

19 

20from ..errors import PydanticUndefinedAnnotation, PydanticUserError 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

21from ..plugin._schema_validator import create_schema_validator 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

22from ..warnings import GenericBeforeBaseModelWarning, PydanticDeprecatedSince20 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

23from ._config import ConfigWrapper 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

24from ._decorators import DecoratorInfos, PydanticDescriptorProxy, get_attribute_from_bases, unwrap_wrapped_function 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

25from ._fields import collect_model_fields, is_valid_field_name, is_valid_privateattr_name, rebuild_model_fields 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

26from ._generate_schema import GenerateSchema, InvalidSchemaError 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

27from ._generics import PydanticGenericMetadata, get_model_typevars_map 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

28from ._import_utils import import_cached_base_model, import_cached_field_info 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

29from ._mock_val_ser import set_model_mocks 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

30from ._namespace_utils import NsResolver 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

31from ._signature import generate_pydantic_signature 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

32from ._typing_extra import ( 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

33 _make_forward_ref, 

34 eval_type_backport, 

35 is_classvar_annotation, 

36 parent_frame_namespace, 

37) 

38from ._utils import LazyClassAttribute, SafeGetItemProxy 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

39 

40if typing.TYPE_CHECKING: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

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 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

49 PydanticModelField = object() 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

50 PydanticModelPrivateAttr = object() 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

51 

52object_setattr = object.__setattr__ 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

53 

54 

55class _ModelNamespaceDict(dict): 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

56 """A dictionary subclass that intercepts attribute setting on model classes and 

57 warns about overriding of decorators. 

58 """ 

59 

60 def __setitem__(self, k: str, v: object) -> None: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

61 existing: Any = self.get(k, None) 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

62 if existing and v is not existing and isinstance(existing, PydanticDescriptorProxy): 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

63 warnings.warn(f'`{k}` overrides an existing Pydantic `{existing.decorator_info.decorator_repr}` decorator') 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

64 

65 return super().__setitem__(k, v) 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

66 

67 

68def NoInitField( 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

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 """ 

76 

77 

78@dataclass_transform(kw_only_default=True, field_specifiers=(PydanticModelField, PydanticModelPrivateAttr, NoInitField)) 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

79class ModelMetaclass(ABCMeta): 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

80 def __new__( 1jmnxoyzJAKadekrsBtCDLEMbfgPluvFwGHNIOchi

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. 

91 

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. 

100 

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: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

108 raw_annotations: dict[str, Any] 

109 if sys.version_info >= (3, 14): 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

110 if ( 

111 '__annotations__' in namespace 

112 ): # `from __future__ import annotations` was used in the model's module 

113 raw_annotations = namespace['__annotations__'] 1adebfgchi

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 1adebfgchi

117 

118 if annotate := get_annotate_from_class_namespace(namespace): 1adebfgchi

119 raw_annotations = call_annotate_function(annotate, format=Format.FORWARDREF) 1adebfgchi

120 else: 

121 raw_annotations = {} 1adebfgchi

122 else: 

123 raw_annotations = namespace.get('__annotations__', {}) 1jmnxoyzJAKpqkrsBtCDLEMPluvFwGHNIO

124 

125 base_field_names, class_vars, base_private_attributes = mcs._collect_bases_data(bases) 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

126 

127 config_wrapper = ConfigWrapper.for_model(bases, namespace, raw_annotations, kwargs) 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

128 namespace['model_config'] = config_wrapper.config_dict 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

129 private_attributes = inspect_namespace( 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

130 namespace, raw_annotations, config_wrapper.ignored_types, class_vars, base_field_names 

131 ) 

132 if private_attributes or base_private_attributes: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

133 original_model_post_init = get_model_post_init(namespace, bases) 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

134 if original_model_post_init is not None: 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

135 # if there are private_attributes and a model_post_init function, we handle both 

136 

137 @wraps(original_model_post_init) 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

138 def wrapped_model_post_init(self: BaseModel, context: Any, /) -> None: 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

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) 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

143 original_model_post_init(self, context) 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

144 

145 namespace['model_post_init'] = wrapped_model_post_init 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

146 else: 

147 namespace['model_post_init'] = init_private_attributes 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

148 

149 namespace['__class_vars__'] = class_vars 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

150 namespace['__private_attributes__'] = {**base_private_attributes, **private_attributes} 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

151 

152 cls = cast('type[BaseModel]', super().__new__(mcs, cls_name, bases, namespace, **kwargs)) 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

153 BaseModel_ = import_cached_base_model() 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

154 

155 mro = cls.__mro__ 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

156 if Generic in mro and mro.index(Generic) < mro.index(BaseModel_): 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

157 warnings.warn( 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

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 ) 

164 

165 cls.__pydantic_custom_init__ = not getattr(cls.__init__, '__pydantic_base_init__', False) 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

166 cls.__pydantic_post_init__ = ( 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

167 None if cls.model_post_init is BaseModel_.model_post_init else 'model_post_init' 

168 ) 

169 

170 cls.__pydantic_setattr_handlers__ = {} 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

171 

172 cls.__pydantic_decorators__ = DecoratorInfos.build(cls) 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

173 cls.__pydantic_decorators__.update_from_config(config_wrapper) 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

174 

175 # Use the getattr below to grab the __parameters__ from the `typing.Generic` parent class 

176 if __pydantic_generic_metadata__: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

177 cls.__pydantic_generic_metadata__ = __pydantic_generic_metadata__ 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

178 else: 

179 parent_parameters = getattr(cls, '__pydantic_generic_metadata__', {}).get('parameters', ()) 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

180 parameters = getattr(cls, '__parameters__', None) or parent_parameters 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

181 if parameters and parent_parameters and not all(x in parameters for x in parent_parameters): 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

182 from ..root_model import RootModelRootType 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

183 

184 missing_parameters = tuple(x for x in parameters if x not in parent_parameters) 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

185 if RootModelRootType in parent_parameters and RootModelRootType not in parameters: 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

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]) 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

194 error_message = ( 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

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 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

201 parameters_str = ', '.join([str(x) for x in combined_parameters]) 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

202 generic_type_label = f'typing.Generic[{parameters_str}]' 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

203 error_message = ( 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

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 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

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]) 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

213 error_message += ( 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

214 f' Note: `typing.Generic` must go last: `class {cls.__name__}({bases_str}): ...`)' 

215 ) 

216 raise TypeError(error_message) 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

217 

218 cls.__pydantic_generic_metadata__ = { 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

219 'origin': None, 

220 'args': (), 

221 'parameters': parameters, 

222 } 

223 

224 cls.__pydantic_complete__ = False # Ensure this specific class gets completed 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

225 

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(): 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

229 obj.__set_name__(cls, name) 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

230 

231 if __pydantic_reset_parent_namespace__: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

232 cls.__pydantic_parent_namespace__ = build_lenient_weakvaluedict(parent_frame_namespace()) 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

233 parent_namespace: dict[str, Any] | None = getattr(cls, '__pydantic_parent_namespace__', None) 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

234 if isinstance(parent_namespace, dict): 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

235 parent_namespace = unpack_lenient_weakvaluedict(parent_namespace) 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

236 

237 ns_resolver = NsResolver(parent_namespace=parent_namespace) 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

238 

239 set_model_fields(cls, config_wrapper=config_wrapper, ns_resolver=ns_resolver) 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

240 

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__ = { 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

244 k: v.info for k, v in cls.__pydantic_decorators__.computed_fields.items() 

245 } 

246 

247 if config_wrapper.defer_build: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

248 set_model_mocks(cls) 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

249 else: 

250 # Any operation that requires accessing the field infos instances should be put inside 

251 # `complete_model_class()`: 

252 complete_model_class( 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

253 cls, 

254 config_wrapper, 

255 ns_resolver, 

256 raise_errors=False, 

257 create_model_module=_create_model_module, 

258 ) 

259 

260 if config_wrapper.frozen and '__hash__' not in namespace: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

261 set_default_hash_func(cls, bases) 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

262 

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] 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

267 return cls 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

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__': 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

271 namespace.pop( 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

272 instance_slot, 

273 None, # In case the metaclass is used with a class other than `BaseModel`. 

274 ) 

275 namespace.get('__annotations__', {}).clear() 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

276 return super().__new__(mcs, cls_name, bases, namespace, **kwargs) 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

277 

278 if not typing.TYPE_CHECKING: # pragma: no branch 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

279 # We put `__getattr__` in a non-TYPE_CHECKING block because otherwise, mypy allows arbitrary attribute access 

280 

281 def __getattr__(self, item: str) -> Any: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

282 """This is necessary to keep attribute access working for class attribute access.""" 

283 private_attributes = self.__dict__.get('__private_attributes__') 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

284 if private_attributes and item in private_attributes: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

285 return private_attributes[item] 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

286 raise AttributeError(item) 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

287 

288 @classmethod 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

289 def __prepare__(cls, *args: Any, **kwargs: Any) -> dict[str, object]: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

290 return _ModelNamespaceDict() 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

291 

292 def __instancecheck__(self, instance: Any) -> bool: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

293 """Avoid calling ABC _abc_instancecheck unless we're pretty sure. 

294 

295 See #3829 and python/cpython#92810 

296 """ 

297 return hasattr(instance, '__pydantic_decorators__') and super().__instancecheck__(instance) 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

298 

299 def __subclasscheck__(self, subclass: type[Any]) -> bool: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

300 """Avoid calling ABC _abc_subclasscheck unless we're pretty sure. 

301 

302 See #3829 and python/cpython#92810 

303 """ 

304 return hasattr(subclass, '__pydantic_decorators__') and super().__subclasscheck__(subclass) 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

305 

306 @staticmethod 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

307 def _collect_bases_data(bases: tuple[type[Any], ...]) -> tuple[set[str], set[str], dict[str, ModelPrivateAttr]]: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

308 BaseModel = import_cached_base_model() 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

309 

310 field_names: set[str] = set() 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

311 class_vars: set[str] = set() 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

312 private_attributes: dict[str, ModelPrivateAttr] = {} 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

313 for base in bases: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

314 if issubclass(base, BaseModel) and base is not BaseModel: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

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()) 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

317 class_vars.update(base.__class_vars__) 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

318 private_attributes.update(base.__private_attributes__) 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

319 return field_names, class_vars, private_attributes 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

320 

321 @property 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

322 @deprecated('The `__fields__` attribute is deprecated, use `model_fields` instead.', category=None) 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

323 def __fields__(self) -> dict[str, FieldInfo]: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

324 warnings.warn( 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

325 'The `__fields__` attribute is deprecated, use `model_fields` instead.', 

326 PydanticDeprecatedSince20, 

327 stacklevel=2, 

328 ) 

329 return getattr(self, '__pydantic_fields__', {}) 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

330 

331 @property 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

332 def __pydantic_fields_complete__(self) -> bool: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

333 """Whether the fields where successfully collected (i.e. type hints were successfully resolves). 

334 

335 This is a private attribute, not meant to be used outside Pydantic. 

336 """ 

337 if not hasattr(self, '__pydantic_fields__'): 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

338 return False 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

339 

340 field_infos = cast('dict[str, FieldInfo]', self.__pydantic_fields__) # pyright: ignore[reportAttributeAccessIssue] 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

341 

342 return all(field_info._complete for field_info in field_infos.values()) 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

343 

344 def __dir__(self) -> list[str]: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

345 attributes = list(super().__dir__()) 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

346 if '__fields__' in attributes: 346 ↛ 348line 346 didn't jump to line 348 because the condition on line 346 was always true1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

347 attributes.remove('__fields__') 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

348 return attributes 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

349 

350 

351def init_private_attributes(self: BaseModel, context: Any, /) -> None: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

352 """This function is meant to behave like a BaseModel method to initialise private attributes. 

353 

354 It takes context as an argument since that's what pydantic-core passes when calling it. 

355 

356 Args: 

357 self: The BaseModel instance. 

358 context: The context. 

359 """ 

360 if getattr(self, '__pydantic_private__', None) is None: 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

361 pydantic_private = {} 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

362 for name, private_attr in self.__private_attributes__.items(): 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

363 default = private_attr.get_default() 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

364 if default is not PydanticUndefined: 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

365 pydantic_private[name] = default 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

366 object_setattr(self, '__pydantic_private__', pydantic_private) 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

367 

368 

369def get_model_post_init(namespace: dict[str, Any], bases: tuple[type[Any], ...]) -> Callable[..., Any] | None: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

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: 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

372 return namespace['model_post_init'] 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

373 

374 BaseModel = import_cached_base_model() 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

375 

376 model_post_init = get_attribute_from_bases(bases, 'model_post_init') 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

377 if model_post_init is not BaseModel.model_post_init: 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

378 return model_post_init 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

379 

380 

381def inspect_namespace( # noqa C901 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

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. 

391 

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. 

398 

399 Returns: 

400 A dict contains private attributes info. 

401 

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 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

410 

411 FieldInfo = import_cached_field_info() 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

412 

413 all_ignored_types = ignored_types + default_ignored_types() 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

414 

415 private_attributes: dict[str, ModelPrivateAttr] = {} 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

416 

417 if '__root__' in raw_annotations or '__root__' in namespace: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

418 raise TypeError("To define root models, use `pydantic.RootModel` rather than a field called '__root__'") 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

419 

420 ignored_names: set[str] = set() 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

421 for var_name, value in list(namespace.items()): 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

422 if var_name == 'model_config' or var_name == '__pydantic_extra__': 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

423 continue 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

424 elif ( 1jmnxoypqkrsBtCluvFwG

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 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

432 elif isinstance(value, all_ignored_types) or value.__class__.__module__ == 'functools': 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

433 ignored_names.add(var_name) 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

434 continue 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

435 elif isinstance(value, ModelPrivateAttr): 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

436 if var_name.startswith('__'): 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

437 raise NameError( 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

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): 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

442 raise NameError( 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

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 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

447 del namespace[var_name] 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

448 elif isinstance(value, FieldInfo) and not is_valid_field_name(var_name): 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

449 suggested_name = var_name.lstrip('_') or 'my_field' # don't suggest '' for all-underscore name 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

450 raise NameError( 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

451 f'Fields must not use names with leading underscores;' 

452 f' e.g., use {suggested_name!r} instead of {var_name!r}.' 

453 ) 

454 

455 elif var_name.startswith('__'): 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

456 continue 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

457 elif is_valid_privateattr_name(var_name): 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

458 if var_name not in raw_annotations or not is_classvar_annotation(raw_annotations[var_name]): 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

459 private_attributes[var_name] = cast(ModelPrivateAttr, PrivateAttr(default=value)) 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

460 del namespace[var_name] 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

461 elif var_name in base_class_vars: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

462 continue 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

463 elif var_name not in raw_annotations: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

464 if var_name in base_class_fields: 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

465 raise PydanticUserError( 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

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): 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

471 raise PydanticUserError( 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

472 f'Field {var_name!r} requires a type annotation', code='model-field-missing-annotation' 

473 ) 

474 else: 

475 raise PydanticUserError( 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

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 ) 

481 

482 for ann_name, ann_type in raw_annotations.items(): 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

483 if ( 1jmnxoypqkrsBtCluvFwG

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): 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

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) 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

497 if frame is not None: 497 ↛ 507line 497 didn't jump to line 507 because the condition on line 497 was always true1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

498 try: 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

499 ann_type = eval_type_backport( 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

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): 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

505 pass 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

506 

507 if typing_objects.is_annotated(get_origin(ann_type)): 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

508 _, *metadata = get_args(ann_type) 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

509 private_attr = next((v for v in metadata if isinstance(v, ModelPrivateAttr)), None) 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

510 if private_attr is not None: 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

511 private_attributes[ann_name] = private_attr 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

512 continue 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

513 private_attributes[ann_name] = PrivateAttr() 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

514 

515 return private_attributes 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

516 

517 

518def set_default_hash_func(cls: type[BaseModel], bases: tuple[type[Any], ...]) -> None: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

519 base_hash_func = get_attribute_from_bases(bases, '__hash__') 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

520 new_hash_func = make_hash_func(cls) 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

521 if base_hash_func in {None, object.__hash__} or getattr(base_hash_func, '__code__', None) == new_hash_func.__code__: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

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 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

529 

530 

531def make_hash_func(cls: type[BaseModel]) -> Any: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

532 getter = operator.itemgetter(*cls.__pydantic_fields__.keys()) if cls.__pydantic_fields__ else lambda _: 0 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

533 

534 def hash_func(self: Any) -> int: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

535 try: 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

536 return hash(getter(self.__dict__)) 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

537 except KeyError: 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

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__))) 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

543 

544 return hash_func 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

545 

546 

547def set_model_fields( 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

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__`. 

553 

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) 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

560 fields, class_vars = collect_model_fields(cls, config_wrapper, ns_resolver, typevars_map=typevars_map) 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

561 

562 cls.__pydantic_fields__ = fields 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

563 cls.__class_vars__.update(class_vars) 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

564 

565 for k in class_vars: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

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 

572 

573 value = cls.__private_attributes__.pop(k, None) 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

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 true1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

575 setattr(cls, k, value.default) 

576 

577 

578def complete_model_class( 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

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. 

588 

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. 

591 

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`. 

599 

600 Returns: 

601 `True` if the model is successfully completed, else `False`. 

602 

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) 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

608 

609 if not cls.__pydantic_fields_complete__: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

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: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

617 cls.__pydantic_fields__ = rebuild_model_fields( 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

618 cls, 

619 config_wrapper=config_wrapper, 

620 ns_resolver=ns_resolver, 

621 typevars_map=typevars_map, 

622 ) 

623 except NameError as e: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

624 exc = PydanticUndefinedAnnotation.from_name_error(e) 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

625 set_model_mocks(cls, f'`{exc.name}`') 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

626 if raise_errors: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

627 raise exc from e 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

628 

629 if not raise_errors and not cls.__pydantic_fields_complete__: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

630 # No need to continue with schema gen, it is guaranteed to fail 

631 return False 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

632 

633 assert cls.__pydantic_fields_complete__ 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

634 

635 gen_schema = GenerateSchema( 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

636 config_wrapper, 

637 ns_resolver, 

638 typevars_map, 

639 ) 

640 

641 try: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

642 schema = gen_schema.generate_schema(cls) 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

643 except PydanticUndefinedAnnotation as e: 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

644 if raise_errors: 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

645 raise 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

646 set_model_mocks(cls, f'`{e.name}`') 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

647 return False 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

648 

649 core_config = config_wrapper.core_config(title=cls.__name__) 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

650 

651 try: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

652 schema = gen_schema.clean_schema(schema) 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

653 except InvalidSchemaError: 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

654 set_model_mocks(cls) 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

655 return False 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

656 

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()} 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

660 

661 set_deprecated_descriptors(cls) 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

662 

663 cls.__pydantic_core_schema__ = schema 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

664 

665 cls.__pydantic_validator__ = create_schema_validator( 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

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) 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

675 

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( 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

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 ) 

689 

690 cls.__pydantic_complete__ = True 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

691 

692 if call_on_complete_hook: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

693 cls.__pydantic_on_complete__() 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

694 

695 return True 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

696 

697 

698def set_deprecated_descriptors(cls: type[BaseModel]) -> None: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

699 """Set data descriptors on the class for deprecated fields.""" 

700 for field, field_info in cls.__pydantic_fields__.items(): 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

701 if (msg := field_info.deprecation_message) is not None: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

702 desc = _DeprecatedFieldDescriptor(msg) 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

703 desc.__set_name__(cls, field) 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

704 setattr(cls, field, desc) 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

705 

706 for field, computed_field_info in cls.__pydantic_computed_fields__.items(): 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

707 if ( 1jmpqkrlu

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) 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

713 desc.__set_name__(cls, field) 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

714 setattr(cls, field, desc) 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

715 

716 

717class _DeprecatedFieldDescriptor: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

718 """Read-only data descriptor used to emit a runtime deprecation warning before accessing a deprecated field. 

719 

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 """ 

725 

726 field_name: str 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

727 

728 def __init__(self, msg: str, wrapped_property: property | None = None) -> None: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

729 self.msg = msg 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

730 self.wrapped_property = wrapped_property 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

731 

732 def __set_name__(self, cls: type[BaseModel], name: str) -> None: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

733 self.field_name = name 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

734 

735 def __get__(self, obj: BaseModel | None, obj_type: type[BaseModel] | None = None) -> Any: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

736 if obj is None: 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

737 if self.wrapped_property is not None: 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

738 return self.wrapped_property.__get__(None, obj_type) 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

739 raise AttributeError(self.field_name) 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

740 

741 warnings.warn(self.msg, builtins.DeprecationWarning, stacklevel=2) 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

742 

743 if self.wrapped_property is not None: 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

744 return self.wrapped_property.__get__(obj, obj_type) 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

745 return obj.__dict__[self.field_name] 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

746 

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: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

751 raise AttributeError(self.field_name) 

752 

753 

754class _PydanticWeakRef: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

755 """Wrapper for `weakref.ref` that enables `pickle` serialization. 

756 

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. 

760 

761 See https://github.com/pydantic/pydantic/issues/6763 for context. 

762 

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 """ 

770 

771 def __init__(self, obj: Any): 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

772 if obj is None: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

773 # The object will be `None` upon deserialization if the serialized weakref 

774 # had lost its underlying object. 

775 self._wr = None 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

776 else: 

777 self._wr = weakref.ref(obj) 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

778 

779 def __call__(self) -> Any: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

780 if self._wr is None: 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

781 return None 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

782 else: 

783 return self._wr() 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

784 

785 def __reduce__(self) -> tuple[Callable, tuple[weakref.ReferenceType | None]]: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

786 return _PydanticWeakRef, (self(),) 1jnozAapqkstDEblvwHIc

787 

788 

789def build_lenient_weakvaluedict(d: dict[str, Any] | None) -> dict[str, Any] | None: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

790 """Takes an input dictionary, and produces a new value that (invertibly) replaces the values with weakrefs. 

791 

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. 

794 

795 The `unpack_lenient_weakvaluedict` function can be used to reverse this operation. 

796 """ 

797 if d is None: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

798 return None 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

799 result = {} 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

800 for k, v in d.items(): 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

801 try: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

802 proxy = _PydanticWeakRef(v) 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

803 except TypeError: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

804 proxy = v 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

805 result[k] = proxy 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

806 return result 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

807 

808 

809def unpack_lenient_weakvaluedict(d: dict[str, Any] | None) -> dict[str, Any] | None: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

810 """Inverts the transform performed by `build_lenient_weakvaluedict`.""" 

811 if d is None: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

812 return None 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

813 

814 result = {} 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

815 for k, v in d.items(): 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

816 if isinstance(v, _PydanticWeakRef): 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

817 v = v() 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

818 if v is not None: 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

819 result[k] = v 1jmnxoyzJAKadepqkrsBtCDLEMbfgluvFwGHNIOchi

820 else: 

821 result[k] = v 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

822 return result 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

823 

824 

825@cache 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

826def default_ignored_types() -> tuple[type[Any], ...]: 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

827 from ..fields import ComputedFieldInfo 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

828 

829 ignored_types = [ 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

830 FunctionType, 

831 property, 

832 classmethod, 

833 staticmethod, 

834 PydanticDescriptorProxy, 

835 ComputedFieldInfo, 

836 TypeAliasType, # from `typing_extensions` 

837 ] 

838 

839 if sys.version_info >= (3, 12): 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi

840 ignored_types.append(typing.TypeAliasType) 1zJAKadeDLEMbfgPHNIOchi

841 

842 return tuple(ignored_types) 1jmnxoyzJAKadepqkrsBtCDLEMbfgPluvFwGHNIOchi