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

348 statements  

« prev     ^ index     » next       coverage.py v7.8.0, created at 2025-05-02 11:05 +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 cls.__pydantic_decorators__.update_from_config(config_wrapper) 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

157 

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

159 if __pydantic_generic_metadata__: 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

160 cls.__pydantic_generic_metadata__ = __pydantic_generic_metadata__ 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

161 else: 

162 parent_parameters = getattr(cls, '__pydantic_generic_metadata__', {}).get('parameters', ()) 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

163 parameters = getattr(cls, '__parameters__', None) or parent_parameters 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

164 if parameters and parent_parameters and not all(x in parameters for x in parent_parameters): 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

165 from ..root_model import RootModelRootType 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

166 

167 missing_parameters = tuple(x for x in parameters if x not in parent_parameters) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

168 if RootModelRootType in parent_parameters and RootModelRootType not in parameters: 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

169 # This is a special case where the user has subclassed `RootModel`, but has not parametrized 

170 # RootModel with the generic type identifiers being used. Ex: 

171 # class MyModel(RootModel, Generic[T]): 

172 # root: T 

173 # Should instead just be: 

174 # class MyModel(RootModel[T]): 

175 # root: T 

176 parameters_str = ', '.join([x.__name__ for x in missing_parameters]) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

177 error_message = ( 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

178 f'{cls.__name__} is a subclass of `RootModel`, but does not include the generic type identifier(s) ' 

179 f'{parameters_str} in its parameters. ' 

180 f'You should parametrize RootModel directly, e.g., `class {cls.__name__}(RootModel[{parameters_str}]): ...`.' 

181 ) 

182 else: 

183 combined_parameters = parent_parameters + missing_parameters 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

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

185 generic_type_label = f'typing.Generic[{parameters_str}]' 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

186 error_message = ( 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

187 f'All parameters must be present on typing.Generic;' 

188 f' you should inherit from {generic_type_label}.' 

189 ) 

190 if Generic not in bases: # pragma: no cover 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

191 # We raise an error here not because it is desirable, but because some cases are mishandled. 

192 # It would be nice to remove this error and still have things behave as expected, it's just 

193 # challenging because we are using a custom `__class_getitem__` to parametrize generic models, 

194 # and not returning a typing._GenericAlias from it. 

195 bases_str = ', '.join([x.__name__ for x in bases] + [generic_type_label]) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

196 error_message += ( 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

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

198 ) 

199 raise TypeError(error_message) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

200 

201 cls.__pydantic_generic_metadata__ = { 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

202 'origin': None, 

203 'args': (), 

204 'parameters': parameters, 

205 } 

206 

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

208 

209 # preserve `__set_name__` protocol defined in https://peps.python.org/pep-0487 

210 # for attributes not in `new_namespace` (e.g. private attributes) 

211 for name, obj in private_attributes.items(): 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

212 obj.__set_name__(cls, name) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

213 

214 if __pydantic_reset_parent_namespace__: 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

215 cls.__pydantic_parent_namespace__ = build_lenient_weakvaluedict(parent_frame_namespace()) 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

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

217 if isinstance(parent_namespace, dict): 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

218 parent_namespace = unpack_lenient_weakvaluedict(parent_namespace) 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

219 

220 ns_resolver = NsResolver(parent_namespace=parent_namespace) 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

221 

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

223 

224 # This is also set in `complete_model_class()`, after schema gen because they are recreated. 

225 # We set them here as well for backwards compatibility: 

226 cls.__pydantic_computed_fields__ = { 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

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

228 } 

229 

230 if config_wrapper.defer_build: 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

231 set_model_mocks(cls) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

232 else: 

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

234 # `complete_model_class()`: 

235 complete_model_class( 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

236 cls, 

237 config_wrapper, 

238 ns_resolver, 

239 raise_errors=False, 

240 create_model_module=_create_model_module, 

241 ) 

242 

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

244 set_default_hash_func(cls, bases) 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

245 

246 # using super(cls, cls) on the next line ensures we only call the parent class's __pydantic_init_subclass__ 

247 # I believe the `type: ignore` is only necessary because mypy doesn't realize that this code branch is 

248 # only hit for _proper_ subclasses of BaseModel 

249 super(cls, cls).__pydantic_init_subclass__(**kwargs) # type: ignore[misc] 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

