Coverage for pydantic/_internal/_fields.py: 98.79%

264 statements  

« prev     ^ index     » next       coverage.py v7.9.1, created at 2025-07-01 21:48 +0000

1"""Private logic related to fields (the `Field()` function and `FieldInfo` class), and arguments to `Annotated`.""" 

2 

3from __future__ import annotations as _annotations 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

4 

5import dataclasses 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

6import warnings 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

7from collections.abc import Mapping 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

8from copy import copy 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

9from functools import cache 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

10from inspect import Parameter, ismethoddescriptor, signature 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

11from re import Pattern 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

12from typing import TYPE_CHECKING, Any, Callable, TypeVar 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

13 

14from pydantic_core import PydanticUndefined 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

15from typing_extensions import TypeIs, get_origin 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

16from typing_inspection import typing_objects 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

17from typing_inspection.introspection import AnnotationSource 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

18 

19from pydantic import PydanticDeprecatedSince211 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

20from pydantic.errors import PydanticUserError 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

21 

22from ..aliases import AliasGenerator 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

23from . import _generics, _typing_extra 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

24from ._config import ConfigWrapper 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

25from ._docs_extraction import extract_docstrings_from_cls 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

26from ._import_utils import import_cached_base_model, import_cached_field_info 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

27from ._namespace_utils import NsResolver 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

28from ._repr import Representation 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

29from ._utils import can_be_positional, get_first_not_none 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

30 

31if TYPE_CHECKING: 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

32 from annotated_types import BaseMetadata 

33 

34 from ..fields import FieldInfo 

35 from ..main import BaseModel 

36 from ._dataclasses import PydanticDataclass, StandardDataclass 

37 from ._decorators import DecoratorInfos 

38 

39 

40class PydanticMetadata(Representation): 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

41 """Base class for annotation markers like `Strict`.""" 

42 

43 __slots__ = () 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

44 

45 

46def pydantic_general_metadata(**metadata: Any) -> BaseMetadata: 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

47 """Create a new `_PydanticGeneralMetadata` class with the given metadata. 

48 

49 Args: 

50 **metadata: The metadata to add. 

51 

52 Returns: 

53 The new `_PydanticGeneralMetadata` class. 

54 """ 

55 return _general_metadata_cls()(metadata) # type: ignore 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

56 

57 

58@cache 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

59def _general_metadata_cls() -> type[BaseMetadata]: 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

60 """Do it this way to avoid importing `annotated_types` at import time.""" 

61 from annotated_types import BaseMetadata 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

62 

63 class _PydanticGeneralMetadata(PydanticMetadata, BaseMetadata): 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

64 """Pydantic general metadata like `max_digits`.""" 

65 

66 def __init__(self, metadata: Any): 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

67 self.__dict__ = metadata 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

68 

69 return _PydanticGeneralMetadata # type: ignore 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

70 

71 

72def _check_protected_namespaces( 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

73 protected_namespaces: tuple[str | Pattern[str], ...], 

74 ann_name: str, 

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

76 cls_name: str, 

77) -> None: 

78 BaseModel = import_cached_base_model() 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

79 

80 for protected_namespace in protected_namespaces: 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

81 ns_violation = False 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

82 if isinstance(protected_namespace, Pattern): 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

83 ns_violation = protected_namespace.match(ann_name) is not None 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

84 elif isinstance(protected_namespace, str): 84 ↛ 87line 84 didn't jump to line 87 because the condition on line 84 was always true1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

85 ns_violation = ann_name.startswith(protected_namespace) 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

86 

87 if ns_violation: 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

88 for b in bases: 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

89 if hasattr(b, ann_name): 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

90 if not (issubclass(b, BaseModel) and ann_name in getattr(b, '__pydantic_fields__', {})): 90 ↛ 88line 90 didn't jump to line 88 because the condition on line 90 was always true1abcghdefij

91 raise ValueError( 1abcghdefij

92 f'Field {ann_name!r} conflicts with member {getattr(b, ann_name)}' 

93 f' of protected namespace {protected_namespace!r}.' 

94 ) 

95 else: 

96 valid_namespaces: list[str] = [] 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

97 for pn in protected_namespaces: 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

98 if isinstance(pn, Pattern): 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

99 if not pn.match(ann_name): 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

