_fields.py 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729
  1. """Private logic related to fields (the `Field()` function and `FieldInfo` class), and arguments to `Annotated`."""
  2. from __future__ import annotations as _annotations
  3. import dataclasses
  4. import warnings
  5. from collections.abc import Mapping
  6. from functools import cache
  7. from inspect import Parameter, ismethoddescriptor
  8. from re import Pattern
  9. from typing import TYPE_CHECKING, Any, Callable, TypeVar, cast
  10. from pydantic_core import PydanticUndefined
  11. from typing_extensions import TypeIs
  12. from typing_inspection.introspection import AnnotationSource
  13. from pydantic import PydanticDeprecatedSince211
  14. from pydantic.errors import PydanticUserError
  15. from ..aliases import AliasGenerator
  16. from . import _generics, _typing_extra
  17. from ._config import ConfigWrapper
  18. from ._docs_extraction import extract_docstrings_from_cls
  19. from ._import_utils import import_cached_base_model, import_cached_field_info
  20. from ._internal_dataclass import slots_true
  21. from ._namespace_utils import NsResolver
  22. from ._repr import Representation
  23. from ._utils import can_be_positional, get_first_not_none
  24. if TYPE_CHECKING:
  25. from annotated_types import BaseMetadata
  26. from ..fields import FieldInfo
  27. from ..main import BaseModel
  28. from ._dataclasses import PydanticDataclass, StandardDataclass
  29. from ._decorators import DecoratorInfos
  30. class PydanticMetadata(Representation):
  31. """Base class for annotation markers like `Strict`."""
  32. __slots__ = ()
  33. @dataclasses.dataclass(**slots_true) # TODO: make kw_only when we drop support for 3.9.
  34. class PydanticExtraInfo:
  35. # TODO: make use of PEP 747:
  36. annotation: Any
  37. complete: bool
  38. def pydantic_general_metadata(**metadata: Any) -> BaseMetadata:
  39. """Create a new `_PydanticGeneralMetadata` class with the given metadata.
  40. Args:
  41. **metadata: The metadata to add.
  42. Returns:
  43. The new `_PydanticGeneralMetadata` class.
  44. """
  45. return _general_metadata_cls()(metadata) # type: ignore
  46. @cache
  47. def _general_metadata_cls() -> type[BaseMetadata]:
  48. """Do it this way to avoid importing `annotated_types` at import time."""
  49. from annotated_types import BaseMetadata
  50. class _PydanticGeneralMetadata(PydanticMetadata, BaseMetadata):
  51. """Pydantic general metadata like `max_digits`."""
  52. def __init__(self, metadata: Any):
  53. self.__dict__ = metadata
  54. return _PydanticGeneralMetadata # type: ignore
  55. def _check_protected_namespaces(
  56. protected_namespaces: tuple[str | Pattern[str], ...],
  57. ann_name: str,
  58. bases: tuple[type[Any], ...],
  59. cls_name: str,
  60. ) -> None:
  61. BaseModel = import_cached_base_model()
  62. for protected_namespace in protected_namespaces:
  63. ns_violation = False
  64. if isinstance(protected_namespace, Pattern):
  65. ns_violation = protected_namespace.match(ann_name) is not None
  66. elif isinstance(protected_namespace, str):
  67. ns_violation = ann_name.startswith(protected_namespace)
  68. if ns_violation:
  69. for b in bases:
  70. if hasattr(b, ann_name):
  71. if not (issubclass(b, BaseModel) and ann_name in getattr(b, '__pydantic_fields__', {})):
  72. raise ValueError(
  73. f'Field {ann_name!r} conflicts with member {getattr(b, ann_name)}'
  74. f' of protected namespace {protected_namespace!r}.'
  75. )
  76. else:
  77. valid_namespaces: list[str] = []
  78. for pn in protected_namespaces:
  79. if isinstance(pn, Pattern):
  80. if not pn.match(ann_name):
  81. valid_namespaces.append(f're.compile({pn.pattern!r})')
  82. else:
  83. if not ann_name.startswith(pn):
  84. valid_namespaces.append(f"'{pn}'")
  85. valid_namespaces_str = f'({", ".join(valid_namespaces)}{",)" if len(valid_namespaces) == 1 else ")"}'
  86. warnings.warn(
  87. f'Field {ann_name!r} in {cls_name!r} conflicts with protected namespace {protected_namespace!r}.\n\n'
  88. f"You may be able to solve this by setting the 'protected_namespaces' configuration to {valid_namespaces_str}.",
  89. UserWarning,
  90. stacklevel=5,
  91. )
  92. def _update_fields_from_docstrings(cls: type[Any], fields: dict[str, FieldInfo], use_inspect: bool = False) -> None:
  93. fields_docs = extract_docstrings_from_cls(cls, use_inspect=use_inspect)
  94. for ann_name, field_info in fields.items():
  95. if field_info.description is None and ann_name in fields_docs:
  96. field_info.description = fields_docs[ann_name]
  97. def _apply_field_title_generator_to_field_info(
  98. title_generator: Callable[[str, FieldInfo], str],
  99. field_name: str,
  100. field_info: FieldInfo,
  101. ):
  102. if field_info.title is None:
  103. title = title_generator(field_name, field_info)
  104. if not isinstance(title, str):
  105. raise TypeError(f'field_title_generator {title_generator} must return str, not {title.__class__}')
  106. field_info.title = title
  107. def _apply_alias_generator_to_field_info(
  108. alias_generator: Callable[[str], str] | AliasGenerator, field_name: str, field_info: FieldInfo
  109. ):
  110. """Apply an alias generator to aliases on a `FieldInfo` instance if appropriate.
  111. Args:
  112. alias_generator: A callable that takes a string and returns a string, or an `AliasGenerator` instance.
  113. field_name: The name of the field from which to generate the alias.
  114. field_info: The `FieldInfo` instance to which the alias generator is (maybe) applied.
  115. """
  116. # Apply an alias_generator if
  117. # 1. An alias is not specified
  118. # 2. An alias is specified, but the priority is <= 1
  119. if (
  120. field_info.alias_priority is None
  121. or field_info.alias_priority <= 1
  122. or field_info.alias is None
  123. or field_info.validation_alias is None
  124. or field_info.serialization_alias is None
  125. ):
  126. alias, validation_alias, serialization_alias = None, None, None
  127. if isinstance(alias_generator, AliasGenerator):
  128. alias, validation_alias, serialization_alias = alias_generator.generate_aliases(field_name)
  129. elif callable(alias_generator):
  130. alias = alias_generator(field_name)
  131. if not isinstance(alias, str):
  132. raise TypeError(f'alias_generator {alias_generator} must return str, not {alias.__class__}')
  133. # if priority is not set, we set to 1
  134. # which supports the case where the alias_generator from a child class is used
  135. # to generate an alias for a field in a parent class
  136. if field_info.alias_priority is None or field_info.alias_priority <= 1:
  137. field_info.alias_priority = 1
  138. # if the priority is 1, then we set the aliases to the generated alias
  139. if field_info.alias_priority == 1:
  140. field_info.serialization_alias = get_first_not_none(serialization_alias, alias)
  141. field_info.validation_alias = get_first_not_none(validation_alias, alias)
  142. field_info.alias = alias
  143. # if any of the aliases are not set, then we set them to the corresponding generated alias
  144. if field_info.alias is None:
  145. field_info.alias = alias
  146. if field_info.serialization_alias is None:
  147. field_info.serialization_alias = get_first_not_none(serialization_alias, alias)
  148. if field_info.validation_alias is None:
  149. field_info.validation_alias = get_first_not_none(validation_alias, alias)
  150. def update_field_from_config(config_wrapper: ConfigWrapper, field_name: str, field_info: FieldInfo) -> None:
  151. """Update the `FieldInfo` instance from the configuration set on the model it belongs to.
  152. This will apply the title and alias generators from the configuration.
  153. Args:
  154. config_wrapper: The configuration from the model.
  155. field_name: The field name the `FieldInfo` instance is attached to.
  156. field_info: The `FieldInfo` instance to update.
  157. """
  158. field_title_generator = field_info.field_title_generator or config_wrapper.field_title_generator
  159. if field_title_generator is not None:
  160. _apply_field_title_generator_to_field_info(field_title_generator, field_name, field_info)
  161. if config_wrapper.alias_generator is not None:
  162. _apply_alias_generator_to_field_info(config_wrapper.alias_generator, field_name, field_info)
  163. _deprecated_method_names = {'dict', 'json', 'copy', '_iter', '_copy_and_set_values', '_calculate_keys'}
  164. _deprecated_classmethod_names = {
  165. 'parse_obj',
  166. 'parse_raw',
  167. 'parse_file',
  168. 'from_orm',
  169. 'construct',
  170. 'schema',
  171. 'schema_json',
  172. 'validate',
  173. 'update_forward_refs',
  174. '_get_value',
  175. }
  176. def collect_model_fields( # noqa: C901
  177. cls: type[BaseModel],
  178. config_wrapper: ConfigWrapper,
  179. ns_resolver: NsResolver,
  180. *,
  181. typevars_map: Mapping[TypeVar, Any] | None = None,
  182. ) -> tuple[dict[str, FieldInfo], PydanticExtraInfo | None, set[str]]:
  183. """Collect the fields and class variables names of a nascent Pydantic model.
  184. The fields collection process is *lenient*, meaning it won't error if string annotations
  185. fail to evaluate. If this happens, the original annotation (and assigned value, if any)
  186. is stored on the created `FieldInfo` instance.
  187. The `rebuild_model_fields()` should be called at a later point (e.g. when rebuilding the model),
  188. and will make use of these stored attributes.
  189. Args:
  190. cls: BaseModel or dataclass.
  191. config_wrapper: The config wrapper instance.
  192. ns_resolver: Namespace resolver to use when getting model annotations.
  193. typevars_map: A dictionary mapping type variables to their concrete types.
  194. Returns:
  195. A three-tuple containing the model fields, the `PydanticExtraInfo` instance if the `__pydantic_extra__` annotation is set,
  196. and class variables names.
  197. Raises:
  198. NameError:
  199. - If there is a conflict between a field name and protected namespaces.
  200. - If there is a field other than `root` in `RootModel`.
  201. - If a field shadows an attribute in the parent model.
  202. """
  203. FieldInfo_ = import_cached_field_info()
  204. BaseModel_ = import_cached_base_model()
  205. bases = cls.__bases__
  206. parent_fields_lookup: dict[str, FieldInfo] = {}
  207. for base in reversed(bases):
  208. if model_fields := getattr(base, '__pydantic_fields__', None):
  209. parent_fields_lookup.update(model_fields)
  210. type_hints = _typing_extra.get_model_type_hints(cls, ns_resolver=ns_resolver)
  211. # `cls_annotations` is only used to determine if an annotation comes from a parent class
  212. cls_annotations = _typing_extra.safe_get_annotations(cls)
  213. fields: dict[str, FieldInfo] = {}
  214. class_vars: set[str] = set()
  215. for ann_name, (ann_type, evaluated) in type_hints.items():
  216. if ann_name == 'model_config':
  217. # We never want to treat `model_config` as a field
  218. # Note: we may need to change this logic if/when we introduce a `BareModel` class with no
  219. # protected namespaces (where `model_config` might be allowed as a field name)
  220. continue
  221. _check_protected_namespaces(
  222. protected_namespaces=config_wrapper.protected_namespaces,
  223. ann_name=ann_name,
  224. bases=bases,
  225. cls_name=cls.__name__,
  226. )
  227. if _typing_extra.is_classvar_annotation(ann_type):
  228. class_vars.add(ann_name)
  229. continue
  230. assigned_value = getattr(cls, ann_name, PydanticUndefined)
  231. if assigned_value is not PydanticUndefined and (
  232. # One of the deprecated instance methods was used as a field name (e.g. `dict()`):
  233. any(getattr(BaseModel_, depr_name, None) is assigned_value for depr_name in _deprecated_method_names)
  234. # One of the deprecated class methods was used as a field name (e.g. `schema()`):
  235. or (
  236. hasattr(assigned_value, '__func__')
  237. and any(
  238. getattr(getattr(BaseModel_, depr_name, None), '__func__', None) is assigned_value.__func__ # pyright: ignore[reportAttributeAccessIssue]
  239. for depr_name in _deprecated_classmethod_names
  240. )
  241. )
  242. ):
  243. # Then `assigned_value` would be the method, even though no default was specified:
  244. assigned_value = PydanticUndefined
  245. if not is_valid_field_name(ann_name):
  246. continue
  247. if cls.__pydantic_root_model__ and ann_name != 'root':
  248. raise NameError(
  249. f"Unexpected field with name {ann_name!r}; only 'root' is allowed as a field of a `RootModel`"
  250. )
  251. for base in bases:
  252. if hasattr(base, ann_name):
  253. if ann_name not in cls_annotations:
  254. # Don't warn when a field exists in a parent class but has not been defined in the current class
  255. continue
  256. # when building a generic model with `MyModel[int]`, the generic_origin check makes sure we don't get
  257. # "... shadows an attribute" warnings
  258. generic_origin = getattr(cls, '__pydantic_generic_metadata__', {}).get('origin')
  259. if base is generic_origin:
  260. # Don't warn when "shadowing" of attributes in parametrized generics
  261. continue
  262. dataclass_fields = {
  263. field.name for field in (dataclasses.fields(base) if dataclasses.is_dataclass(base) else ())
  264. }
  265. if ann_name in dataclass_fields:
  266. # Don't warn when inheriting stdlib dataclasses whose fields are "shadowed" by defaults being set
  267. # on the class instance.
  268. continue
  269. warnings.warn(
  270. f'Field name "{ann_name}" in "{cls.__qualname__}" shadows an attribute in parent '
  271. f'"{base.__qualname__}"',
  272. UserWarning,
  273. stacklevel=4,
  274. )
  275. if assigned_value is PydanticUndefined: # no assignment, just a plain annotation
  276. if ann_name in cls_annotations or ann_name not in parent_fields_lookup:
  277. # field is either:
  278. # - present in the current model's annotations (and *not* from parent classes)
  279. # - not found on any base classes; this seems to be caused by fields not getting
  280. # generated due to models not being fully defined while initializing recursive models.
  281. # Nothing stops us from just creating a `FieldInfo` for this type hint, so we do this.
  282. field_info = FieldInfo_.from_annotation(ann_type, _source=AnnotationSource.CLASS)
  283. field_info._original_annotation = ann_type
  284. if not evaluated:
  285. field_info._complete = False
  286. # Store the original annotation that should be used to rebuild
  287. # the field info later:
  288. else:
  289. # The field was present on one of the (possibly multiple) base classes, we make a copy directly from it.
  290. parent_field_info = parent_fields_lookup[ann_name]._copy()
  291. # The only case where substituting the type variables is relevant (i.e. when `typevars_map` is not empty)
  292. # is when a generic class is parameterized (e.g. `MyGenericModel[int, str]`), which creates a new class object
  293. # (unlike the stdlib genercis that create a generic alias). In this case, we are guaranteed to only have to copy
  294. # from the origin/parent model (e.g. `MyGenericModel`).
  295. if typevars_map:
  296. field_info = _recreate_field_info(
  297. parent_field_info, ns_resolver=ns_resolver, typevars_map=typevars_map, lenient=True
  298. )
  299. else:
  300. field_info = parent_field_info
  301. else: # An assigned value is present (either the default value, or a `Field()` function)
  302. if isinstance(assigned_value, FieldInfo_) and ismethoddescriptor(assigned_value.default):
  303. # `assigned_value` was fetched using `getattr`, which triggers a call to `__get__`
  304. # for descriptors, so we do the same if the `= field(default=...)` form is used.
  305. # Note that we only do this for method descriptors for now, we might want to
  306. # extend this to any descriptor in the future (by simply checking for
  307. # `hasattr(assigned_value.default, '__get__')`).
  308. default = assigned_value.default.__get__(None, cls)
  309. assigned_value.default = default
  310. assigned_value._attributes_set['default'] = default
  311. field_info = FieldInfo_.from_annotated_attribute(ann_type, assigned_value, _source=AnnotationSource.CLASS)
  312. # Store the original annotation and assignment value that could be used to rebuild the field info later.
  313. field_info._original_assignment = assigned_value
  314. field_info._original_annotation = ann_type
  315. if not evaluated:
  316. field_info._complete = False
  317. elif 'final' in field_info._qualifiers and not field_info.is_required():
  318. warnings.warn(
  319. f'Annotation {ann_name!r} is marked as final and has a default value. Pydantic treats {ann_name!r} as a '
  320. 'class variable, but it will be considered as a normal field in V3 to be aligned with dataclasses. If you '
  321. f'still want {ann_name!r} to be considered as a class variable, annotate it as: `ClassVar[<type>] = <default>.`',
  322. category=PydanticDeprecatedSince211,
  323. # Incorrect when `create_model` is used, but the chance that final with a default is used is low in that case:
  324. stacklevel=4,
  325. )
  326. class_vars.add(ann_name)
  327. continue
  328. # attributes which are fields are removed from the class namespace:
  329. # 1. To match the behaviour of annotation-only fields
  330. # 2. To avoid false positives in the NameError check above
  331. try:
  332. delattr(cls, ann_name)
  333. except AttributeError:
  334. pass # indicates the attribute was on a parent class
  335. # Use cls.__dict__['__pydantic_decorators__'] instead of cls.__pydantic_decorators__
  336. # to make sure the decorators have already been built for this exact class
  337. decorators: DecoratorInfos = cls.__dict__['__pydantic_decorators__']
  338. if ann_name in decorators.computed_fields:
  339. raise TypeError(
  340. f'Field {ann_name!r} of class {cls.__name__!r} overrides symbol of same name in a parent class. '
  341. 'This override with a computed_field is incompatible.'
  342. )
  343. fields[ann_name] = field_info
  344. if field_info._complete:
  345. # If not complete, this will be called in `rebuild_model_fields()`:
  346. update_field_from_config(config_wrapper, ann_name, field_info)
  347. if config_wrapper.use_attribute_docstrings:
  348. _update_fields_from_docstrings(cls, fields)
  349. pydantic_extra_info: PydanticExtraInfo | None = None
  350. if '__pydantic_extra__' in type_hints:
  351. ann, complete = type_hints['__pydantic_extra__']
  352. pydantic_extra_info = PydanticExtraInfo(
  353. annotation=ann,
  354. complete=complete,
  355. )
  356. return fields, pydantic_extra_info, class_vars
  357. def rebuild_model_fields(
  358. cls: type[BaseModel],
  359. *,
  360. config_wrapper: ConfigWrapper,
  361. ns_resolver: NsResolver,
  362. typevars_map: Mapping[TypeVar, Any],
  363. ) -> tuple[dict[str, FieldInfo], PydanticExtraInfo | None]:
  364. """Rebuild the (already present) model fields by trying to reevaluate annotations.
  365. This function should be called whenever a model with incomplete fields is encountered.
  366. Returns:
  367. A two-tuple, the first element being the rebuilt fields, the second element being
  368. the rebuild `PydanticExtraInfo` instance, if available.
  369. Raises:
  370. NameError: If one of the annotations failed to evaluate.
  371. Note:
  372. This function *doesn't* mutate the model fields in place, as it can be called during
  373. schema generation, where you don't want to mutate other model's fields.
  374. """
  375. rebuilt_fields: dict[str, FieldInfo] = {}
  376. with ns_resolver.push(cls):
  377. for f_name, field_info in cls.__pydantic_fields__.items():
  378. if field_info._complete:
  379. rebuilt_fields[f_name] = field_info
  380. else:
  381. new_field = _recreate_field_info(
  382. field_info, ns_resolver=ns_resolver, typevars_map=typevars_map, lenient=False
  383. )
  384. update_field_from_config(config_wrapper, f_name, new_field)
  385. rebuilt_fields[f_name] = new_field
  386. if cls.__pydantic_extra_info__ is not None and not cls.__pydantic_extra_info__.complete:
  387. rebuilt_extra_info = PydanticExtraInfo(
  388. annotation=_typing_extra.eval_type(
  389. cls.__pydantic_extra_info__.annotation, *ns_resolver.types_namespace
  390. ),
  391. complete=True,
  392. )
  393. else:
  394. rebuilt_extra_info = cls.__pydantic_extra_info__
  395. return rebuilt_fields, rebuilt_extra_info
  396. def _recreate_field_info(
  397. field_info: FieldInfo,
  398. ns_resolver: NsResolver,
  399. typevars_map: Mapping[TypeVar, Any],
  400. *,
  401. lenient: bool,
  402. ) -> FieldInfo:
  403. FieldInfo_ = import_cached_field_info()
  404. existing_desc = field_info.description
  405. if lenient:
  406. ann = _generics.replace_types(field_info._original_annotation, typevars_map)
  407. ann, evaluated = _typing_extra.try_eval_type(
  408. ann,
  409. *ns_resolver.types_namespace,
  410. )
  411. else:
  412. # Not the best pattern, maybe we could ship our own `eval_type()`,
  413. # that would replace the type variables on the fly during evaluation.
  414. ann = _typing_extra.eval_type(
  415. field_info._original_annotation,
  416. *ns_resolver.types_namespace,
  417. )
  418. ann = _generics.replace_types(ann, typevars_map)
  419. ann = _typing_extra.eval_type(
  420. ann,
  421. *ns_resolver.types_namespace,
  422. )
  423. evaluated = True
  424. if (assign := field_info._original_assignment) is PydanticUndefined:
  425. new_field = FieldInfo_.from_annotation(ann, _source=AnnotationSource.CLASS)
  426. else:
  427. new_field = FieldInfo_.from_annotated_attribute(ann, assign, _source=AnnotationSource.CLASS)
  428. new_field._original_assignment = assign
  429. new_field._original_annotation = ann
  430. # The description might come from the docstring if `use_attribute_docstrings` was `True`:
  431. new_field.description = new_field.description if new_field.description is not None else existing_desc
  432. if not evaluated:
  433. new_field._complete = False
  434. return new_field
  435. def collect_dataclass_fields(
  436. cls: type[StandardDataclass],
  437. *,
  438. config_wrapper: ConfigWrapper,
  439. ns_resolver: NsResolver | None = None,
  440. typevars_map: dict[Any, Any] | None = None,
  441. ) -> dict[str, FieldInfo]:
  442. """Collect the fields of a dataclass.
  443. Args:
  444. cls: dataclass.
  445. config_wrapper: The config wrapper instance.
  446. ns_resolver: Namespace resolver to use when getting dataclass annotations.
  447. Defaults to an empty instance.
  448. typevars_map: A dictionary mapping type variables to their concrete types.
  449. Returns:
  450. The dataclass fields.
  451. """
  452. FieldInfo_ = import_cached_field_info()
  453. fields: dict[str, FieldInfo] = {}
  454. ns_resolver = ns_resolver or NsResolver()
  455. dataclass_fields = cls.__dataclass_fields__
  456. # The logic here is similar to `_typing_extra.get_cls_type_hints`,
  457. # although we do it manually as stdlib dataclasses already have annotations
  458. # collected in each class:
  459. for base in reversed(cls.__mro__):
  460. if not dataclasses.is_dataclass(base):
  461. continue
  462. with ns_resolver.push(base):
  463. for ann_name, dataclass_field in dataclass_fields.items():
  464. base_anns = _typing_extra.safe_get_annotations(base)
  465. if ann_name not in base_anns:
  466. # `__dataclass_fields__`contains every field, even the ones from base classes.
  467. # Only collect the ones defined on `base`.
  468. continue
  469. globalns, localns = ns_resolver.types_namespace
  470. ann_type, evaluated = _typing_extra.try_eval_type(dataclass_field.type, globalns, localns)
  471. if _typing_extra.is_classvar_annotation(ann_type):
  472. continue
  473. if (
  474. not dataclass_field.init
  475. and dataclass_field.default is dataclasses.MISSING
  476. and dataclass_field.default_factory is dataclasses.MISSING
  477. ):
  478. # TODO: We should probably do something with this so that validate_assignment behaves properly
  479. # Issue: https://github.com/pydantic/pydantic/issues/5470
  480. continue
  481. if isinstance(dataclass_field.default, FieldInfo_):
  482. if dataclass_field.default.init_var:
  483. if dataclass_field.default.init is False:
  484. raise PydanticUserError(
  485. f'Dataclass field {ann_name} has init=False and init_var=True, but these are mutually exclusive.',
  486. code='clashing-init-and-init-var',
  487. )
  488. # TODO: same note as above re validate_assignment
  489. continue
  490. field_info = FieldInfo_.from_annotated_attribute(
  491. ann_type, dataclass_field.default, _source=AnnotationSource.DATACLASS
  492. )
  493. field_info._original_assignment = dataclass_field.default
  494. else:
  495. field_info = FieldInfo_.from_annotated_attribute(
  496. ann_type, dataclass_field, _source=AnnotationSource.DATACLASS
  497. )
  498. field_info._original_assignment = dataclass_field
  499. if not evaluated:
  500. field_info._complete = False
  501. field_info._original_annotation = ann_type
  502. fields[ann_name] = field_info
  503. update_field_from_config(config_wrapper, ann_name, field_info)
  504. if field_info.default is not PydanticUndefined and isinstance(
  505. getattr(cls, ann_name, field_info), FieldInfo_
  506. ):
  507. # We need this to fix the default when the "default" from __dataclass_fields__ is a pydantic.FieldInfo
  508. setattr(cls, ann_name, field_info.default)
  509. if typevars_map:
  510. for field in fields.values():
  511. # We don't pass any ns, as `field.annotation`
  512. # was already evaluated. TODO: is this method relevant?
  513. # Can't we juste use `_generics.replace_types`?
  514. field.apply_typevars_map(typevars_map)
  515. if config_wrapper.use_attribute_docstrings:
  516. _update_fields_from_docstrings(
  517. cls,
  518. fields,
  519. # We can't rely on the (more reliable) frame inspection method
  520. # for stdlib dataclasses:
  521. use_inspect=not hasattr(cls, '__is_pydantic_dataclass__'),
  522. )
  523. return fields
  524. def rebuild_dataclass_fields(
  525. cls: type[PydanticDataclass],
  526. *,
  527. config_wrapper: ConfigWrapper,
  528. ns_resolver: NsResolver,
  529. typevars_map: Mapping[TypeVar, Any],
  530. ) -> dict[str, FieldInfo]:
  531. """Rebuild the (already present) dataclass fields by trying to reevaluate annotations.
  532. This function should be called whenever a dataclass with incomplete fields is encountered.
  533. Raises:
  534. NameError: If one of the annotations failed to evaluate.
  535. Note:
  536. This function *doesn't* mutate the dataclass fields in place, as it can be called during
  537. schema generation, where you don't want to mutate other dataclass's fields.
  538. """
  539. FieldInfo_ = import_cached_field_info()
  540. rebuilt_fields: dict[str, FieldInfo] = {}
  541. with ns_resolver.push(cls):
  542. for f_name, field_info in cls.__pydantic_fields__.items():
  543. if field_info._complete:
  544. rebuilt_fields[f_name] = field_info
  545. else:
  546. existing_desc = field_info.description
  547. ann = _typing_extra.eval_type(
  548. field_info._original_annotation,
  549. *ns_resolver.types_namespace,
  550. )
  551. ann = _generics.replace_types(ann, typevars_map)
  552. new_field = FieldInfo_.from_annotated_attribute(
  553. ann,
  554. field_info._original_assignment,
  555. _source=AnnotationSource.DATACLASS,
  556. )
  557. # The description might come from the docstring if `use_attribute_docstrings` was `True`:
  558. new_field.description = new_field.description if new_field.description is not None else existing_desc
  559. update_field_from_config(config_wrapper, f_name, new_field)
  560. rebuilt_fields[f_name] = new_field
  561. return rebuilt_fields
  562. def is_valid_field_name(name: str) -> bool:
  563. return not name.startswith('_')
  564. def is_valid_privateattr_name(name: str) -> bool:
  565. return name.startswith('_') and not name.startswith('__')
  566. def takes_validated_data_argument(
  567. default_factory: Callable[[], Any] | Callable[[dict[str, Any]], Any],
  568. ) -> TypeIs[Callable[[dict[str, Any]], Any]]:
  569. """Whether the provided default factory callable has a validated data parameter."""
  570. try:
  571. sig = _typing_extra.signature_no_eval(default_factory)
  572. except (ValueError, TypeError):
  573. # `inspect.signature` might not be able to infer a signature, e.g. with C objects.
  574. # In this case, we assume no data argument is present:
  575. return False
  576. parameters = list(sig.parameters.values())
  577. return len(parameters) == 1 and can_be_positional(parameters[0]) and parameters[0].default is Parameter.empty
  578. def resolve_default_value(
  579. default: Any,
  580. default_factory: Callable[[], Any] | Callable[[dict[str, Any]], Any] | None,
  581. *,
  582. validated_data: dict[str, Any] | None = None,
  583. call_default_factory: bool = False,
  584. ) -> Any:
  585. """Resolve the default value using either a static default or a default_factory."""
  586. from ._utils import smart_deepcopy
  587. if default_factory is None:
  588. return smart_deepcopy(default)
  589. if call_default_factory:
  590. if takes_validated_data_argument(default_factory=default_factory):
  591. fac = cast('Callable[[dict[str, Any]], Any]', default_factory)
  592. if validated_data is None:
  593. raise ValueError(
  594. "The default factory requires the 'validated_data' argument, which was not provided when calling 'get_default()'."
  595. )
  596. return fac(validated_data)
  597. else:
  598. fac = cast('Callable[[], Any]', default_factory)
  599. return fac()
  600. return PydanticUndefined