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

159 statements  

« prev     ^ index     » next       coverage.py v7.5.3, created at 2024-06-21 17:00 +0000

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

2 

3from __future__ import annotations as _annotations 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

4 

5import dataclasses 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

6import sys 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

7import warnings 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

8from copy import copy 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

9from functools import lru_cache 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

10from typing import TYPE_CHECKING, Any 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

11 

12from pydantic_core import PydanticUndefined 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

13 

14from pydantic.errors import PydanticUserError 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

15 

16from . import _typing_extra 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

17from ._config import ConfigWrapper 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

18from ._docs_extraction import extract_docstrings_from_cls 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

19from ._repr import Representation 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

20from ._typing_extra import get_cls_type_hints_lenient, get_type_hints, is_classvar, is_finalvar 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

21 

22if TYPE_CHECKING: 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

23 from annotated_types import BaseMetadata 

24 

25 from ..fields import FieldInfo 

26 from ..main import BaseModel 

27 from ._dataclasses import StandardDataclass 

28 from ._decorators import DecoratorInfos 

29 

30 

31def get_type_hints_infer_globalns( 1mnopabcdqrtuvwefghxyGHIJKLMNOzABCijklDE

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. 

37 

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`. 

40 

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. 

45 

46 Returns: 

47 The object type hints. 

48 """ 

49 module_name = getattr(obj, '__module__', None) 1mnopabcdqrFstuvwefghxyzABCijklDE

50 globalns: dict[str, Any] | None = None 1mnopabcdqrFstuvwefghxyzABCijklDE

51 if module_name: 51 ↛ 57line 51 didn't jump to line 57, because the condition on line 51 was always true1mnopabcdqrFstuvwefghxyzABCijklDE

52 try: 1mnopabcdqrFstuvwefghxyzABCijklDE

53 globalns = sys.modules[module_name].__dict__ 1mnopabcdqrFstuvwefghxyzABCijklDE

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) 1mnopabcdqrFstuvwefghxyzABCijklDE

58 

59 

60class PydanticMetadata(Representation): 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

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

62 

63 __slots__ = () 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

64 

65 

66def pydantic_general_metadata(**metadata: Any) -> BaseMetadata: 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

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

68 

69 Args: 

70 **metadata: The metadata to add. 

71 

72 Returns: 

73 The new `_PydanticGeneralMetadata` class. 

74 """ 

75 return _general_metadata_cls()(metadata) # type: ignore 1mnopabcdqrFstuvwefghxyzABCijklDE

76 

77 

78@lru_cache(maxsize=None) 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

79def _general_metadata_cls() -> type[BaseMetadata]: 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

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

81 from annotated_types import BaseMetadata 1mnopabcdqrFstuvwefghxyzABCijklDE

82 

83 class _PydanticGeneralMetadata(PydanticMetadata, BaseMetadata): 1mnopabcdqrFstuvwefghxyzABCijklDE

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

85 

86 def __init__(self, metadata: Any): 1mnopabcdqrFstuvwefghxyzABCijklDE

87 self.__dict__ = metadata 1mnopabcdqrFstuvwefghxyzABCijklDE

88 

89 return _PydanticGeneralMetadata # type: ignore 1mnopabcdqrFstuvwefghxyzABCijklDE

90 

91 

92def _update_fields_from_docstrings(cls: type[Any], fields: dict[str, FieldInfo], config_wrapper: ConfigWrapper) -> None: 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

93 if config_wrapper.use_attribute_docstrings: 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

94 fields_docs = extract_docstrings_from_cls(cls) 1mnopabcdqrFstuvwefghxyzABCijklDE

95 for ann_name, field_info in fields.items(): 1mnopabcdqrFstuvwefghxyzABCijklDE

96 if field_info.description is None and ann_name in fields_docs: 1mnopabcdqrFstuvwefghxyzABCijklDE

97 field_info.description = fields_docs[ann_name] 1mnopabcdqrFstuvwefghxyzABCijklDE

98 

99 

100def collect_model_fields( # noqa: C901 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

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. 

109 

110 Also collect the names of any ClassVars present in the type hints. 

111 

112 The returned value is a tuple of two items: the fields dict, and the set of ClassVar names. 

113 

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. 

120 

121 Returns: 

122 A tuple contains fields and class variables. 

123 

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

131 

132 type_hints = get_cls_type_hints_lenient(cls, types_namespace) 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

133 

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__', {}) 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

137 fields: dict[str, FieldInfo] = {} 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

138 

139 class_vars: set[str] = set() 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

140 for ann_name, ann_type in type_hints.items(): 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

141 if ann_name == 'model_config': 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

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

146 for protected_namespace in config_wrapper.protected_namespaces: 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

147 if ann_name.startswith(protected_namespace): 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

148 for b in bases: 1mnopabcdqrFstuvwefghxyzABCijklDE

149 if hasattr(b, ann_name): 1mnopabcdqrFstuvwefghxyzABCijklDE

150 from ..main import BaseModel 1mnopabcdqrFstuvwefghxyzABCijklDE

151 

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 true1mnopabcdqrFstuvwefghxyzABCijklDE

153 raise NameError( 1mnopabcdqrFstuvwefghxyzABCijklDE

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

159 x for x in config_wrapper.protected_namespaces if not ann_name.startswith(x) 

160 ) 

161 warnings.warn( 1mnopabcdqrFstuvwefghxyzABCijklDE

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): 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

168 class_vars.add(ann_name) 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

169 continue 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

170 if _is_finalvar_with_default_val(ann_type, getattr(cls, ann_name, PydanticUndefined)): 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

171 class_vars.add(ann_name) 1mnopabcdqrFstuvwefghxyzABCijklDE

172 continue 1mnopabcdqrFstuvwefghxyzABCijklDE

173 if not is_valid_field_name(ann_name): 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

174 continue 1mnopabcdqrFstuvwefghxyzABCijklDE

175 if cls.__pydantic_root_model__ and ann_name != 'root': 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

176 raise NameError( 1mnopabcdqrFstuvwefghxyzABCijklDE

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

178 ) 

179 

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') 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

183 for base in bases: 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

184 dataclass_fields = { 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

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

186 } 

187 if hasattr(base, ann_name): 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

188 if base is generic_origin: 188 ↛ 190line 188 didn't jump to line 190, because the condition on line 188 was never true1mnopabcdqrFstuvwefghxyzABCijklDE

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

190 continue 

191 

192 if ann_name in dataclass_fields: 1mnopabcdqrFstuvwefghxyzABCijklDE

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

194 # on the class instance. 

195 continue 1mnopabcdqrFstuvwefghxyzABCijklDE

196 

197 if ann_name not in annotations: 1mnopabcdqrFstuvwefghxyzABCijklDE

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

199 continue 1mnopabcdqrFstuvwefghxyzABCijklDE

200 

201 warnings.warn( 1mnopabcdqrFstuvwefghxyzABCijklDE

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

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

204 UserWarning, 

205 ) 

206 

207 try: 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

208 default = getattr(cls, ann_name, PydanticUndefined) 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

209 if default is PydanticUndefined: 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

210 raise AttributeError 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

211 except AttributeError: 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

212 if ann_name in annotations: 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

213 field_info = FieldInfo.from_annotation(ann_type) 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

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] = {} 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

218 for x in cls.__bases__[::-1]: 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

219 model_fields_lookup.update(getattr(x, 'model_fields', {})) 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

220 if ann_name in model_fields_lookup: 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

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]) 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

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) 1mnopabcdqrFstuvwefghxyzABCijklDE

229 else: 

230 _warn_on_nested_alias_in_annotation(ann_type, ann_name) 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

231 field_info = FieldInfo.from_annotated_attribute(ann_type, default) 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

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

236 delattr(cls, ann_name) 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

237 except AttributeError: 1mnopabcdqrFstuvwefghxyzABCijklDE

238 pass # indicates the attribute was on a parent class 1mnopabcdqrFstuvwefghxyzABCijklDE

239 

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__'] 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

243 if ann_name in decorators.computed_fields: 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

244 raise ValueError("you can't override a field with a computed field") 1mnopabcdqrFstuvwefghxyzABCijklDE

245 fields[ann_name] = field_info 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

246 

247 if typevars_map: 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

248 for field in fields.values(): 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

249 field.apply_typevars_map(typevars_map, types_namespace) 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

250 

251 _update_fields_from_docstrings(cls, fields, config_wrapper) 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

252 

253 return fields, class_vars 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

254 

255 

256def _warn_on_nested_alias_in_annotation(ann_type: type[Any], ann_name: str): 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

257 from ..fields import FieldInfo 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

258 

259 if hasattr(ann_type, '__args__'): 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

260 for anno_arg in ann_type.__args__: 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

261 if _typing_extra.is_annotated(anno_arg): 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

262 for anno_type_arg in _typing_extra.get_args(anno_arg): 1mnopabcdqrFstuvwefghxyzABCijklDE

263 if isinstance(anno_type_arg, FieldInfo) and anno_type_arg.alias is not None: 1mnopabcdqrFstuvwefghxyzABCijklDE

264 warnings.warn( 1mnopabcdqrFstuvwefghxyzABCijklDE

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

266 UserWarning, 

267 ) 

268 break 1mnopabcdqrFstuvwefghxyzABCijklDE

269 

270 

271def _is_finalvar_with_default_val(type_: type[Any], val: Any) -> bool: 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

272 from ..fields import FieldInfo 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

273 

274 if not is_finalvar(type_): 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

275 return False 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

276 elif val is PydanticUndefined: 1mnopabcdqrFstuvwefghxyzABCijklDE

277 return False 1mnopabcdqrFstuvwefghxyzABCijklDE

278 elif isinstance(val, FieldInfo) and (val.default is PydanticUndefined and val.default_factory is None): 1mnopabcdqrFstuvwefghxyzABCijklDE

279 return False 1mnopabcdqrFstuvwefghxyzABCijklDE

280 else: 

281 return True 1mnopabcdqrFstuvwefghxyzABCijklDE

282 

283 

284def collect_dataclass_fields( 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

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. 

292 

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. 

298 

299 Returns: 

300 The dataclass fields. 

301 """ 

302 from ..fields import FieldInfo 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

303 

304 fields: dict[str, FieldInfo] = {} 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

305 dataclass_fields: dict[str, dataclasses.Field] = cls.__dataclass_fields__ 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

306 cls_localns = dict(vars(cls)) # this matches get_cls_type_hints_lenient, but all tests pass with `= None` instead 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

307 

308 source_module = sys.modules.get(cls.__module__) 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

309 if source_module is not None: 309 ↛ 312line 309 didn't jump to line 312, because the condition on line 309 was always true1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

310 types_namespace = {**source_module.__dict__, **(types_namespace or {})} 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

311 

312 for ann_name, dataclass_field in dataclass_fields.items(): 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

313 ann_type = _typing_extra.eval_type_lenient(dataclass_field.type, types_namespace, cls_localns) 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

314 if is_classvar(ann_type): 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

315 continue 1mnopabcdqrFstuvwefghxyzABCijklDE

316 

317 if ( 1mnopabcdFstuvwefghGHIJKLMNzABCijkl

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

325 

326 if isinstance(dataclass_field.default, FieldInfo): 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

327 if dataclass_field.default.init_var: 1mnopabcdqrFstuvwefghxyzABCijklDE

328 if dataclass_field.default.init is False: 1mnopabcdqrFstuvwefghxyzABCijklDE

329 raise PydanticUserError( 1mnopabcdqrFstuvwefghxyzABCijklDE

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 ) 

333 

334 # TODO: same note as above re validate_assignment 

335 continue 1abcdqrsefghxyijklDE

336 field_info = FieldInfo.from_annotated_attribute(ann_type, dataclass_field.default) 1mnopabcdqrFstuvwefghxyzABCijklDE

337 else: 

338 field_info = FieldInfo.from_annotated_attribute(ann_type, dataclass_field) 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

339 

340 fields[ann_name] = field_info 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

341 

342 if field_info.default is not PydanticUndefined and isinstance(getattr(cls, ann_name, field_info), FieldInfo): 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

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) 1mnopabcdqrFstuvwefghxyzABCijklDE

345 

346 if typevars_map: 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

347 for field in fields.values(): 1mnopabcdqrFstuvwefghxyzABCijklDE

348 field.apply_typevars_map(typevars_map, types_namespace) 1mnopabcdqrFstuvwefghxyzABCijklDE

349 

350 if config_wrapper is not None: 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

351 _update_fields_from_docstrings(cls, fields, config_wrapper) 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

352 

353 return fields 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

354 

355 

356def is_valid_field_name(name: str) -> bool: 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

357 return not name.startswith('_') 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

358 

359 

360def is_valid_privateattr_name(name: str) -> bool: 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE

361 return name.startswith('_') and not name.startswith('__') 1mnopabcdqrFstuvwefghxyGHIJKLMNOzABCijklDE