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

306 statements  

« prev     ^ index     » next       coverage.py v7.5.4, created at 2024-07-03 19:29 +0000

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

2 

3from __future__ import annotations as _annotations 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

4 

5import builtins 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

6import operator 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

7import typing 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

8import warnings 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

9import weakref 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

10from abc import ABCMeta 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

11from functools import partial 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

12from types import FunctionType 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

13from typing import Any, Callable, Generic, NoReturn 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

14 

15import typing_extensions 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

16from pydantic_core import PydanticUndefined, SchemaSerializer 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

17from typing_extensions import dataclass_transform, deprecated 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

18 

19from ..errors import PydanticUndefinedAnnotation, PydanticUserError 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

20from ..plugin._schema_validator import create_schema_validator 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

21from ..warnings import GenericBeforeBaseModelWarning, PydanticDeprecatedSince20 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

22from ._config import ConfigWrapper 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

23from ._decorators import DecoratorInfos, PydanticDescriptorProxy, get_attribute_from_bases, unwrap_wrapped_function 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

24from ._fields import collect_model_fields, is_valid_field_name, is_valid_privateattr_name 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

25from ._generate_schema import GenerateSchema 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

26from ._generics import PydanticGenericMetadata, get_model_typevars_map 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

27from ._mock_val_ser import set_model_mocks 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

28from ._schema_generation_shared import CallbackGetCoreSchemaHandler 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

29from ._signature import generate_pydantic_signature 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

30from ._typing_extra import get_cls_types_namespace, is_annotated, is_classvar, parent_frame_namespace 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

31from ._utils import ClassAttribute, SafeGetItemProxy 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

32from ._validate_call import ValidateCallWrapper 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

33 

34if typing.TYPE_CHECKING: 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

35 from ..fields import Field as PydanticModelField 

36 from ..fields import FieldInfo, ModelPrivateAttr 

37 from ..fields import PrivateAttr as PydanticModelPrivateAttr 

38 from ..main import BaseModel 

39else: 

40 # See PyCharm issues https://youtrack.jetbrains.com/issue/PY-21915 

41 # and https://youtrack.jetbrains.com/issue/PY-51428 

42 DeprecationWarning = PydanticDeprecatedSince20 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

43 PydanticModelField = object() 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

44 PydanticModelPrivateAttr = object() 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

45 

46object_setattr = object.__setattr__ 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

47 

48 

49class _ModelNamespaceDict(dict): 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

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

51 warns about overriding of decorators. 

52 """ 

53 

54 def __setitem__(self, k: str, v: object) -> None: 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

55 existing: Any = self.get(k, None) 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

56 if existing and v is not existing and isinstance(existing, PydanticDescriptorProxy): 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

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

58 

59 return super().__setitem__(k, v) 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

60 

61 

62@dataclass_transform(kw_only_default=True, field_specifiers=(PydanticModelField, PydanticModelPrivateAttr)) 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

63class ModelMetaclass(ABCMeta): 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

64 def __new__( 1abcdmnopABCDefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

65 mcs, 

66 cls_name: str, 

67 bases: tuple[type[Any], ...], 

68 namespace: dict[str, Any], 

69 __pydantic_generic_metadata__: PydanticGenericMetadata | None = None, 

70 __pydantic_reset_parent_namespace__: bool = True, 

71 _create_model_module: str | None = None, 

72 **kwargs: Any, 

73 ) -> type: 

74 """Metaclass for creating Pydantic models. 

75 

76 Args: 

77 cls_name: The name of the class to be created. 

78 bases: The base classes of the class to be created. 

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

80 __pydantic_generic_metadata__: Metadata for generic models. 

81 __pydantic_reset_parent_namespace__: Reset parent namespace. 

82 _create_model_module: The module of the class to be created, if created by `create_model`. 

83 **kwargs: Catch-all for any other keyword arguments. 

84 

85 Returns: 

86 The new class created by the metaclass. 

