Coverage for pydantic/_internal/_fields.py: 97.25%
159 statements
« prev ^ index » next coverage.py v7.5.4, created at 2024-07-03 19:29 +0000
« prev ^ index » next coverage.py v7.5.4, created at 2024-07-03 19:29 +0000
1"""Private logic related to fields (the `Field()` function and `FieldInfo` class), and arguments to `Annotated`."""
3from __future__ import annotations as _annotations 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
5import dataclasses 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
6import sys 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
7import warnings 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
8from copy import copy 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
9from functools import lru_cache 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
10from typing import TYPE_CHECKING, Any 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
12from pydantic_core import PydanticUndefined 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
14from pydantic.errors import PydanticUserError 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
16from . import _typing_extra 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
17from ._config import ConfigWrapper 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
18from ._docs_extraction import extract_docstrings_from_cls 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
19from ._repr import Representation 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
20from ._typing_extra import get_cls_type_hints_lenient, get_type_hints, is_classvar, is_finalvar 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
22if TYPE_CHECKING: 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
23 from annotated_types import BaseMetadata
25 from ..fields import FieldInfo
26 from ..main import BaseModel
27 from ._dataclasses import StandardDataclass
28 from ._decorators import DecoratorInfos
31def get_type_hints_infer_globalns( 1mnopabcdqrstvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
32 obj: Any,
33 localns: dict[str, Any] | None = None,
34 include_extras: bool = False,
35) -> dict[str, Any]:
36 """Gets type hints for an object by inferring the global namespace.
38 It uses the `typing.get_type_hints`, The only thing that we do here is fetching
39 global namespace from `obj.__module__` if it is not `None`.
41 Args:
42 obj: The object to get its type hints.
43 localns: The local namespaces.
44 include_extras: Whether to recursively include annotation metadata.
46 Returns:
47 The object type hints.
48 """
49 module_name = getattr(obj, '__module__', None) 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
50 globalns: dict[str, Any] | None = None 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
51 if module_name: 51 ↛ 57line 51 didn't jump to line 57 because the condition on line 51 was always true1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
52 try: 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
53 globalns = sys.modules[module_name].__dict__ 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
54 except KeyError:
55 # happens occasionally, see https://github.com/pydantic/pydantic/issues/2363
56 pass
57 return get_type_hints(obj, globalns=globalns, localns=localns, include_extras=include_extras) 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
60class PydanticMetadata(Representation): 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
61 """Base class for annotation markers like `Strict`."""
63 __slots__ = () 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
66def pydantic_general_metadata(**metadata: Any) -> BaseMetadata: 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
67 """Create a new `_PydanticGeneralMetadata` class with the given metadata.
69 Args:
70 **metadata: The metadata to add.
72 Returns:
73 The new `_PydanticGeneralMetadata` class.
74 """
75 return _general_metadata_cls()(metadata) # type: ignore 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
78@lru_cache(maxsize=None) 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
79def _general_metadata_cls() -> type[BaseMetadata]: 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
80 """Do it this way to avoid importing `annotated_types` at import time."""
81 from annotated_types import BaseMetadata 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
83 class _PydanticGeneralMetadata(PydanticMetadata, BaseMetadata): 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
84 """Pydantic general metadata like `max_digits`."""
86 def __init__(self, metadata: Any): 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
87 self.__dict__ = metadata 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
89 return _PydanticGeneralMetadata # type: ignore 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
92def _update_fields_from_docstrings(cls: type[Any], fields: dict[str, FieldInfo], config_wrapper: ConfigWrapper) -> None: 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
93 if config_wrapper.use_attribute_docstrings: 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
94 fields_docs = extract_docstrings_from_cls(cls) 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
95 for ann_name, field_info in fields.items(): 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
96 if field_info.description is None and ann_name in fields_docs: 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
97 field_info.description = fields_docs[ann_name] 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
100def collect_model_fields( # noqa: C901 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
101 cls: type[BaseModel],
102 bases: tuple[type[Any], ...],
103 config_wrapper: ConfigWrapper,
104 types_namespace: dict[str, Any] | None,
105 *,
106 typevars_map: dict[Any, Any] | None = None,
107) -> tuple[dict[str, FieldInfo], set[str]]:
108 """Collect the fields of a nascent pydantic model.
110 Also collect the names of any ClassVars present in the type hints.
112 The returned value is a tuple of two items: the fields dict, and the set of ClassVar names.
114 Args:
115 cls: BaseModel or dataclass.
116 bases: Parents of the class, generally `cls.__bases__`.
117 config_wrapper: The config wrapper instance.
118 types_namespace: Optional extra namespace to look for types in.
119 typevars_map: A dictionary mapping type variables to their concrete types.
121 Returns:
122 A tuple contains fields and class variables.
124 Raises:
125 NameError:
126 - If there is a conflict between a field name and protected namespaces.
127 - If there is a field other than `root` in `RootModel`.
128 - If a field shadows an attribute in the parent model.
129 """
130 from ..fields import FieldInfo 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
132 type_hints = get_cls_type_hints_lenient(cls, types_namespace) 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
134 # https://docs.python.org/3/howto/annotations.html#accessing-the-annotations-dict-of-an-object-in-python-3-9-and-older
135 # annotations is only used for finding fields in parent classes
136 annotations = cls.__dict__.get('__annotations__', {}) 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
137 fields: dict[str, FieldInfo] = {} 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
139 class_vars: set[str] = set() 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
140 for ann_name, ann_type in type_hints.items(): 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
141 if ann_name == 'model_config': 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
142 # We never want to treat `model_config` as a field
143 # Note: we may need to change this logic if/when we introduce a `BareModel` class with no
144 # protected namespaces (where `model_config` might be allowed as a field name)
145 continue 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
146 for protected_namespace in config_wrapper.protected_namespaces: 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
147 if ann_name.startswith(protected_namespace): 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
148 for b in bases: 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
149 if hasattr(b, ann_name): 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
150 from ..main import BaseModel 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
152 if not (issubclass(b, BaseModel) and ann_name in b.model_fields): 152 ↛ 148line 152 didn't jump to line 148 because the condition on line 152 was always true1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
153 raise NameError( 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
154 f'Field "{ann_name}" conflicts with member {getattr(b, ann_name)}'
155 f' of protected namespace "{protected_namespace}".'
156 )
157 else:
158 valid_namespaces = tuple( 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
159 x for x in config_wrapper.protected_namespaces if not ann_name.startswith(x)
160 )
161 warnings.warn( 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
162 f'Field "{ann_name}" has conflict with protected namespace "{protected_namespace}".'
163 '\n\nYou may be able to resolve this warning by setting'
164 f" `model_config['protected_namespaces'] = {valid_namespaces}`.",
165 UserWarning,
166 )
167 if is_classvar(ann_type): 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
168 class_vars.add(ann_name) 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
169 continue 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
170 if _is_finalvar_with_default_val(ann_type, getattr(cls, ann_name, PydanticUndefined)): 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
171 class_vars.add(ann_name) 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
172 continue 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
173 if not is_valid_field_name(ann_name): 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
174 continue 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
175 if cls.__pydantic_root_model__ and ann_name != 'root': 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
176 raise NameError( 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
177 f"Unexpected field with name {ann_name!r}; only 'root' is allowed as a field of a `RootModel`"
178 )
180 # when building a generic model with `MyModel[int]`, the generic_origin check makes sure we don't get
181 # "... shadows an attribute" warnings
182 generic_origin = getattr(cls, '__pydantic_generic_metadata__', {}).get('origin') 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
183 for base in bases: 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
184 dataclass_fields = { 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
185 field.name for field in (dataclasses.fields(base) if dataclasses.is_dataclass(base) else ())
186 }
187 if hasattr(base, ann_name): 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
188 if base is generic_origin: 188 ↛ 190line 188 didn't jump to line 190 because the condition on line 188 was never true1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
189 # Don't warn when "shadowing" of attributes in parametrized generics
190 continue
192 if ann_name in dataclass_fields: 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
193 # Don't warn when inheriting stdlib dataclasses whose fields are "shadowed" by defaults being set
194 # on the class instance.
195 continue 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
197 if ann_name not in annotations: 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
198 # Don't warn when a field exists in a parent class but has not been defined in the current class
199 continue 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
201 warnings.warn( 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
202 f'Field name "{ann_name}" in "{cls.__qualname__}" shadows an attribute in parent '
203 f'"{base.__qualname__}"',
204 UserWarning,
205 )
207 try: 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
208 default = getattr(cls, ann_name, PydanticUndefined) 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
209 if default is PydanticUndefined: 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
210 raise AttributeError 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
211 except AttributeError: 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
212 if ann_name in annotations: 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
213 field_info = FieldInfo.from_annotation(ann_type) 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
214 else:
215 # if field has no default value and is not in __annotations__ this means that it is
216 # defined in a base class and we can take it from there
217 model_fields_lookup: dict[str, FieldInfo] = {} 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
218 for x in cls.__bases__[::-1]: 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
219 model_fields_lookup.update(getattr(x, 'model_fields', {})) 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
220 if ann_name in model_fields_lookup: 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
221 # The field was present on one of the (possibly multiple) base classes
222 # copy the field to make sure typevar substitutions don't cause issues with the base classes
223 field_info = copy(model_fields_lookup[ann_name]) 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
224 else:
225 # The field was not found on any base classes; this seems to be caused by fields not getting
226 # generated thanks to models not being fully defined while initializing recursive models.
227 # Nothing stops us from just creating a new FieldInfo for this type hint, so we do this.
228 field_info = FieldInfo.from_annotation(ann_type) 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
229 else:
230 _warn_on_nested_alias_in_annotation(ann_type, ann_name) 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
231 field_info = FieldInfo.from_annotated_attribute(ann_type, default) 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
232 # attributes which are fields are removed from the class namespace:
233 # 1. To match the behaviour of annotation-only fields
234 # 2. To avoid false positives in the NameError check above
235 try: 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
236 delattr(cls, ann_name) 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
237 except AttributeError: 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
238 pass # indicates the attribute was on a parent class 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
240 # Use cls.__dict__['__pydantic_decorators__'] instead of cls.__pydantic_decorators__
241 # to make sure the decorators have already been built for this exact class
242 decorators: DecoratorInfos = cls.__dict__['__pydantic_decorators__'] 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
243 if ann_name in decorators.computed_fields: 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
244 raise ValueError("you can't override a field with a computed field") 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
245 fields[ann_name] = field_info 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
247 if typevars_map: 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
248 for field in fields.values(): 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
249 field.apply_typevars_map(typevars_map, types_namespace) 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
251 _update_fields_from_docstrings(cls, fields, config_wrapper) 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
253 return fields, class_vars 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
256def _warn_on_nested_alias_in_annotation(ann_type: type[Any], ann_name: str): 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
257 from ..fields import FieldInfo 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
259 if hasattr(ann_type, '__args__'): 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
260 for anno_arg in ann_type.__args__: 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
261 if _typing_extra.is_annotated(anno_arg): 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
262 for anno_type_arg in _typing_extra.get_args(anno_arg): 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
263 if isinstance(anno_type_arg, FieldInfo) and anno_type_arg.alias is not None: 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
264 warnings.warn( 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
265 f'`alias` specification on field "{ann_name}" must be set on outermost annotation to take effect.',
266 UserWarning,
267 )
268 break 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
271def _is_finalvar_with_default_val(type_: type[Any], val: Any) -> bool: 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
272 from ..fields import FieldInfo 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
274 if not is_finalvar(type_): 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
275 return False 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
276 elif val is PydanticUndefined: 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
277 return False 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
278 elif isinstance(val, FieldInfo) and (val.default is PydanticUndefined and val.default_factory is None): 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
279 return False 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
280 else:
281 return True 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
284def collect_dataclass_fields( 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
285 cls: type[StandardDataclass],
286 types_namespace: dict[str, Any] | None,
287 *,
288 typevars_map: dict[Any, Any] | None = None,
289 config_wrapper: ConfigWrapper | None = None,
290) -> dict[str, FieldInfo]:
291 """Collect the fields of a dataclass.
293 Args:
294 cls: dataclass.
295 types_namespace: Optional extra namespace to look for types in.
296 typevars_map: A dictionary mapping type variables to their concrete types.
297 config_wrapper: The config wrapper instance.
299 Returns:
300 The dataclass fields.
301 """
302 from ..fields import FieldInfo 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
304 fields: dict[str, FieldInfo] = {} 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
305 dataclass_fields: dict[str, dataclasses.Field] = cls.__dataclass_fields__ 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
306 cls_localns = dict(vars(cls)) # this matches get_cls_type_hints_lenient, but all tests pass with `= None` instead 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
308 source_module = sys.modules.get(cls.__module__) 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
309 if source_module is not None: 309 ↛ 312line 309 didn't jump to line 312 because the condition on line 309 was always true1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
310 types_namespace = {**source_module.__dict__, **(types_namespace or {})} 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
312 for ann_name, dataclass_field in dataclass_fields.items(): 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
313 ann_type = _typing_extra.eval_type_lenient(dataclass_field.type, types_namespace, cls_localns) 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
314 if is_classvar(ann_type): 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
315 continue 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
317 if ( 1mnopabcdLuvwxyefghMNOPQRSTDEFGijkl
318 not dataclass_field.init
319 and dataclass_field.default == dataclasses.MISSING
320 and dataclass_field.default_factory == dataclasses.MISSING
321 ):
322 # TODO: We should probably do something with this so that validate_assignment behaves properly
323 # Issue: https://github.com/pydantic/pydantic/issues/5470
324 continue 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
326 if isinstance(dataclass_field.default, FieldInfo): 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
327 if dataclass_field.default.init_var: 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
328 if dataclass_field.default.init is False: 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
329 raise PydanticUserError( 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
330 f'Dataclass field {ann_name} has init=False and init_var=True, but these are mutually exclusive.',
331 code='clashing-init-and-init-var',
332 )
334 # TODO: same note as above re validate_assignment
335 continue 1abcdqrstuefghzABCijklHIJK
336 field_info = FieldInfo.from_annotated_attribute(ann_type, dataclass_field.default) 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
337 else:
338 field_info = FieldInfo.from_annotated_attribute(ann_type, dataclass_field) 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
340 fields[ann_name] = field_info 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
342 if field_info.default is not PydanticUndefined and isinstance(getattr(cls, ann_name, field_info), FieldInfo): 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
343 # We need this to fix the default when the "default" from __dataclass_fields__ is a pydantic.FieldInfo
344 setattr(cls, ann_name, field_info.default) 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
346 if typevars_map: 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
347 for field in fields.values(): 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
348 field.apply_typevars_map(typevars_map, types_namespace) 1mnopabcdqrstLuvwxyefghzABCDEFGijklHIJK
350 if config_wrapper is not None: 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
351 _update_fields_from_docstrings(cls, fields, config_wrapper) 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
353 return fields 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
356def is_valid_field_name(name: str) -> bool: 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
357 return not name.startswith('_') 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
360def is_valid_privateattr_name(name: str) -> bool: 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK
361 return name.startswith('_') and not name.startswith('__') 1mnopabcdqrstLuvwxyefghzABCMNOPQRSTUVDEFGijklHIJK