250 return cls 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

251 else: 

252 # These are instance variables, but have been assigned to `NoInitField` to trick the type checker. 

253 for instance_slot in '__pydantic_fields_set__', '__pydantic_extra__', '__pydantic_private__': 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

254 namespace.pop( 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

255 instance_slot, 

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

257 ) 

258 namespace.get('__annotations__', {}).clear() 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

259 return super().__new__(mcs, cls_name, bases, namespace, **kwargs) 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

260 

261 if not typing.TYPE_CHECKING: # pragma: no branch 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

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

263 

264 def __getattr__(self, item: str) -> Any: 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

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

266 private_attributes = self.__dict__.get('__private_attributes__') 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

267 if private_attributes and item in private_attributes: 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

268 return private_attributes[item] 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

269 raise AttributeError(item) 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

270 

271 @classmethod 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

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

273 return _ModelNamespaceDict() 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

274 

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

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

277 

278 See #3829 and python/cpython#92810 

279 """ 

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

281 

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

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

284 

285 See #3829 and python/cpython#92810 

286 """ 

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

288 

289 @staticmethod 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

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

291 BaseModel = import_cached_base_model() 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

292 

293 field_names: set[str] = set() 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

294 class_vars: set[str] = set() 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

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

296 for base in bases: 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

297 if issubclass(base, BaseModel) and base is not BaseModel: 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

298 # model_fields might not be defined yet in the case of generics, so we use getattr here: 

299 field_names.update(getattr(base, '__pydantic_fields__', {}).keys()) 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

300 class_vars.update(base.__class_vars__) 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

301 private_attributes.update(base.__private_attributes__) 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

302 return field_names, class_vars, private_attributes 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

303 

304 @property 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

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

306 def __fields__(self) -> dict[str, FieldInfo]: 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

307 warnings.warn( 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

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

309 PydanticDeprecatedSince20, 

310 stacklevel=2, 

311 ) 

312 return getattr(self, '__pydantic_fields__', {}) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

313 

314 @property 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

315 def __pydantic_fields_complete__(self) -> bool: 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

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

317 

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

319 """ 

320 if not hasattr(self, '__pydantic_fields__'): 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

321 return False 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

322 

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

324 

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

326 

327 def __dir__(self) -> list[str]: 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

328 attributes = list(super().__dir__()) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

329 if '__fields__' in attributes: 329 ↛ 331line 329 didn't jump to line 331 because the condition on line 329 was always true1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

330 attributes.remove('__fields__') 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

331 return attributes 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

332 

333 

334def init_private_attributes(self: BaseModel, context: Any, /) -> None: 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

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

336 

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

338 

339 Args: 

340 self: The BaseModel instance. 

341 context: The context. 

342 """ 

343 if getattr(self, '__pydantic_private__', None) is None: 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

344 pydantic_private = {} 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

345 for name, private_attr in self.__private_attributes__.items(): 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

346 default = private_attr.get_default() 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

347 if default is not PydanticUndefined: 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

348 pydantic_private[name] = default 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

349 object_setattr(self, '__pydantic_private__', pydantic_private) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

350 

351 

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

353 """Get the `model_post_init` method from the namespace or the class bases, or `None` if not defined.""" 

354 if 'model_post_init' in namespace: 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

355 return namespace['model_post_init'] 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

356 

357 BaseModel = import_cached_base_model() 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

358 

359 model_post_init = get_attribute_from_bases(bases, 'model_post_init') 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

360 if model_post_init is not BaseModel.model_post_init: 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

361 return model_post_init 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

362 

363 

364def inspect_namespace( # noqa C901 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

365 namespace: dict[str, Any], 

366 ignored_types: tuple[type[Any], ...], 

367 base_class_vars: set[str], 

368 base_class_fields: set[str], 

369) -> dict[str, ModelPrivateAttr]: 

370 """Iterate over the namespace and: 

371 * gather private attributes 

372 * check for items which look like fields but are not (e.g. have no annotation) and warn. 

373 

374 Args: 

375 namespace: The attribute dictionary of the class to be created. 

376 ignored_types: A tuple of ignore types. 

377 base_class_vars: A set of base class class variables. 

378 base_class_fields: A set of base class fields. 

379 

380 Returns: 

381 A dict contains private attributes info. 

382 

383 Raises: 

384 TypeError: If there is a `__root__` field in model. 

385 NameError: If private attribute name is invalid. 

386 PydanticUserError: 

387 - If a field does not have a type annotation. 

388 - If a field on base class was overridden by a non-annotated attribute. 

389 """ 