87 """ 

88 # Note `ModelMetaclass` refers to `BaseModel`, but is also used to *create* `BaseModel`, so we rely on the fact 

89 # that `BaseModel` itself won't have any bases, but any subclass of it will, to determine whether the `__new__` 

90 # call we're in the middle of is for the `BaseModel` class. 

91 if bases: 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

92 base_field_names, class_vars, base_private_attributes = mcs._collect_bases_data(bases) 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

93 

94 config_wrapper = ConfigWrapper.for_model(bases, namespace, kwargs) 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

95 namespace['model_config'] = config_wrapper.config_dict 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

96 private_attributes = inspect_namespace( 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

97 namespace, config_wrapper.ignored_types, class_vars, base_field_names 

98 ) 

99 if private_attributes or base_private_attributes: 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

100 original_model_post_init = get_model_post_init(namespace, bases) 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

101 if original_model_post_init is not None: 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

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

103 

104 def wrapped_model_post_init(self: BaseModel, context: Any, /) -> None: 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

105 """We need to both initialize private attributes and call the user-defined model_post_init 

106 method. 

107 """ 

108 init_private_attributes(self, context) 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

109 original_model_post_init(self, context) 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

110 

111 namespace['model_post_init'] = wrapped_model_post_init 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

112 else: 

113 namespace['model_post_init'] = init_private_attributes 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

114 

115 namespace['__class_vars__'] = class_vars 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

116 namespace['__private_attributes__'] = {**base_private_attributes, **private_attributes} 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

117 

118 cls: type[BaseModel] = super().__new__(mcs, cls_name, bases, namespace, **kwargs) # type: ignore 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

119 

120 from ..main import BaseModel 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

121 

122 mro = cls.__mro__ 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

123 if Generic in mro and mro.index(Generic) < mro.index(BaseModel): 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

124 warnings.warn( 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

125 GenericBeforeBaseModelWarning( 

126 'Classes should inherit from `BaseModel` before generic classes (e.g. `typing.Generic[T]`) ' 

127 'for pydantic generics to work properly.' 

128 ), 

129 stacklevel=2, 

130 ) 

131 

132 cls.__pydantic_custom_init__ = not getattr(cls.__init__, '__pydantic_base_init__', False) 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

133 cls.__pydantic_post_init__ = None if cls.model_post_init is BaseModel.model_post_init else 'model_post_init' 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

134 

135 cls.__pydantic_decorators__ = DecoratorInfos.build(cls) 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

136 

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

138 if __pydantic_generic_metadata__: 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

139 cls.__pydantic_generic_metadata__ = __pydantic_generic_metadata__ 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

140 else: 

141 parent_parameters = getattr(cls, '__pydantic_generic_metadata__', {}).get('parameters', ()) 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

142 parameters = getattr(cls, '__parameters__', None) or parent_parameters 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

143 if parameters and parent_parameters and not all(x in parameters for x in parent_parameters): 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

144 from ..root_model import RootModelRootType 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

145 

146 missing_parameters = tuple(x for x in parameters if x not in parent_parameters) 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

147 if RootModelRootType in parent_parameters and RootModelRootType not in parameters: 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

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

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

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

151 # root: T 

152 # Should instead just be: 

153 # class MyModel(RootModel[T]): 

154 # root: T 

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

156 error_message = ( 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

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

158 f'{parameters_str} in its parameters. ' 

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

160 ) 

161 else: 

162 combined_parameters = parent_parameters + missing_parameters 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

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

164 generic_type_label = f'typing.Generic[{parameters_str}]' 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

165 error_message = ( 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

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

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

168 ) 

169 if Generic not in bases: # pragma: no cover 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

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

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

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

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

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

175 error_message += ( 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

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

177 ) 

178 raise TypeError(error_message) 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

179 

180 cls.__pydantic_generic_metadata__ = { 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

181 'origin': None, 

182 'args': (), 

183 'parameters': parameters, 

184 } 

185 

186 cls.__pydantic_complete__ = False # Ensure this specific class gets completed 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

187 

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

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

190 for name, obj in private_attributes.items(): 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

191 obj.__set_name__(cls, name) 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

192 

193 if __pydantic_reset_parent_namespace__: 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

194 cls.__pydantic_parent_namespace__ = build_lenient_weakvaluedict(parent_frame_namespace()) 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

195 parent_namespace = getattr(cls, '__pydantic_parent_namespace__', None) 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

196 if isinstance(parent_namespace, dict): 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

197 parent_namespace = unpack_lenient_weakvaluedict(parent_namespace) 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

198 

199 types_namespace = get_cls_types_namespace(cls, parent_namespace) 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

200 set_model_fields(cls, bases, config_wrapper, types_namespace) 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

201 

202 if config_wrapper.frozen and '__hash__' not in namespace: 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

203 set_default_hash_func(cls, bases) 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

204 

205 complete_model_class( 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

206 cls, 

207 cls_name, 

208 config_wrapper, 

209 raise_errors=False, 

210 types_namespace=types_namespace, 

211 create_model_module=_create_model_module, 

212 ) 

213 

214 # If this is placed before the complete_model_class call above, 

215 # the generic computed fields return type is set to PydanticUndefined 

216 cls.model_computed_fields = {k: v.info for k, v in cls.__pydantic_decorators__.computed_fields.items()} 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

217 

218 set_deprecated_descriptors(cls) 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

219 

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

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

222 # only hit for _proper_ subclasses of BaseModel 

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

224 return cls 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

225 else: 

226 # this is the BaseModel class itself being created, no logic required 

227 return super().__new__(mcs, cls_name, bases, namespace, **kwargs) 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

228 

229 if not typing.TYPE_CHECKING: # pragma: no branch 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

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

231 

232 def __getattr__(self, item: str) -> Any: 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

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

234 private_attributes = self.__dict__.get('__private_attributes__') 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

235 if private_attributes and item in private_attributes: 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

236 return private_attributes[item] 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

237 raise AttributeError(item) 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

238 

239 @classmethod 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

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

241 return _ModelNamespaceDict() 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

242 

243 def __instancecheck__(self, instance: Any) -> bool: 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

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

245 

246 See #3829 and python/cpython#92810 

247 """ 