100 valid_namespaces.append(f're.compile({pn.pattern!r})') 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

101 else: 

102 if not ann_name.startswith(pn): 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

103 valid_namespaces.append(f"'{pn}'") 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

104 

105 valid_namespaces_str = f'({", ".join(valid_namespaces)}{",)" if len(valid_namespaces) == 1 else ")"}' 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

106 

107 warnings.warn( 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

108 f'Field {ann_name!r} in {cls_name!r} conflicts with protected namespace {protected_namespace!r}.\n\n' 

109 f"You may be able to solve this by setting the 'protected_namespaces' configuration to {valid_namespaces_str}.", 

110 UserWarning, 

111 stacklevel=5, 

112 ) 

113 

114 

115def _update_fields_from_docstrings(cls: type[Any], fields: dict[str, FieldInfo], use_inspect: bool = False) -> None: 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

116 fields_docs = extract_docstrings_from_cls(cls, use_inspect=use_inspect) 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

117 for ann_name, field_info in fields.items(): 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

118 if field_info.description is None and ann_name in fields_docs: 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

119 field_info.description = fields_docs[ann_name] 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

120 

121 

122def _apply_field_title_generator_to_field_info( 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

123 title_generator: Callable[[str, FieldInfo], str], 

124 field_name: str, 

125 field_info: FieldInfo, 

126): 

127 if field_info.title is None: 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

128 title = title_generator(field_name, field_info) 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

129 if not isinstance(title, str): 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

130 raise TypeError(f'field_title_generator {title_generator} must return str, not {title.__class__}') 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

131 

132 field_info.title = title 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

133 

134 

135def _apply_alias_generator_to_field_info( 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

136 alias_generator: Callable[[str], str] | AliasGenerator, field_name: str, field_info: FieldInfo 

137): 

138 """Apply an alias generator to aliases on a `FieldInfo` instance if appropriate. 

139 

140 Args: 

141 alias_generator: A callable that takes a string and returns a string, or an `AliasGenerator` instance. 

142 field_name: The name of the field from which to generate the alias. 

143 field_info: The `FieldInfo` instance to which the alias generator is (maybe) applied. 

144 """ 

145 # Apply an alias_generator if 

146 # 1. An alias is not specified 

147 # 2. An alias is specified, but the priority is <= 1 

148 if ( 1akIznodt

149 field_info.alias_priority is None 

150 or field_info.alias_priority <= 1 

151 or field_info.alias is None 

152 or field_info.validation_alias is None 

153 or field_info.serialization_alias is None 

154 ): 

155 alias, validation_alias, serialization_alias = None, None, None 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

156 

157 if isinstance(alias_generator, AliasGenerator): 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

158 alias, validation_alias, serialization_alias = alias_generator.generate_aliases(field_name) 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

159 elif callable(alias_generator): 159 ↛ 167line 159 didn't jump to line 167 because the condition on line 159 was always true1akblcmgwhxyIznopqrsABCDEdteufviFjGH

160 alias = alias_generator(field_name) 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

161 if not isinstance(alias, str): 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

162 raise TypeError(f'alias_generator {alias_generator} must return str, not {alias.__class__}') 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

163 

164 # if priority is not set, we set to 1 

165 # which supports the case where the alias_generator from a child class is used 

166 # to generate an alias for a field in a parent class 

167 if field_info.alias_priority is None or field_info.alias_priority <= 1: 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

168 field_info.alias_priority = 1 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

169 

170 # if the priority is 1, then we set the aliases to the generated alias 

171 if field_info.alias_priority == 1: 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

172 field_info.serialization_alias = get_first_not_none(serialization_alias, alias) 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

173 field_info.validation_alias = get_first_not_none(validation_alias, alias) 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

174 field_info.alias = alias 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

175 

176 # if any of the aliases are not set, then we set them to the corresponding generated alias 

177 if field_info.alias is None: 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

178 field_info.alias = alias 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

179 if field_info.serialization_alias is None: 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

180 field_info.serialization_alias = get_first_not_none(serialization_alias, alias) 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

181 if field_info.validation_alias is None: 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

182 field_info.validation_alias = get_first_not_none(validation_alias, alias) 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

183 

184 

185def update_field_from_config(config_wrapper: ConfigWrapper, field_name: str, field_info: FieldInfo) -> None: 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