390 from ..fields import ModelPrivateAttr, PrivateAttr 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

391 

392 FieldInfo = import_cached_field_info() 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

393 

394 all_ignored_types = ignored_types + default_ignored_types() 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

395 

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

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

398 

399 if '__root__' in raw_annotations or '__root__' in namespace: 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

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

401 

402 ignored_names: set[str] = set() 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

403 for var_name, value in list(namespace.items()): 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

404 if var_name == 'model_config' or var_name == '__pydantic_extra__': 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

405 continue 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

406 elif ( 1adeofpghbijsktJKLclmwnx

407 isinstance(value, type) 

408 and value.__module__ == namespace['__module__'] 

409 and '__qualname__' in namespace 

410 and value.__qualname__.startswith(f'{namespace["__qualname__"]}.') 

411 ): 

412 # `value` is a nested type defined in this namespace; don't error 

413 continue 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

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

415 ignored_names.add(var_name) 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

416 continue 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

417 elif isinstance(value, ModelPrivateAttr): 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

418 if var_name.startswith('__'): 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

419 raise NameError( 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

420 'Private attributes must not use dunder names;' 

421 f' use a single underscore prefix instead of {var_name!r}.' 

422 ) 

423 elif is_valid_field_name(var_name): 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

424 raise NameError( 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

425 'Private attributes must not use valid field names;' 

426 f' use sunder names, e.g. {"_" + var_name!r} instead of {var_name!r}.' 

427 ) 

428 private_attributes[var_name] = value 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

429 del namespace[var_name] 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

430 elif isinstance(value, FieldInfo) and not is_valid_field_name(var_name): 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

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

432 raise NameError( 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

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

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

435 ) 

436 

437 elif var_name.startswith('__'): 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

438 continue 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

439 elif is_valid_privateattr_name(var_name): 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

440 if var_name not in raw_annotations or not is_classvar_annotation(raw_annotations[var_name]): 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

441 private_attributes[var_name] = cast(ModelPrivateAttr, PrivateAttr(default=value)) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

442 del namespace[var_name] 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

443 elif var_name in base_class_vars: 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

444 continue 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

445 elif var_name not in raw_annotations: 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

446 if var_name in base_class_fields: 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

447 raise PydanticUserError( 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

448 f'Field {var_name!r} defined on a base class was overridden by a non-annotated attribute. ' 

449 f'All field definitions, including overrides, require a type annotation.', 

450 code='model-field-overridden', 

451 ) 

452 elif isinstance(value, FieldInfo): 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

453 raise PydanticUserError( 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

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

455 ) 

456 else: 

457 raise PydanticUserError( 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

458 f'A non-annotated attribute was detected: `{var_name} = {value!r}`. All model fields require a ' 

459 f'type annotation; if `{var_name}` is not meant to be a field, you may be able to resolve this ' 

460 f"error by annotating it as a `ClassVar` or updating `model_config['ignored_types']`.", 

461 code='model-field-missing-annotation', 

462 ) 

463 

464 for ann_name, ann_type in raw_annotations.items(): 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

465 if ( 1adeofpghbijsktJKLclmwnx

466 is_valid_privateattr_name(ann_name) 

467 and ann_name not in private_attributes 

468 and ann_name not in ignored_names 

469 # This condition can be a false negative when `ann_type` is stringified, 

470 # but it is handled in most cases in `set_model_fields`: 

471 and not is_classvar_annotation(ann_type) 

472 and ann_type not in all_ignored_types 

473 and getattr(ann_type, '__module__', None) != 'functools' 

474 ): 

475 if isinstance(ann_type, str): 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

476 # Walking up the frames to get the module namespace where the model is defined 

477 # (as the model class wasn't created yet, we unfortunately can't use `cls.__module__`): 

478 frame = sys._getframe(2) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

479 if frame is not None: 479 ↛ 489line 479 didn't jump to line 489 because the condition on line 479 was always true1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

480 try: 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