248 return hasattr(instance, '__pydantic_validator__') and super().__instancecheck__(instance) 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

249 

250 @staticmethod 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

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

252 from ..main import BaseModel 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

253 

254 field_names: set[str] = set() 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

255 class_vars: set[str] = set() 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

256 private_attributes: dict[str, ModelPrivateAttr] = {} 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

257 for base in bases: 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

258 if issubclass(base, BaseModel) and base is not BaseModel: 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

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

260 field_names.update(getattr(base, 'model_fields', {}).keys()) 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

261 class_vars.update(base.__class_vars__) 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

262 private_attributes.update(base.__private_attributes__) 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

263 return field_names, class_vars, private_attributes 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

264 

265 @property 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

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

267 def __fields__(self) -> dict[str, FieldInfo]: 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

268 warnings.warn( 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

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

270 ) 

271 return self.model_fields # type: ignore 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

272 

273 def __dir__(self) -> list[str]: 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

274 attributes = list(super().__dir__()) 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

275 if '__fields__' in attributes: 275 ↛ 277line 275 didn't jump to line 277 because the condition on line 275 was always true1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

276 attributes.remove('__fields__') 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

277 return attributes 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

278 

279 

280def init_private_attributes(self: BaseModel, context: Any, /) -> None: 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

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

282 

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

284 

285 Args: 

286 self: The BaseModel instance. 

287 context: The context. 

288 """ 

289 if getattr(self, '__pydantic_private__', None) is None: 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

290 pydantic_private = {} 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

291 for name, private_attr in self.__private_attributes__.items(): 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

292 default = private_attr.get_default() 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

293 if default is not PydanticUndefined: 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

294 pydantic_private[name] = default 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

295 object_setattr(self, '__pydantic_private__', pydantic_private) 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

296 

297 

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

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

300 if 'model_post_init' in namespace: 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

301 return namespace['model_post_init'] 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

302 

303 from ..main import BaseModel 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

304 

305 model_post_init = get_attribute_from_bases(bases, 'model_post_init') 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

306 if model_post_init is not BaseModel.model_post_init: 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

307 return model_post_init 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

308 

309 

310def inspect_namespace( # noqa C901 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

311 namespace: dict[str, Any], 

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

313 base_class_vars: set[str], 

314 base_class_fields: set[str], 

315) -> dict[str, ModelPrivateAttr]: 

316 """Iterate over the namespace and: 