186 """Update the `FieldInfo` instance from the configuration set on the model it belongs to. 

187 

188 This will apply the title and alias generators from the configuration. 

189 

190 Args: 

191 config_wrapper: The configuration from the model. 

192 field_name: The field name the `FieldInfo` instance is attached to. 

193 field_info: The `FieldInfo` instance to update. 

194 """ 

195 field_title_generator = field_info.field_title_generator or config_wrapper.field_title_generator 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

196 if field_title_generator is not None: 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

197 _apply_field_title_generator_to_field_info(field_title_generator, field_name, field_info) 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

198 if config_wrapper.alias_generator is not None: 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

199 _apply_alias_generator_to_field_info(config_wrapper.alias_generator, field_name, field_info) 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

200 

201 

202_deprecated_method_names = {'dict', 'json', 'copy', '_iter', '_copy_and_set_values', '_calculate_keys'} 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

203 

204_deprecated_classmethod_names = { 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

205 'parse_obj', 

206 'parse_raw', 

207 'parse_file', 

208 'from_orm', 

209 'construct', 

210 'schema', 

211 'schema_json', 

212 'validate', 

213 'update_forward_refs', 

214 '_get_value', 

215} 

216 

217 

218def collect_model_fields( # noqa: C901 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

219 cls: type[BaseModel], 

220 config_wrapper: ConfigWrapper, 

221 ns_resolver: NsResolver | None, 

222 *, 

223 typevars_map: Mapping[TypeVar, Any] | None = None, 

224) -> tuple[dict[str, FieldInfo], set[str]]: 

225 """Collect the fields and class variables names of a nascent Pydantic model. 

226 

227 The fields collection process is *lenient*, meaning it won't error if string annotations 

228 fail to evaluate. If this happens, the original annotation (and assigned value, if any) 

229 is stored on the created `FieldInfo` instance. 

230 

231 The `rebuild_model_fields()` should be called at a later point (e.g. when rebuilding the model), 

232 and will make use of these stored attributes. 

233 

234 Args: 

235 cls: BaseModel or dataclass. 

236 config_wrapper: The config wrapper instance. 

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

238 typevars_map: A dictionary mapping type variables to their concrete types. 

239 

240 Returns: 

241 A two-tuple containing model fields and class variables names. 

242 

243 Raises: 

244 NameError: 

245 - If there is a conflict between a field name and protected namespaces. 

246 - If there is a field other than `root` in `RootModel`. 

247 - If a field shadows an attribute in the parent model. 

248 """ 

249 FieldInfo_ = import_cached_field_info() 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

250 BaseModel_ = import_cached_base_model() 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

251 

252 bases = cls.__bases__ 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

253 parent_fields_lookup: dict[str, FieldInfo] = {} 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

254 for base in reversed(bases): 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

255 if model_fields := getattr(base, '__pydantic_fields__', None): 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

256 parent_fields_lookup.update(model_fields) 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

257 

258 type_hints = _typing_extra.get_model_type_hints(cls, ns_resolver=ns_resolver) 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

259 

260 # https://docs.python.org/3/howto/annotations.html#accessing-the-annotations-dict-of-an-object-in-python-3-9-and-older 

261 # annotations is only used for finding fields in parent classes 

262 annotations = cls.__dict__.get('__annotations__', {}) 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

263 fields: dict[str, FieldInfo] = {} 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

264 

265 class_vars: set[str] = set() 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

266 for ann_name, (ann_type, evaluated) in type_hints.items(): 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

267 if ann_name == 'model_config': 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

268 # We never want to treat `model_config` as a field 

269 # Note: we may need to change this logic if/when we introduce a `BareModel` class with no 

270 # protected namespaces (where `model_config` might be allowed as a field name) 

271 continue 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

272 

273 _check_protected_namespaces( 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

274 protected_namespaces=config_wrapper.protected_namespaces, 

275 ann_name=ann_name, 

276 bases=bases, 

277 cls_name=cls.__name__, 

278 ) 

279 

280 if _typing_extra.is_classvar_annotation(ann_type): 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

281 class_vars.add(ann_name) 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

282 continue 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

283 

284 assigned_value = getattr(cls, ann_name, PydanticUndefined) 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

285 if assigned_value is not PydanticUndefined and ( 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

286 # One of the deprecated instance methods was used as a field name (e.g. `dict()`): 

287 any(getattr(BaseModel_, depr_name, None) is assigned_value for depr_name in _deprecated_method_names) 

288 # One of the deprecated class methods was used as a field name (e.g. `schema()`): 

289 or ( 

290 hasattr(assigned_value, '__func__') 

291 and any( 

292 getattr(getattr(BaseModel_, depr_name, None), '__func__', None) is assigned_value.__func__ # pyright: ignore[reportAttributeAccessIssue] 

293 for depr_name in _deprecated_classmethod_names 

294 ) 

295 ) 

296 ): 

297 # Then `assigned_value` would be the method, even though no default was specified: 

298 assigned_value = PydanticUndefined 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

299 

300 if not is_valid_field_name(ann_name): 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

301 continue 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

302 if cls.__pydantic_root_model__ and ann_name != 'root': 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

303 raise NameError( 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

304 f"Unexpected field with name {ann_name!r}; only 'root' is allowed as a field of a `RootModel`" 

305 ) 

306 

307 # when building a generic model with `MyModel[int]`, the generic_origin check makes sure we don't get 

308 # "... shadows an attribute" warnings 

309 generic_origin = getattr(cls, '__pydantic_generic_metadata__', {}).get('origin') 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

310 for base in bases: 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

311 dataclass_fields = { 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

312 field.name for field in (dataclasses.fields(base) if dataclasses.is_dataclass(base) else ()) 

313 } 

314 if hasattr(base, ann_name): 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

315 if base is generic_origin: 315 ↛ 317line 315 didn't jump to line 317 because the condition on line 315 was never true1akblcmgwhxyIznopqrsABCDEdteufviFjGH

316 # Don't warn when "shadowing" of attributes in parametrized generics 

317 continue 

318 

319 if ann_name in dataclass_fields: 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

320 # Don't warn when inheriting stdlib dataclasses whose fields are "shadowed" by defaults being set 

321 # on the class instance. 

322 continue 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

323 

324 if ann_name not in annotations: 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

325 # Don't warn when a field exists in a parent class but has not been defined in the current class 

326 continue 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

327 

328 warnings.warn( 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

329 f'Field name "{ann_name}" in "{cls.__qualname__}" shadows an attribute in parent ' 

330 f'"{base.__qualname__}"', 

331 UserWarning, 

332 ) 

333 

334 if assigned_value is PydanticUndefined: # no assignment, just a plain annotation 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

335 if ann_name in annotations or ann_name not in parent_fields_lookup: 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

336 # field is either: 

337 # - present in the current model's annotations (and *not* from parent classes) 

338 # - not found on any base classes; this seems to be caused by fields bot getting 

339 # generated due to models not being fully defined while initializing recursive models. 

340 # Nothing stops us from just creating a `FieldInfo` for this type hint, so we do this. 

341 field_info = FieldInfo_.from_annotation(ann_type, _source=AnnotationSource.CLASS) 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

342 if not evaluated: 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

343 field_info._complete = False 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

344 # Store the original annotation that should be used to rebuild 

345 # the field info later: 

346 field_info._original_annotation = ann_type 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

347 else: 

348 # The field was present on one of the (possibly multiple) base classes 

349 # copy the field to make sure typevar substitutions don't cause issues with the base classes 

350 field_info = copy(parent_fields_lookup[ann_name]) 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

351 

352 else: # An assigned value is present (either the default value, or a `Field()` function) 

353 _warn_on_nested_alias_in_annotation(ann_type, ann_name) 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

354 if isinstance(assigned_value, FieldInfo_) and ismethoddescriptor(assigned_value.default): 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

355 # `assigned_value` was fetched using `getattr`, which triggers a call to `__get__` 

356 # for descriptors, so we do the same if the `= field(default=...)` form is used. 

357 # Note that we only do this for method descriptors for now, we might want to 

358 # extend this to any descriptor in the future (by simply checking for 

359 # `hasattr(assigned_value.default, '__get__')`). 

360 default = assigned_value.default.__get__(None, cls) 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

361 assigned_value.default = default 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

362 assigned_value._attributes_set['default'] = default 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

363 

364 field_info = FieldInfo_.from_annotated_attribute(ann_type, assigned_value, _source=AnnotationSource.CLASS) 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

365 # Store the original annotation and assignment value that should be used to rebuild the field info later. 

366 # Note that the assignment is always stored as the annotation might contain a type var that is later 

367 # parameterized with an unknown forward reference (and we'll need it to rebuild the field info): 

368 field_info._original_assignment = assigned_value 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

369 if not evaluated: 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

370 field_info._complete = False 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

371 field_info._original_annotation = ann_type 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

372 elif 'final' in field_info._qualifiers and not field_info.is_required(): 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

373 warnings.warn( 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

374 f'Annotation {ann_name!r} is marked as final and has a default value. Pydantic treats {ann_name!r} as a ' 

375 'class variable, but it will be considered as a normal field in V3 to be aligned with dataclasses. If you ' 

376 f'still want {ann_name!r} to be considered as a class variable, annotate it as: `ClassVar[<type>] = <default>.`', 

377 category=PydanticDeprecatedSince211, 

378 # Incorrect when `create_model` is used, but the chance that final with a default is used is low in that case: 

379 stacklevel=4, 

380 ) 

381 class_vars.add(ann_name) 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

382 continue 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

383 

384 # attributes which are fields are removed from the class namespace: 

385 # 1. To match the behaviour of annotation-only fields 

386 # 2. To avoid false positives in the NameError check above 

387 try: 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

388 delattr(cls, ann_name) 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

389 except AttributeError: 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

390 pass # indicates the attribute was on a parent class 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

391 

392 # Use cls.__dict__['__pydantic_decorators__'] instead of cls.__pydantic_decorators__ 

393 # to make sure the decorators have already been built for this exact class 

394 decorators: DecoratorInfos = cls.__dict__['__pydantic_decorators__'] 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

395 if ann_name in decorators.computed_fields: 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

396 raise TypeError( 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

397 f'Field {ann_name!r} of class {cls.__name__!r} overrides symbol of same name in a parent class. ' 

398 'This override with a computed_field is incompatible.' 

399 ) 

400 fields[ann_name] = field_info 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

401 

402 if field_info._complete: 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

403 # If not complete, this will be called in `rebuild_model_fields()`: 

404 update_field_from_config(config_wrapper, ann_name, field_info) 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

405 

406 if typevars_map: 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

407 for field in fields.values(): 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

408 if field._complete: 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

409 field.apply_typevars_map(typevars_map) 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

410 

411 if config_wrapper.use_attribute_docstrings: 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

412 _update_fields_from_docstrings(cls, fields) 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

413 return fields, class_vars 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

414 

415 

416def _warn_on_nested_alias_in_annotation(ann_type: type[Any], ann_name: str) -> None: 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

417 FieldInfo = import_cached_field_info() 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

418 

419 args = getattr(ann_type, '__args__', None) 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

420 if args: 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

421 for anno_arg in args: 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

422 if typing_objects.is_annotated(get_origin(anno_arg)): 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

423 for anno_type_arg in _typing_extra.get_args(anno_arg): 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

424 if isinstance(anno_type_arg, FieldInfo) and anno_type_arg.alias is not None: 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

425 warnings.warn( 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

426 f'`alias` specification on field "{ann_name}" must be set on outermost annotation to take effect.', 

427 UserWarning, 

428 ) 

429 return 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

430 

431 

432def rebuild_model_fields( 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

433 cls: type[BaseModel], 

434 *, 

435 config_wrapper: ConfigWrapper, 

436 ns_resolver: NsResolver, 

437 typevars_map: Mapping[TypeVar, Any], 

438) -> dict[str, FieldInfo]: 

439 """Rebuild the (already present) model fields by trying to reevaluate annotations. 

440 

441 This function should be called whenever a model with incomplete fields is encountered. 

442 

443 Raises: 

444 NameError: If one of the annotations failed to evaluate. 

445 

446 Note: 

447 This function *doesn't* mutate the model fields in place, as it can be called during 

448 schema generation, where you don't want to mutate other model's fields. 

449 """ 

450 FieldInfo_ = import_cached_field_info() 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

451 

452 rebuilt_fields: dict[str, FieldInfo] = {} 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

453 with ns_resolver.push(cls): 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

454 for f_name, field_info in cls.__pydantic_fields__.items(): 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

455 if field_info._complete: 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

456 rebuilt_fields[f_name] = field_info 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

457 else: 

458 existing_desc = field_info.description 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

459 ann = _typing_extra.eval_type( 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

460 field_info._original_annotation, 

461 *ns_resolver.types_namespace, 

462 ) 

463 ann = _generics.replace_types(ann, typevars_map) 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

464 

465 if (assign := field_info._original_assignment) is PydanticUndefined: 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

466 new_field = FieldInfo_.from_annotation(ann, _source=AnnotationSource.CLASS) 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

467 else: 

468 new_field = FieldInfo_.from_annotated_attribute(ann, assign, _source=AnnotationSource.CLASS) 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

469 # The description might come from the docstring if `use_attribute_docstrings` was `True`: 

470 new_field.description = new_field.description if new_field.description is not None else existing_desc 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

471 update_field_from_config(config_wrapper, f_name, new_field) 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

472 rebuilt_fields[f_name] = new_field 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

473 

474 return rebuilt_fields 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

475 

476 

477def collect_dataclass_fields( 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

478 cls: type[StandardDataclass], 

479 *, 

480 config_wrapper: ConfigWrapper, 

481 ns_resolver: NsResolver | None = None, 

482 typevars_map: dict[Any, Any] | None = None, 

483) -> dict[str, FieldInfo]: 

484 """Collect the fields of a dataclass. 

485 

486 Args: 

487 cls: dataclass. 

488 config_wrapper: The config wrapper instance. 

489 ns_resolver: Namespace resolver to use when getting dataclass annotations. 

490 Defaults to an empty instance. 

491 typevars_map: A dictionary mapping type variables to their concrete types. 

492 

493 Returns: 

494 The dataclass fields. 

495 """ 

496 FieldInfo_ = import_cached_field_info() 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

497 

498 fields: dict[str, FieldInfo] = {} 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

499 ns_resolver = ns_resolver or NsResolver() 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

500 dataclass_fields = cls.__dataclass_fields__ 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

501 

502 # The logic here is similar to `_typing_extra.get_cls_type_hints`, 

503 # although we do it manually as stdlib dataclasses already have annotations 

504 # collected in each class: 

505 for base in reversed(cls.__mro__): 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

506 if not dataclasses.is_dataclass(base): 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

507 continue 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

508 

509 with ns_resolver.push(base): 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

510 for ann_name, dataclass_field in dataclass_fields.items(): 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

511 if ann_name not in base.__dict__.get('__annotations__', {}): 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

512 # `__dataclass_fields__`contains every field, even the ones from base classes. 

513 # Only collect the ones defined on `base`. 

514 continue 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

515 

516 globalns, localns = ns_resolver.types_namespace 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

517 ann_type, evaluated = _typing_extra.try_eval_type(dataclass_field.type, globalns, localns) 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

518 

519 if _typing_extra.is_classvar_annotation(ann_type): 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

520 continue 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

521 

522 if ( 1akblcmIznopqrsdteufv

523 not dataclass_field.init 

524 and dataclass_field.default is dataclasses.MISSING 

525 and dataclass_field.default_factory is dataclasses.MISSING 

526 ): 

527 # TODO: We should probably do something with this so that validate_assignment behaves properly 

528 # Issue: https://github.com/pydantic/pydantic/issues/5470 

529 continue 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

530 

531 if isinstance(dataclass_field.default, FieldInfo_): 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

532 if dataclass_field.default.init_var: 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

533 if dataclass_field.default.init is False: 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

534 raise PydanticUserError( 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

535 f'Dataclass field {ann_name} has init=False and init_var=True, but these are mutually exclusive.', 

536 code='clashing-init-and-init-var', 

537 ) 

538 

539 # TODO: same note as above re validate_assignment 

540 continue 1blcmgwhxyzpqrsABCDEeufviFjGH

541 field_info = FieldInfo_.from_annotated_attribute( 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

542 ann_type, dataclass_field.default, _source=AnnotationSource.DATACLASS 

543 ) 

544 field_info._original_assignment = dataclass_field.default 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

545 else: 

546 field_info = FieldInfo_.from_annotated_attribute( 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

547 ann_type, dataclass_field, _source=AnnotationSource.DATACLASS 

548 ) 

549 field_info._original_assignment = dataclass_field 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

550 

551 if not evaluated: 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

552 field_info._complete = False 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

553 field_info._original_annotation = ann_type 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

554 

555 fields[ann_name] = field_info 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

556 update_field_from_config(config_wrapper, ann_name, field_info) 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

557 

558 if field_info.default is not PydanticUndefined and isinstance( 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

559 getattr(cls, ann_name, field_info), FieldInfo_ 

560 ): 

561 # We need this to fix the default when the "default" from __dataclass_fields__ is a pydantic.FieldInfo 

562 setattr(cls, ann_name, field_info.default) 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

563 

564 if typevars_map: 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

565 for field in fields.values(): 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

566 # We don't pass any ns, as `field.annotation` 

567 # was already evaluated. TODO: is this method relevant? 

568 # Can't we juste use `_generics.replace_types`? 

569 field.apply_typevars_map(typevars_map) 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

570 

571 if config_wrapper.use_attribute_docstrings: 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

572 _update_fields_from_docstrings( 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

573 cls, 

574 fields, 

575 # We can't rely on the (more reliable) frame inspection method 

576 # for stdlib dataclasses: 

577 use_inspect=not hasattr(cls, '__is_pydantic_dataclass__'), 

578 ) 

579 

580 return fields 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

581 

582 

583def rebuild_dataclass_fields( 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

584 cls: type[PydanticDataclass], 

585 *, 

586 config_wrapper: ConfigWrapper, 

587 ns_resolver: NsResolver, 

588 typevars_map: Mapping[TypeVar, Any], 

589) -> dict[str, FieldInfo]: 

590 """Rebuild the (already present) dataclass fields by trying to reevaluate annotations. 

591 

592 This function should be called whenever a dataclass with incomplete fields is encountered. 

593 

594 Raises: 

595 NameError: If one of the annotations failed to evaluate. 

596 

597 Note: 

598 This function *doesn't* mutate the dataclass fields in place, as it can be called during 

599 schema generation, where you don't want to mutate other dataclass's fields. 

600 """ 

601 FieldInfo_ = import_cached_field_info() 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

602 

603 rebuilt_fields: dict[str, FieldInfo] = {} 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

604 with ns_resolver.push(cls): 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

605 for f_name, field_info in cls.__pydantic_fields__.items(): 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

606 if field_info._complete: 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

607 rebuilt_fields[f_name] = field_info 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

608 else: 

609 existing_desc = field_info.description 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

610 ann = _typing_extra.eval_type( 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

611 field_info._original_annotation, 

612 *ns_resolver.types_namespace, 

613 ) 

614 ann = _generics.replace_types(ann, typevars_map) 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

615 new_field = FieldInfo_.from_annotated_attribute( 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

616 ann, 

617 field_info._original_assignment, 

618 _source=AnnotationSource.DATACLASS, 

619 ) 

620 

621 # The description might come from the docstring if `use_attribute_docstrings` was `True`: 

622 new_field.description = new_field.description if new_field.description is not None else existing_desc 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

623 update_field_from_config(config_wrapper, f_name, new_field) 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

624 rebuilt_fields[f_name] = new_field 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

625 

626 return rebuilt_fields 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

627 

628 

629def is_valid_field_name(name: str) -> bool: 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

630 return not name.startswith('_') 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

631 

632 

633def is_valid_privateattr_name(name: str) -> bool: 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

634 return name.startswith('_') and not name.startswith('__') 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

635 

636 

637def takes_validated_data_argument( 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

638 default_factory: Callable[[], Any] | Callable[[dict[str, Any]], Any], 

639) -> TypeIs[Callable[[dict[str, Any]], Any]]: 

640 """Whether the provided default factory callable has a validated data parameter.""" 

641 try: 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

642 sig = signature(default_factory) 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

643 except (ValueError, TypeError): 1akblcmgwhxynopqrsABCDEdteufviFjGH

644 # `inspect.signature` might not be able to infer a signature, e.g. with C objects. 

645 # In this case, we assume no data argument is present: 

646 return False 1akblcmgwhxynopqrsABCDEdteufviFjGH

647 

648 parameters = list(sig.parameters.values()) 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH

649 

650 return len(parameters) == 1 and can_be_positional(parameters[0]) and parameters[0].default is Parameter.empty 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH