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

238 statements  

« prev     ^ index     » next       coverage.py v7.8.0, created at 2025-05-02 08:21 +0000

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

2 

3from __future__ import annotations as _annotations 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

4 

5import dataclasses 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

6import warnings 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

7from collections.abc import Mapping 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

8from copy import copy 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

9from functools import cache 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

10from inspect import Parameter, ismethoddescriptor, signature 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

11from re import Pattern 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

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

13 

14from pydantic_core import PydanticUndefined 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

15from typing_extensions import TypeIs, get_origin 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

16from typing_inspection import typing_objects 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

17from typing_inspection.introspection import AnnotationSource 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

18 

19from pydantic import PydanticDeprecatedSince211 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

20from pydantic.errors import PydanticUserError 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

21 

22from ..aliases import AliasGenerator 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

23from . import _generics, _typing_extra 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

24from ._config import ConfigWrapper 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

25from ._docs_extraction import extract_docstrings_from_cls 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

26from ._import_utils import import_cached_base_model, import_cached_field_info 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

27from ._namespace_utils import NsResolver 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

28from ._repr import Representation 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

29from ._utils import can_be_positional, get_first_not_none 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

30 

31if TYPE_CHECKING: 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

32 from annotated_types import BaseMetadata 

33 

34 from ..fields import FieldInfo 

35 from ..main import BaseModel 

36 from ._dataclasses import StandardDataclass 

37 from ._decorators import DecoratorInfos 

38 

39 

40class PydanticMetadata(Representation): 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

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

42 

43 __slots__ = () 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

44 