317 * gather private attributes 

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

319 

320 Args: 

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

322 ignored_types: A tuple of ignore types. 

323 base_class_vars: A set of base class class variables. 

324 base_class_fields: A set of base class fields. 

325 

326 Returns: 

327 A dict contains private attributes info. 

328 

329 Raises: 

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

331 NameError: If private attribute name is invalid. 

332 PydanticUserError: 

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

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

335 """ 

336 from ..fields import FieldInfo, ModelPrivateAttr, PrivateAttr 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

337 

338 all_ignored_types = ignored_types + default_ignored_types() 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

339 

340 private_attributes: dict[str, ModelPrivateAttr] = {} 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

341 raw_annotations = namespace.get('__annotations__', {}) 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

342 

343 if '__root__' in raw_annotations or '__root__' in namespace: 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

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

345 

346 ignored_names: set[str] = set() 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

347 for var_name, value in list(namespace.items()): 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

348 if var_name == 'model_config' or var_name == '__pydantic_extra__': 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

349 continue 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

350 elif ( 1abcdmnopqrefghstuvMNOPQRSTijklwxyz

351 isinstance(value, type) 

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

353 and '__qualname__' in namespace 

354 and value.__qualname__.startswith(namespace['__qualname__']) 

355 ): 

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

357 continue 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

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

359 ignored_names.add(var_name) 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

360 continue 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

361 elif isinstance(value, ModelPrivateAttr): 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

362 if var_name.startswith('__'): 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

363 raise NameError( 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

364 'Private attributes must not use dunder names;' 

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

366 ) 

367 elif is_valid_field_name(var_name): 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

368 raise NameError( 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

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

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

371 ) 

372 private_attributes[var_name] = value 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

373 del namespace[var_name] 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

374 elif isinstance(value, FieldInfo) and not is_valid_field_name(var_name): 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

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

376 raise NameError( 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

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

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

379 ) 

380 

381 elif var_name.startswith('__'): 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

382 continue 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

383 elif is_valid_privateattr_name(var_name): 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

384 if var_name not in raw_annotations or not is_classvar(raw_annotations[var_name]): 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

385 private_attributes[var_name] = PrivateAttr(default=value) 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

386 del namespace[var_name] 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

387 elif var_name in base_class_vars: 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

388 continue 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

389 elif var_name not in raw_annotations: 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

390 if var_name in base_class_fields: 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

391 raise PydanticUserError( 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

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

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

394 code='model-field-overridden', 

395 ) 

396 elif isinstance(value, FieldInfo): 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

397 raise PydanticUserError( 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

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

399 ) 

400 else: 

401 raise PydanticUserError( 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

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

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

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

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

406 ) 

407 

408 for ann_name, ann_type in raw_annotations.items(): 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

409 if ( 1abcdmnopqrefghstuvMNOPQRSTijklwxyz

410 is_valid_privateattr_name(ann_name) 

411 and ann_name not in private_attributes 

412 and ann_name not in ignored_names 

413 and not is_classvar(ann_type) 

414 and ann_type not in all_ignored_types 

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

416 ): 

417 if is_annotated(ann_type): 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

418 _, *metadata = typing_extensions.get_args(ann_type) 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

419 private_attr = next((v for v in metadata if isinstance(v, ModelPrivateAttr)), None) 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

420 if private_attr is not None: 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

421 private_attributes[ann_name] = private_attr 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

422 continue 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

423 private_attributes[ann_name] = PrivateAttr() 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

424 

425 return private_attributes 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

426 

427 

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

429 base_hash_func = get_attribute_from_bases(bases, '__hash__') 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

430 new_hash_func = make_hash_func(cls) 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

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

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

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

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

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

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

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

438 cls.__hash__ = new_hash_func 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

439 

440 

441def make_hash_func(cls: type[BaseModel]) -> Any: 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

442 getter = operator.itemgetter(*cls.model_fields.keys()) if cls.model_fields else lambda _: 0 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

443 

444 def hash_func(self: Any) -> int: 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

445 try: 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

446 return hash(getter(self.__dict__)) 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

447 except KeyError: 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

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

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

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

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

452 return hash(getter(SafeGetItemProxy(self.__dict__))) 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

453 

454 return hash_func 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

455 

456 

457def set_model_fields( 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

458 cls: type[BaseModel], bases: tuple[type[Any], ...], config_wrapper: ConfigWrapper, types_namespace: dict[str, Any] 

459) -> None: 

460 """Collect and set `cls.model_fields` and `cls.__class_vars__`. 

