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

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

2 

3from __future__ import annotations as _annotations 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

4 

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

15 

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

19 

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

39 

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

51 

52object_setattr = object.__setattr__ 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

53 

54 

55class _ModelNamespaceDict(dict): 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

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

64 

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

66 

67 

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

76 

77 

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. 

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

108 base_field_names, class_vars, base_private_attributes = mcs._collect_bases_data(bases) 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

109 

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 

119 

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

127 

128 namespace['model_post_init'] = wrapped_model_post_init 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

129 else: 

130 namespace['model_post_init'] = init_private_attributes 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

131 

132 namespace['__class_vars__'] = class_vars 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

133 namespace['__private_attributes__'] = {**base_private_attributes, **private_attributes} 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

134 

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

136 BaseModel_ = import_cached_base_model() 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

137 

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 ) 

147 

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 ) 

152 

153 cls.__pydantic_setattr_handlers__ = {} 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

154 

155 cls.__pydantic_decorators__ = DecoratorInfos.build(cls) 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

156 

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

165 

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

199 

200 cls.__pydantic_generic_metadata__ = { 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

201 'origin': None, 

202 'args': (), 

203 'parameters': parameters, 

204 } 

205 

206 cls.__pydantic_complete__ = False # Ensure this specific class gets completed 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

207 

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

212 

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

218 

219 ns_resolver = NsResolver(parent_namespace=parent_namespace) 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

220 

221 set_model_fields(cls, config_wrapper=config_wrapper, ns_resolver=ns_resolver) 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

222 

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 } 

228 

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 ) 

241 

242 if config_wrapper.frozen and '__hash__' not in namespace: 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

243 set_default_hash_func(cls, bases) 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

244 

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

259 

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 

262 

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

269 

270 @classmethod 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

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

272 return _ModelNamespaceDict() 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

273 

274 def __instancecheck__(self, instance: Any) -> bool: 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

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

276 

277 See #3829 and python/cpython#92810 

278 """ 

279 return hasattr(instance, '__pydantic_decorators__') and super().__instancecheck__(instance) 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

280 

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

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

283 

284 See #3829 and python/cpython#92810 

285 """ 

286 return hasattr(subclass, '__pydantic_decorators__') and super().__subclasscheck__(subclass) 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

287 

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

291 

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

302 

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

312 

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

316 

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

321 

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

323 

324 return all(field_info._complete for field_info in field_infos.values()) 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

325 

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

331 

332 

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. 

335 

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

337 

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

349 

350 

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

355 

356 BaseModel = import_cached_base_model() 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

357 

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

361 

362 

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. 

372 

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. 

378 

379 Returns: 

380 A dict contains private attributes info. 

381 

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

390 

391 FieldInfo = import_cached_field_info() 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

392 

393 all_ignored_types = ignored_types + default_ignored_types() 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

394 

395 private_attributes: dict[str, ModelPrivateAttr] = {} 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

396 raw_annotations = namespace.get('__annotations__', {}) 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

397 

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

400 

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 ) 

435 

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 ) 

462 

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

487 

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

495 

496 return private_attributes 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

497 

498 

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

510 

511 

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

514 

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

524 

525 return hash_func 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

526 

527 

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

534 

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

542 

543 cls.__pydantic_fields__ = fields 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

544 cls.__class_vars__.update(class_vars) 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

545 

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 

553 

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) 

557 

558 

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. 

568 

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. 

571 

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

578 

579 Returns: 

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

581 

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

587 

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

606 

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

610 

611 assert cls.__pydantic_fields_complete__ 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

612 

613 gen_schema = GenerateSchema( 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

614 config_wrapper, 

615 ns_resolver, 

616 typevars_map, 

617 ) 

618 

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

626 

627 core_config = config_wrapper.core_config(title=cls.__name__) 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

628 

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

634 

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

638 

639 set_deprecated_descriptors(cls) 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

640 

641 cls.__pydantic_core_schema__ = schema 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

642 

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

653 

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 ) 

667 

668 cls.__pydantic_complete__ = True 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

669 

670 return True 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

671 

672 

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

680 

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

690 

691 

692class _DeprecatedFieldDescriptor: 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

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

694 

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

700 

701 field_name: str 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

702 

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

706 

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

708 self.field_name = name 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

709 

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

715 

716 warnings.warn(self.msg, builtins.DeprecationWarning, stacklevel=2) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

717 

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

721 

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) 

727 

728 

729class _PydanticWeakRef: 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

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

731 

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. 

735 

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

737 

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

745 

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

753 

754 def __call__(self) -> Any: 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

755 if self._wr is None: 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

756 return None 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

757 else: 

758 return self._wr() 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

759 

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

761 return _PydanticWeakRef, (self(),) 1aefqrghbjkuvcmnyz

762 

763 

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. 

766 

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. 

769 

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

782 

783 

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

788 

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

798 

799 

800@cache 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

801def default_ignored_types() -> tuple[type[Any], ...]: 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

802 from ..fields import ComputedFieldInfo 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

803 

804 ignored_types = [ 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

805 FunctionType, 

806 property, 

807 classmethod, 

808 staticmethod, 

809 PydanticDescriptorProxy, 

810 ComputedFieldInfo, 

811 TypeAliasType, # from `typing_extensions` 

812 ] 

813 

814 if sys.version_info >= (3, 12): 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

815 ignored_types.append(typing.TypeAliasType) 1qArBCuDvEFMNOPyGzHI

816 

817 return tuple(ignored_types) 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI