Coverage for pydantic/_internal/_fields.py: 98.79%
264 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 08:39 +0000
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 08:39 +0000
1"""Private logic related to fields (the `Field()` function and `FieldInfo` class), and arguments to `Annotated`."""
3from __future__ import annotations as _annotations 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH
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
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
19from pydantic import PydanticDeprecatedSince211 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH
20from pydantic.errors import PydanticUserError 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH
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
31if TYPE_CHECKING: 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH
32 from annotated_types import BaseMetadata
34 from ..fields import FieldInfo
35 from ..main import BaseModel
36 from ._dataclasses import PydanticDataclass, StandardDataclass
37 from ._decorators import DecoratorInfos
40class PydanticMetadata(Representation): 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH
41 """Base class for annotation markers like `Strict`."""
43 __slots__ = () 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH
46def pydantic_general_metadata(**metadata: Any) -> BaseMetadata: 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH
47 """Create a new `_PydanticGeneralMetadata` class with the given metadata.
49 Args:
50 **metadata: The metadata to add.
52 Returns:
53 The new `_PydanticGeneralMetadata` class.
54 """
55 return _general_metadata_cls()(metadata) # type: ignore 1akblcmgwhxyIznopqrsABCDEdteufviFjGH
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
63 class _PydanticGeneralMetadata(PydanticMetadata, BaseMetadata): 1akblcmgwhxyIznopqrsABCDEdteufviFjGH
64 """Pydantic general metadata like `max_digits`."""
66 def __init__(self, metadata: Any): 1akblcmgwhxyIznopqrsABCDEdteufviFjGH
67 self.__dict__ = metadata 1akblcmgwhxyIznopqrsABCDEdteufviFjGH
69 return _PydanticGeneralMetadata # type: ignore 1akblcmgwhxyIznopqrsABCDEdteufviFjGH
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
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
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
105 valid_namespaces_str = f'({", ".join(valid_namespaces)}{",)" if len(valid_namespaces) == 1 else ")"}' 1akblcmgwhxyIznopqrsABCDEdteufviFjGH
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 )
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
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
132 field_info.title = title 1akblcmgwhxyIznopqrsABCDEdteufviFjGH
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.
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
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
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
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
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
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.
188 This will apply the title and alias generators from the configuration.
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
202_deprecated_method_names = {'dict', 'json', 'copy', '_iter', '_copy_and_set_values', '_calculate_keys'} 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH
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}
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.
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.
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.
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.
240 Returns:
241 A two-tuple containing model fields and class variables names.
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
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
258 type_hints = _typing_extra.get_model_type_hints(cls, ns_resolver=ns_resolver) 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH
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
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
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 )
280 if _typing_extra.is_classvar_annotation(ann_type): 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH
281 class_vars.add(ann_name) 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH
282 continue 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH
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
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 )
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
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
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
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 )
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
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
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
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
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
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
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
411 if config_wrapper.use_attribute_docstrings: 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH
412 _update_fields_from_docstrings(cls, fields) 1akblcmgwhxyIznopqrsABCDEdteufviFjGH
413 return fields, class_vars 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH
416def _warn_on_nested_alias_in_annotation(ann_type: type[Any], ann_name: str) -> None: 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH
417 FieldInfo = import_cached_field_info() 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH
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
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.
441 This function should be called whenever a model with incomplete fields is encountered.
443 Raises:
444 NameError: If one of the annotations failed to evaluate.
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
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
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
474 return rebuilt_fields 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH
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.
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.
493 Returns:
494 The dataclass fields.
495 """
496 FieldInfo_ = import_cached_field_info() 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH
498 fields: dict[str, FieldInfo] = {} 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH
499 ns_resolver = ns_resolver or NsResolver() 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH
500 dataclass_fields = cls.__dataclass_fields__ 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH
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
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
516 globalns, localns = ns_resolver.types_namespace 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH
517 ann_type, evaluated = _typing_extra.try_eval_type(dataclass_field.type, globalns, localns) 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH
519 if _typing_extra.is_classvar_annotation(ann_type): 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH
520 continue 1akblcmgwhxyIznopqrsABCDEdteufviFjGH
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
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 )
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
551 if not evaluated: 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH
552 field_info._complete = False 1akblcmgwhxyIznopqrsABCDEdteufviFjGH
553 field_info._original_annotation = ann_type 1akblcmgwhxyIznopqrsABCDEdteufviFjGH
555 fields[ann_name] = field_info 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH
556 update_field_from_config(config_wrapper, ann_name, field_info) 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH
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
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
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 )
580 return fields 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH
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.
592 This function should be called whenever a dataclass with incomplete fields is encountered.
594 Raises:
595 NameError: If one of the annotations failed to evaluate.
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
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 )
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
626 return rebuilt_fields 1akblcmgwhxyIznopqrsABCDEdteufviFjGH
629def is_valid_field_name(name: str) -> bool: 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH
630 return not name.startswith('_') 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH
633def is_valid_privateattr_name(name: str) -> bool: 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH
634 return name.startswith('_') and not name.startswith('__') 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH
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
648 parameters = list(sig.parameters.values()) 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH
650 return len(parameters) == 1 and can_be_positional(parameters[0]) and parameters[0].default is Parameter.empty 1akblcmgwhxyIznopqrsABCDEJdteufviFjGH