461 

462 Args: 

463 cls: BaseModel or dataclass. 

464 bases: Parents of the class, generally `cls.__bases__`. 

465 config_wrapper: The config wrapper instance. 

466 types_namespace: Optional extra namespace to look for types in. 

467 """ 

468 typevars_map = get_model_typevars_map(cls) 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

469 fields, class_vars = collect_model_fields(cls, bases, config_wrapper, types_namespace, typevars_map=typevars_map) 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

470 

471 cls.model_fields = fields 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

472 cls.__class_vars__.update(class_vars) 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

473 

474 for k in class_vars: 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

475 # Class vars should not be private attributes 

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

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

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

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

480 # evaluated to a classvar 

481 

482 value = cls.__private_attributes__.pop(k, None) 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

483 if value is not None and value.default is not PydanticUndefined: 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

484 setattr(cls, k, value.default) 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

485 

486 

487def complete_model_class( 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

488 cls: type[BaseModel], 

489 cls_name: str, 

490 config_wrapper: ConfigWrapper, 

491 *, 

492 raise_errors: bool = True, 

493 types_namespace: dict[str, Any] | None, 

494 create_model_module: str | None = None, 

495) -> bool: 

496 """Finish building a model class. 

497 

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

499 and `get_type_hints` requires a class object. 

500 

501 Args: 

502 cls: BaseModel or dataclass. 

503 cls_name: The model or dataclass name. 

504 config_wrapper: The config wrapper instance. 

505 raise_errors: Whether to raise errors. 

506 types_namespace: Optional extra namespace to look for types in. 

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

508 

509 Returns: 

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

511 

512 Raises: 

513 PydanticUndefinedAnnotation: If `PydanticUndefinedAnnotation` occurs in`__get_pydantic_core_schema__` 

514 and `raise_errors=True`. 

515 """ 

516 typevars_map = get_model_typevars_map(cls) 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

517 gen_schema = GenerateSchema( 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

518 config_wrapper, 

519 types_namespace, 

520 typevars_map, 

521 ) 

522 

523 handler = CallbackGetCoreSchemaHandler( 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

524 partial(gen_schema.generate_schema, from_dunder_get_core_schema=False), 

525 gen_schema, 

526 ref_mode='unpack', 

527 ) 

528 

529 if config_wrapper.defer_build and 'model' in config_wrapper.experimental_defer_build_mode: 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

530 set_model_mocks(cls, cls_name) 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

531 return False 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

532 

533 try: 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

534 schema = cls.__get_pydantic_core_schema__(cls, handler) 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

535 except PydanticUndefinedAnnotation as e: 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

536 if raise_errors: 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

537 raise 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

538 set_model_mocks(cls, cls_name, f'`{e.name}`') 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

539 return False 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

540 

541 core_config = config_wrapper.core_config(cls) 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

542 

543 try: 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

544 schema = gen_schema.clean_schema(schema) 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

545 except gen_schema.CollectedInvalid: 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

546 set_model_mocks(cls, cls_name) 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

547 return False 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

548 

549 # debug(schema) 

550 cls.__pydantic_core_schema__ = schema 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

551 

552 cls.__pydantic_validator__ = create_schema_validator( 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

553 schema, 

554 cls, 

555 create_model_module or cls.__module__, 

556 cls.__qualname__, 

557 'create_model' if create_model_module else 'BaseModel', 

558 core_config, 

559 config_wrapper.plugin_settings, 

560 ) 

561 cls.__pydantic_serializer__ = SchemaSerializer(schema, core_config) 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

562 cls.__pydantic_complete__ = True 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

563 

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

565 cls.__signature__ = ClassAttribute( 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

566 '__signature__', 

567 generate_pydantic_signature(init=cls.__init__, fields=cls.model_fields, config_wrapper=config_wrapper), 

568 ) 

569 return True 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

570 

571 

572def set_deprecated_descriptors(cls: type[BaseModel]) -> None: 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

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

574 for field, field_info in cls.model_fields.items(): 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

575 if (msg := field_info.deprecation_message) is not None: 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

576 desc = _DeprecatedFieldDescriptor(msg) 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

577 desc.__set_name__(cls, field) 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

578 setattr(cls, field, desc) 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

579 

580 for field, computed_field_info in cls.model_computed_fields.items(): 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

581 if ( 1abcdqrefghijkl

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

583 # Avoid having two warnings emitted: 

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

585 ): 

586 desc = _DeprecatedFieldDescriptor(msg, computed_field_info.wrapped_property) 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

587 desc.__set_name__(cls, field) 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

588 setattr(cls, field, desc) 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

589 

590 

591class _DeprecatedFieldDescriptor: 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

592 """Data descriptor used to emit a runtime deprecation warning before accessing a deprecated field. 