481 ann_type = eval_type_backport( 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

482 _make_forward_ref(ann_type, is_argument=False, is_class=True), 

483 globalns=frame.f_globals, 

484 localns=frame.f_locals, 

485 ) 

486 except (NameError, TypeError): 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

487 pass 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

488 

489 if typing_objects.is_annotated(get_origin(ann_type)): 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

490 _, *metadata = get_args(ann_type) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

491 private_attr = next((v for v in metadata if isinstance(v, ModelPrivateAttr)), None) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

492 if private_attr is not None: 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

493 private_attributes[ann_name] = private_attr 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

494 continue 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

495 private_attributes[ann_name] = PrivateAttr() 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

496 

497 return private_attributes 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

498 

499 

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

501 base_hash_func = get_attribute_from_bases(bases, '__hash__') 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

502 new_hash_func = make_hash_func(cls) 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

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

504 # If `__hash__` is some default, we generate a hash function. 

505 # It will be `None` if not overridden from BaseModel. 

506 # It may be `object.__hash__` if there is another 

507 # parent class earlier in the bases which doesn't override `__hash__` (e.g. `typing.Generic`). 

508 # It may be a value set by `set_default_hash_func` if `cls` is a subclass of another frozen model. 

509 # In the last case we still need a new hash function to account for new `model_fields`. 

510 cls.__hash__ = new_hash_func 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

511 

512 

513def make_hash_func(cls: type[BaseModel]) -> Any: 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

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

515 

516 def hash_func(self: Any) -> int: 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

517 try: 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

518 return hash(getter(self.__dict__)) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

519 except KeyError: 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

520 # In rare cases (such as when using the deprecated copy method), the __dict__ may not contain 

521 # all model fields, which is how we can get here. 

522 # getter(self.__dict__) is much faster than any 'safe' method that accounts for missing keys, 

523 # and wrapping it in a `try` doesn't slow things down much in the common case. 

524 return hash(getter(SafeGetItemProxy(self.__dict__))) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

525 

526 return hash_func 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

527 

528 

529def set_model_fields( 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

530 cls: type[BaseModel], 

531 config_wrapper: ConfigWrapper, 

532 ns_resolver: NsResolver | None, 

533) -> None: 

534 """Collect and set `cls.__pydantic_fields__` and `cls.__class_vars__`. 

535 

536 Args: 

537 cls: BaseModel or dataclass. 

538 config_wrapper: The config wrapper instance. 

539 ns_resolver: Namespace resolver to use when getting model annotations. 

540 """ 

541 typevars_map = get_model_typevars_map(cls) 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

542 fields, class_vars = collect_model_fields(cls, config_wrapper, ns_resolver, typevars_map=typevars_map) 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

543 

544 cls.__pydantic_fields__ = fields 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

545 cls.__class_vars__.update(class_vars) 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

546 

547 for k in class_vars: 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

548 # Class vars should not be private attributes 

549 # We remove them _here_ and not earlier because we rely on inspecting the class to determine its classvars, 

550 # but private attributes are determined by inspecting the namespace _prior_ to class creation. 

551 # In the case that a classvar with a leading-'_' is defined via a ForwardRef (e.g., when using 

552 # `__future__.annotations`), we want to remove the private attribute which was detected _before_ we knew it 

553 # evaluated to a classvar 

554 

555 value = cls.__private_attributes__.pop(k, None) 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

556 if value is not None and value.default is not PydanticUndefined: 556 ↛ 557line 556 didn't jump to line 557 because the condition on line 556 was never true1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

557 setattr(cls, k, value.default) 

558 

559 

560def complete_model_class( 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

561 cls: type[BaseModel], 

562 config_wrapper: ConfigWrapper, 

563 ns_resolver: NsResolver, 

564 *, 

565 raise_errors: bool = True, 

566 call_on_complete_hook: bool = True, 

567 create_model_module: str | None = None, 

568) -> bool: 

569 """Finish building a model class. 

570 

571 This logic must be called after class has been created since validation functions must be bound 

572 and `get_type_hints` requires a class object. 

573 

574 Args: 

575 cls: BaseModel or dataclass. 

576 config_wrapper: The config wrapper instance. 

577 ns_resolver: The namespace resolver instance to use during schema building. 

578 raise_errors: Whether to raise errors. 

579 call_on_complete_hook: Whether to call the `__pydantic_on_complete__` hook. 

580 create_model_module: The module of the class to be created, if created by `create_model`. 

581 

582 Returns: 

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

584 

585 Raises: 

586 PydanticUndefinedAnnotation: If `PydanticUndefinedAnnotation` occurs in`__get_pydantic_core_schema__` 

587 and `raise_errors=True`. 

588 """ 

589 typevars_map = get_model_typevars_map(cls) 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

590 

591 if not cls.__pydantic_fields_complete__: 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

592 # Note: when coming from `ModelMetaclass.__new__()`, this results in fields being built twice. 

593 # We do so a second time here so that we can get the `NameError` for the specific undefined annotation. 

594 # Alternatively, we could let `GenerateSchema()` raise the error, but there are cases where incomplete 

595 # fields are inherited in `collect_model_fields()` and can actually have their annotation resolved in the 

596 # generate schema process. As we want to avoid having `__pydantic_fields_complete__` set to `False` 

597 # when `__pydantic_complete__` is `True`, we rebuild here: 

598 try: 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

599 cls.__pydantic_fields__ = rebuild_model_fields( 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

600 cls, 

601 config_wrapper=config_wrapper, 

602 ns_resolver=ns_resolver, 

603 typevars_map=typevars_map, 

604 ) 

605 except NameError as e: 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

606 exc = PydanticUndefinedAnnotation.from_name_error(e) 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

607 set_model_mocks(cls, f'`{exc.name}`') 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

608 if raise_errors: 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

609 raise exc from e 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

610 

611 if not raise_errors and not cls.__pydantic_fields_complete__: 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

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

613 return False 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

614 

615 assert cls.__pydantic_fields_complete__ 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

616 

617 gen_schema = GenerateSchema( 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

618 config_wrapper, 

619 ns_resolver, 

620 typevars_map, 

621 ) 

622 

623 try: 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

624 schema = gen_schema.generate_schema(cls) 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

625 except PydanticUndefinedAnnotation as e: 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

626 if raise_errors: 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

627 raise 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

628 set_model_mocks(cls, f'`{e.name}`') 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

629 return False 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

630 

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

632 

633 try: 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

634 schema = gen_schema.clean_schema(schema) 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

635 except InvalidSchemaError: 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

636 set_model_mocks(cls) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

637 return False 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

638 

639 # This needs to happen *after* model schema generation, as the return type 

640 # of the properties are evaluated and the `ComputedFieldInfo` are recreated: 

641 cls.__pydantic_computed_fields__ = {k: v.info for k, v in cls.__pydantic_decorators__.computed_fields.items()} 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

642 

643 set_deprecated_descriptors(cls) 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

644 

645 cls.__pydantic_core_schema__ = schema 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

646 

647 cls.__pydantic_validator__ = create_schema_validator( 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

648 schema, 

649 cls, 

650 create_model_module or cls.__module__, 

651 cls.__qualname__, 

652 'create_model' if create_model_module else 'BaseModel', 

653 core_config, 

654 config_wrapper.plugin_settings, 

655 ) 

656 cls.__pydantic_serializer__ = SchemaSerializer(schema, core_config) 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

657 

658 # set __signature__ attr only for model class, but not for its instances 

659 # (because instances can define `__call__`, and `inspect.signature` shouldn't 

660 # use the `__signature__` attribute and instead generate from `__call__`). 

661 cls.__signature__ = LazyClassAttribute( 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

662 '__signature__', 

663 partial( 

664 generate_pydantic_signature, 

665 init=cls.__init__, 

666 fields=cls.__pydantic_fields__, 

667 validate_by_name=config_wrapper.validate_by_name, 

668 extra=config_wrapper.extra, 

669 ), 

670 ) 

671 

672 cls.__pydantic_complete__ = True 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

673 

674 if call_on_complete_hook: 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

675 cls.__pydantic_on_complete__() 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

676 

677 return True 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

678 

679 

680def set_deprecated_descriptors(cls: type[BaseModel]) -> None: 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

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

682 for field, field_info in cls.__pydantic_fields__.items(): 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

683 if (msg := field_info.deprecation_message) is not None: 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

684 desc = _DeprecatedFieldDescriptor(msg) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

685 desc.__set_name__(cls, field) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

686 setattr(cls, field, desc) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

687 

688 for field, computed_field_info in cls.__pydantic_computed_fields__.items(): 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

689 if ( 1adghbicl

690 (msg := computed_field_info.deprecation_message) is not None 

691 # Avoid having two warnings emitted: 

692 and not hasattr(unwrap_wrapped_function(computed_field_info.wrapped_property), '__deprecated__') 

693 ): 

694 desc = _DeprecatedFieldDescriptor(msg, computed_field_info.wrapped_property) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

695 desc.__set_name__(cls, field) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

696 setattr(cls, field, desc) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

697 

698 

699class _DeprecatedFieldDescriptor: 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

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

701 

702 Attributes: 

703 msg: The deprecation message to be emitted. 

704 wrapped_property: The property instance if the deprecated field is a computed field, or `None`. 

705 field_name: The name of the field being deprecated. 

706 """ 

707 

708 field_name: str 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

709 

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

711 self.msg = msg 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

712 self.wrapped_property = wrapped_property 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

713 

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

715 self.field_name = name 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

716 

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

718 if obj is None: 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

719 if self.wrapped_property is not None: 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

720 return self.wrapped_property.__get__(None, obj_type) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

721 raise AttributeError(self.field_name) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

722 

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

724 

725 if self.wrapped_property is not None: 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

726 return self.wrapped_property.__get__(obj, obj_type) 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

727 return obj.__dict__[self.field_name] 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

728 

729 # Defined to make it a data descriptor and take precedence over the instance's dictionary. 

730 # Note that it will not be called when setting a value on a model instance 

731 # as `BaseModel.__setattr__` is defined and takes priority. 

732 def __set__(self, obj: Any, value: Any) -> NoReturn: 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

733 raise AttributeError(self.field_name) 

734 

735 

736class _PydanticWeakRef: 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

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

738 

739 Cloudpickle fails to serialize `weakref.ref` objects due to an arcane error related 

740 to abstract base classes (`abc.ABC`). This class works around the issue by wrapping 

741 `weakref.ref` instead of subclassing it. 

742 

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

744 

745 Semantics: 

746 - If not pickled, behaves the same as a `weakref.ref`. 

747 - If pickled along with the referenced object, the same `weakref.ref` behavior 

748 will be maintained between them after unpickling. 

749 - If pickled without the referenced object, after unpickling the underlying 

750 reference will be cleared (`__call__` will always return `None`). 

751 """ 

752 

753 def __init__(self, obj: Any): 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

754 if obj is None: 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

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

756 # had lost its underlying object. 

757 self._wr = None 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

758 else: 

759 self._wr = weakref.ref(obj) 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

760 

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

762 if self._wr is None: 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

763 return None 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

764 else: 

765 return self._wr() 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

766 

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

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

769 

770 

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

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

773 

774 We can't just use a WeakValueDictionary because many types (including int, str, etc.) can't be stored as values 

775 in a WeakValueDictionary. 

776 

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

778 """ 

779 if d is None: 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

780 return None 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

781 result = {} 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

782 for k, v in d.items(): 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

783 try: 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

784 proxy = _PydanticWeakRef(v) 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

785 except TypeError: 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

786 proxy = v 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

787 result[k] = proxy 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

788 return result 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

789 

790 

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

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

793 if d is None: 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

794 return None 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

795 

796 result = {} 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

797 for k, v in d.items(): 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

798 if isinstance(v, _PydanticWeakRef): 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

799 v = v() 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

800 if v is not None: 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

801 result[k] = v 1adeofpqArBCghbijsktuDvEFclmwnxyGzHI

802 else: 

803 result[k] = v 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

804 return result 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

805 

806 

807@cache 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

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

809 from ..fields import ComputedFieldInfo 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

810 

811 ignored_types = [ 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI

812 FunctionType, 

813 property, 

814 classmethod, 

815 staticmethod, 

816 PydanticDescriptorProxy, 

817 ComputedFieldInfo, 

818 TypeAliasType, # from `typing_extensions` 

819 ] 

820 

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

822 ignored_types.append(typing.TypeAliasType) 1qArBCuDvEFMNOPyGzHI

823 

824 return tuple(ignored_types) 1adeofpqArBCghbijsktuDvEFJKLMNOPclmwnxyGzHI