45 

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

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 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

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

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( 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

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() 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

79 

80 for protected_namespace in protected_namespaces: 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

81 ns_violation = False 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

82 if isinstance(protected_namespace, Pattern): 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

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 true1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

85 ns_violation = ann_name.startswith(protected_namespace) 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

86 

87 if ns_violation: 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

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: 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

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( 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

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( 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

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: 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

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 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

196 if field_title_generator is not None: 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

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: 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

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

200 

201 

202def collect_model_fields( # noqa: C901 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

203 cls: type[BaseModel], 

204 config_wrapper: ConfigWrapper, 

205 ns_resolver: NsResolver | None, 

206 *, 

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

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

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

210 

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

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

213 is stored on the created `FieldInfo` instance. 

214 

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

216 and will make use of these stored attributes. 

217 

218 Args: 

219 cls: BaseModel or dataclass. 

220 config_wrapper: The config wrapper instance. 

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

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

223 

224 Returns: 

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

226 

227 Raises: 

228 NameError: 

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

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

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

232 """ 

233 FieldInfo_ = import_cached_field_info() 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

234 

235 bases = cls.__bases__ 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

236 parent_fields_lookup: dict[str, FieldInfo] = {} 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

237 for base in reversed(bases): 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

238 if model_fields := getattr(base, '__pydantic_fields__', None): 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

239 parent_fields_lookup.update(model_fields) 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

240 

241 type_hints = _typing_extra.get_model_type_hints(cls, ns_resolver=ns_resolver) 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

242 

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

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

245 annotations = cls.__dict__.get('__annotations__', {}) 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

246 fields: dict[str, FieldInfo] = {} 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

247 

248 class_vars: set[str] = set() 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

249 for ann_name, (ann_type, evaluated) in type_hints.items(): 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

250 if ann_name == 'model_config': 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

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

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

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

254 continue 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

255 

256 _check_protected_namespaces( 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

257 protected_namespaces=config_wrapper.protected_namespaces, 

258 ann_name=ann_name, 

259 bases=bases, 

260 cls_name=cls.__name__, 

261 ) 

262 

263 if _typing_extra.is_classvar_annotation(ann_type): 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

264 class_vars.add(ann_name) 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

265 continue 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

266 

267 assigned_value = getattr(cls, ann_name, PydanticUndefined) 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

268 

269 if not is_valid_field_name(ann_name): 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

270 continue 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

271 if cls.__pydantic_root_model__ and ann_name != 'root': 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

272 raise NameError( 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

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

274 ) 

275 

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

277 # "... shadows an attribute" warnings 

278 generic_origin = getattr(cls, '__pydantic_generic_metadata__', {}).get('origin') 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

279 for base in bases: 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

280 dataclass_fields = { 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

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

282 } 

283 if hasattr(base, ann_name): 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

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

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

286 continue 

287 

288 if ann_name in dataclass_fields: 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

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

290 # on the class instance. 

291 continue 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

292 

293 if ann_name not in annotations: 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

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

295 continue 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

296 

297 warnings.warn( 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

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

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

300 UserWarning, 

301 ) 

302 

303 if assigned_value is PydanticUndefined: # no assignment, just a plain annotation 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

304 if ann_name in annotations or ann_name not in parent_fields_lookup: 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

305 # field is either: 

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

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

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

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

310 field_info = FieldInfo_.from_annotation(ann_type, _source=AnnotationSource.CLASS) 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

311 if not evaluated: 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

312 field_info._complete = False 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

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

314 # the field info later: 

315 field_info._original_annotation = ann_type 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

316 else: 

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

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

319 field_info = copy(parent_fields_lookup[ann_name]) 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

320 

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

322 _warn_on_nested_alias_in_annotation(ann_type, ann_name) 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

323 if isinstance(assigned_value, FieldInfo_) and ismethoddescriptor(assigned_value.default): 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

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

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

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

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

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

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

330 

331 # The `from_annotated_attribute()` call below mutates the assigned `Field()`, so make a copy: 

332 original_assignment = ( 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

333 copy(assigned_value) if not evaluated and isinstance(assigned_value, FieldInfo_) else assigned_value 

334 ) 

335 

336 field_info = FieldInfo_.from_annotated_attribute(ann_type, assigned_value, _source=AnnotationSource.CLASS) 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

337 if not evaluated: 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

338 field_info._complete = False 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

339 # Store the original annotation and assignment value that should be used to rebuild 

340 # the field info later: 

341 field_info._original_annotation = ann_type 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

342 field_info._original_assignment = original_assignment 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

343 elif 'final' in field_info._qualifiers and not field_info.is_required(): 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

344 warnings.warn( 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

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

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

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

348 category=PydanticDeprecatedSince211, 

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

350 stacklevel=4, 

351 ) 

352 class_vars.add(ann_name) 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

353 continue 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

354 

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

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

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

358 try: 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

359 delattr(cls, ann_name) 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

360 except AttributeError: 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

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

362 

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

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

365 decorators: DecoratorInfos = cls.__dict__['__pydantic_decorators__'] 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

366 if ann_name in decorators.computed_fields: 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

367 raise TypeError( 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

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

369 'This override with a computed_field is incompatible.' 

370 ) 

371 fields[ann_name] = field_info 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

372 

373 if field_info._complete: 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

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

375 update_field_from_config(config_wrapper, ann_name, field_info) 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

376 

377 if typevars_map: 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

378 for field in fields.values(): 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

379 if field._complete: 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

380 field.apply_typevars_map(typevars_map) 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

381 

382 if config_wrapper.use_attribute_docstrings: 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

383 _update_fields_from_docstrings(cls, fields) 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

384 return fields, class_vars 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

385 

386 

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

388 FieldInfo = import_cached_field_info() 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

389 

390 args = getattr(ann_type, '__args__', None) 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

391 if args: 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

392 for anno_arg in args: 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

393 if typing_objects.is_annotated(get_origin(anno_arg)): 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

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

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

396 warnings.warn( 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

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

398 UserWarning, 

399 ) 

400 return 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

401 

402 

403def rebuild_model_fields( 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

404 cls: type[BaseModel], 

405 *, 

406 config_wrapper: ConfigWrapper, 

407 ns_resolver: NsResolver, 

408 typevars_map: Mapping[TypeVar, Any], 

409) -> dict[str, FieldInfo]: 

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

411 

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

413 

414 Note: 

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

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

417 """ 

418 FieldInfo_ = import_cached_field_info() 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

419 

420 rebuilt_fields: dict[str, FieldInfo] = {} 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

421 with ns_resolver.push(cls): 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

422 for f_name, field_info in cls.__pydantic_fields__.items(): 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

423 if field_info._complete: 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

424 rebuilt_fields[f_name] = field_info 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

425 else: 

426 existing_desc = field_info.description 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

427 ann = _typing_extra.eval_type( 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

428 field_info._original_annotation, 

429 *ns_resolver.types_namespace, 

430 ) 

431 ann = _generics.replace_types(ann, typevars_map) 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

432 

433 if (assign := field_info._original_assignment) is PydanticUndefined: 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

434 new_field = FieldInfo_.from_annotation(ann, _source=AnnotationSource.CLASS) 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

435 else: 

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

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

438 new_field.description = new_field.description if new_field.description is not None else existing_desc 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

439 update_field_from_config(config_wrapper, f_name, new_field) 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

440 rebuilt_fields[f_name] = new_field 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

441 

442 return rebuilt_fields 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

443 

444 

445def collect_dataclass_fields( 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

446 cls: type[StandardDataclass], 

447 *, 

448 config_wrapper: ConfigWrapper, 

449 ns_resolver: NsResolver | None = None, 

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

451) -> dict[str, FieldInfo]: 

452 """Collect the fields of a dataclass. 

453 

454 Args: 

455 cls: dataclass. 

456 config_wrapper: The config wrapper instance. 

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

458 Defaults to an empty instance. 

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

460 

461 Returns: 

462 The dataclass fields. 

463 """ 

464 FieldInfo_ = import_cached_field_info() 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

465 

466 fields: dict[str, FieldInfo] = {} 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

467 ns_resolver = ns_resolver or NsResolver() 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

468 dataclass_fields = cls.__dataclass_fields__ 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

469 

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

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

472 # collected in each class: 

473 for base in reversed(cls.__mro__): 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

474 if not dataclasses.is_dataclass(base): 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

475 continue 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

476 

477 with ns_resolver.push(base): 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

478 for ann_name, dataclass_field in dataclass_fields.items(): 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

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

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

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

482 continue 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

483 

484 globalns, localns = ns_resolver.types_namespace 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

485 ann_type, _ = _typing_extra.try_eval_type(dataclass_field.type, globalns, localns) 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

486 

487 if _typing_extra.is_classvar_annotation(ann_type): 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

488 continue 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

489 

490 if ( 1akblcmIznopqrsJKLdteufv

491 not dataclass_field.init 

492 and dataclass_field.default is dataclasses.MISSING 

493 and dataclass_field.default_factory is dataclasses.MISSING 

494 ): 

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

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

497 continue 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

498 

499 if isinstance(dataclass_field.default, FieldInfo_): 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

500 if dataclass_field.default.init_var: 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

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

502 raise PydanticUserError( 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

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

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

505 ) 

506 

507 # TODO: same note as above re validate_assignment 

508 continue 1blcmgwhxyzpqrsABCDEeufviFjGH

509 field_info = FieldInfo_.from_annotated_attribute( 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

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

511 ) 

512 else: 

513 field_info = FieldInfo_.from_annotated_attribute( 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

514 ann_type, dataclass_field, _source=AnnotationSource.DATACLASS 

515 ) 

516 

517 fields[ann_name] = field_info 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

518 update_field_from_config(config_wrapper, ann_name, field_info) 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

519 

520 if field_info.default is not PydanticUndefined and isinstance( 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

521 getattr(cls, ann_name, field_info), FieldInfo_ 

522 ): 

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

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

525 

526 if typevars_map: 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

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

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

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

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

531 field.apply_typevars_map(typevars_map) 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

532 

533 if config_wrapper.use_attribute_docstrings: 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

534 _update_fields_from_docstrings( 1akblcmgwhxyIznopqrsABCDEdteufviFjGH

535 cls, 

536 fields, 

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

538 # for stdlib dataclasses: 

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

540 ) 

541 

542 return fields 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

543 

544 

545def is_valid_field_name(name: str) -> bool: 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

546 return not name.startswith('_') 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

547 

548 

549def is_valid_privateattr_name(name: str) -> bool: 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

550 return name.startswith('_') and not name.startswith('__') 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

551 

552 

553def takes_validated_data_argument( 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

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

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

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

557 try: 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

558 sig = signature(default_factory) 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

559 except (ValueError, TypeError): 1akblcmgwhxynopqrsABCDEdteufviFjGH

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

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

562 return False 1akblcmgwhxynopqrsABCDEdteufviFjGH

563 

564 parameters = list(sig.parameters.values()) 1akblcmgwhxyIznopqrsABCDEJKLMNOPdteufviFjGH

565 

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