593 

594 Attributes: 

595 msg: The deprecation message to be emitted. 

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

597 field_name: The name of the field being deprecated. 

598 """ 

599 

600 field_name: str 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

601 

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

603 self.msg = msg 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

604 self.wrapped_property = wrapped_property 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

605 

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

607 self.field_name = name 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

608 

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

610 if obj is None: 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

611 raise AttributeError(self.field_name) 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

612 

613 warnings.warn(self.msg, builtins.DeprecationWarning, stacklevel=2) 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

614 

615 if self.wrapped_property is not None: 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

616 return self.wrapped_property.__get__(obj, obj_type) 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

617 return obj.__dict__[self.field_name] 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

618 

619 # Defined to take precedence over the instance's dictionary 

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

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

622 def __set__(self, obj: Any, value: Any) -> NoReturn: 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

623 raise AttributeError(self.field_name) 

624 

625 

626class _PydanticWeakRef: 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

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

628 

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

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

631 `weakref.ref` instead of subclassing it. 

632 

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

634 

635 Semantics: 

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

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

638 will be maintained between them after unpickling. 

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

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

641 """ 

642 

643 def __init__(self, obj: Any): 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

644 if obj is None: 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

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

646 # had lost its underlying object. 

647 self._wr = None 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

648 else: 

649 self._wr = weakref.ref(obj) 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

650 

651 def __call__(self) -> Any: 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

652 if self._wr is None: 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

653 return None 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

654 else: 

655 return self._wr() 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

656 

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

658 return _PydanticWeakRef, (self(),) 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

659 

660 

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

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

663 

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

665 in a WeakValueDictionary. 

666 

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

668 """ 

669 if d is None: 669 ↛ 670line 669 didn't jump to line 670 because the condition on line 669 was never true1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

670 return None 

671 result = {} 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

672 for k, v in d.items(): 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

673 try: 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

674 proxy = _PydanticWeakRef(v) 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

675 except TypeError: 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

676 proxy = v 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

677 result[k] = proxy 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

678 return result 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

679 

680 

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

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

683 if d is None: 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

684 return None 1abcdmnopABCDqrefghstuvEFGHijklwxyzIJKL

685 

686 result = {} 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

687 for k, v in d.items(): 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

688 if isinstance(v, _PydanticWeakRef): 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

689 v = v() 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

690 if v is not None: 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

691 result[k] = v 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

692 else: 

693 result[k] = v 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

694 return result 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

695 

696 

697def default_ignored_types() -> tuple[type[Any], ...]: 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

698 from ..fields import ComputedFieldInfo 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

699 

700 return ( 1abcdmnopABCDqrefghstuvEFGHMNOPQRSTUVijklwxyzIJKL

701 FunctionType, 

702 property, 

703 classmethod, 

704 staticmethod, 

705 PydanticDescriptorProxy, 

706 ComputedFieldInfo, 

707 ValidateCallWrapper, 

708 )