Coverage for pydantic/_internal/_config.py: 100.00%

148 statements  

« prev     ^ index     » next       coverage.py v7.10.0, created at 2025-07-26 11:49 +0000

1from __future__ import annotations as _annotations 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

2 

3import warnings 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

4from contextlib import contextmanager 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

5from re import Pattern 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

6from typing import ( 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

7 TYPE_CHECKING, 

8 Any, 

9 Callable, 

10 Literal, 

11 cast, 

12) 

13 

14from pydantic_core import core_schema 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

15from typing_extensions import Self 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

16 

17from ..aliases import AliasGenerator 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

18from ..config import ConfigDict, ExtraValues, JsonDict, JsonEncoder, JsonSchemaExtraCallable 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

19from ..errors import PydanticUserError 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

20from ..warnings import PydanticDeprecatedSince20, PydanticDeprecatedSince210 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

21 

22if not TYPE_CHECKING: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

23 # See PyCharm issues https://youtrack.jetbrains.com/issue/PY-21915 

24 # and https://youtrack.jetbrains.com/issue/PY-51428 

25 DeprecationWarning = PydanticDeprecatedSince20 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

26 

27if TYPE_CHECKING: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

28 from .._internal._schema_generation_shared import GenerateSchema 

29 from ..fields import ComputedFieldInfo, FieldInfo 

30 

31DEPRECATION_MESSAGE = 'Support for class-based `config` is deprecated, use ConfigDict instead.' 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

32 

33 

34class ConfigWrapper: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

35 """Internal wrapper for Config which exposes ConfigDict items as attributes.""" 

36 

37 __slots__ = ('config_dict',) 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

38 

39 config_dict: ConfigDict 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

40 

41 # all annotations are copied directly from ConfigDict, and should be kept up to date, a test will fail if they 

42 # stop matching 

43 title: str | None 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

44 str_to_lower: bool 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

45 str_to_upper: bool 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

46 str_strip_whitespace: bool 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

47 str_min_length: int 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

48 str_max_length: int | None 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

49 extra: ExtraValues | None 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

50 frozen: bool 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

51 populate_by_name: bool 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

52 use_enum_values: bool 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

53 validate_assignment: bool 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

54 arbitrary_types_allowed: bool 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

55 from_attributes: bool 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

56 # whether to use the actual key provided in the data (e.g. alias or first alias for "field required" errors) instead of field_names 

57 # to construct error `loc`s, default `True` 

58 loc_by_alias: bool 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

59 alias_generator: Callable[[str], str] | AliasGenerator | None 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

60 model_title_generator: Callable[[type], str] | None 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

61 field_title_generator: Callable[[str, FieldInfo | ComputedFieldInfo], str] | None 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

62 ignored_types: tuple[type, ...] 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

63 allow_inf_nan: bool 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

64 json_schema_extra: JsonDict | JsonSchemaExtraCallable | None 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

65 json_encoders: dict[type[object], JsonEncoder] | None 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

66 

67 # new in V2 

68 strict: bool 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

69 # whether instances of models and dataclasses (including subclass instances) should re-validate, default 'never' 

70 revalidate_instances: Literal['always', 'never', 'subclass-instances'] 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

71 ser_json_timedelta: Literal['iso8601', 'float'] 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

72 ser_json_bytes: Literal['utf8', 'base64', 'hex'] 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

73 val_json_bytes: Literal['utf8', 'base64', 'hex'] 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

74 ser_json_inf_nan: Literal['null', 'constants', 'strings'] 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

75 # whether to validate default values during validation, default False 

76 validate_default: bool 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

77 validate_return: bool 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

78 protected_namespaces: tuple[str | Pattern[str], ...] 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

79 hide_input_in_errors: bool 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

80 defer_build: bool 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

81 plugin_settings: dict[str, object] | None 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

82 schema_generator: type[GenerateSchema] | None 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

83 json_schema_serialization_defaults_required: bool 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

84 json_schema_mode_override: Literal['validation', 'serialization', None] 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

85 coerce_numbers_to_str: bool 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

86 regex_engine: Literal['rust-regex', 'python-re'] 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

87 validation_error_cause: bool 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

88 use_attribute_docstrings: bool 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

89 cache_strings: bool | Literal['all', 'keys', 'none'] 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

90 validate_by_alias: bool 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

91 validate_by_name: bool 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

92 serialize_by_alias: bool 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

93 

94 def __init__(self, config: ConfigDict | dict[str, Any] | type[Any] | None, *, check: bool = True): 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

95 if check: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

96 self.config_dict = prepare_config(config) 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

97 else: 

98 self.config_dict = cast(ConfigDict, config) 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

99 

100 @classmethod 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

101 def for_model( 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

102 cls, 

103 bases: tuple[type[Any], ...], 

104 namespace: dict[str, Any], 

105 raw_annotations: dict[str, Any], 

106 kwargs: dict[str, Any], 

107 ) -> Self: 

108 """Build a new `ConfigWrapper` instance for a `BaseModel`. 

109 

110 The config wrapper built based on (in descending order of priority): 

111 - options from `kwargs` 

112 - options from the `namespace` 

113 - options from the base classes (`bases`) 

114 

115 Args: 

116 bases: A tuple of base classes. 

117 namespace: The namespace of the class being created. 

118 raw_annotations: The (non-evaluated) annotations of the model. 

119 kwargs: The kwargs passed to the class being created. 

120 

121 Returns: 

122 A `ConfigWrapper` instance for `BaseModel`. 

123 """ 

124 config_new = ConfigDict() 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

125 for base in bases: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

126 config = getattr(base, 'model_config', None) 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

127 if config: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

128 config_new.update(config.copy()) 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

129 

130 config_class_from_namespace = namespace.get('Config') 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

131 config_dict_from_namespace = namespace.get('model_config') 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

132 

133 if raw_annotations.get('model_config') and config_dict_from_namespace is None: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

134 raise PydanticUserError( 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

135 '`model_config` cannot be used as a model field name. Use `model_config` for model configuration.', 

136 code='model-config-invalid-field-name', 

137 ) 

138 

139 if config_class_from_namespace and config_dict_from_namespace: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

140 raise PydanticUserError('"Config" and "model_config" cannot be used together', code='config-both') 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

141 

142 config_from_namespace = config_dict_from_namespace or prepare_config(config_class_from_namespace) 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

143 

144 config_new.update(config_from_namespace) 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

145 

146 for k in list(kwargs.keys()): 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

147 if k in config_keys: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

148 config_new[k] = kwargs.pop(k) 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

149 

150 return cls(config_new) 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

151 

152 # we don't show `__getattr__` to type checkers so missing attributes cause errors 

153 if not TYPE_CHECKING: # pragma: no branch 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

154 

155 def __getattr__(self, name: str) -> Any: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

156 try: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

157 return self.config_dict[name] 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

158 except KeyError: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

159 try: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

160 return config_defaults[name] 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

161 except KeyError: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

162 raise AttributeError(f'Config has no attribute {name!r}') from None 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

163 

164 def core_config(self, title: str | None) -> core_schema.CoreConfig: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

165 """Create a pydantic-core config. 

166 

167 We don't use getattr here since we don't want to populate with defaults. 

168 

169 Args: 

170 title: The title to use if not set in config. 

171 

172 Returns: 

173 A `CoreConfig` object created from config. 

174 """ 

175 config = self.config_dict 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

176 

177 if config.get('schema_generator') is not None: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

178 warnings.warn( 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

179 'The `schema_generator` setting has been deprecated since v2.10. This setting no longer has any effect.', 

180 PydanticDeprecatedSince210, 

181 stacklevel=2, 

182 ) 

183 

184 if (populate_by_name := config.get('populate_by_name')) is not None: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

185 # We include this patch for backwards compatibility purposes, but this config setting will be deprecated in v3.0, and likely removed in v4.0. 

186 # Thus, the above warning and this patch can be removed then as well. 

187 if config.get('validate_by_name') is None: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

188 config['validate_by_alias'] = True 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

189 config['validate_by_name'] = populate_by_name 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

190 

191 # We dynamically patch validate_by_name to be True if validate_by_alias is set to False 

192 # and validate_by_name is not explicitly set. 

193 if config.get('validate_by_alias') is False and config.get('validate_by_name') is None: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

194 config['validate_by_name'] = True 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

195 

196 if (not config.get('validate_by_alias', True)) and (not config.get('validate_by_name', False)): 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

197 raise PydanticUserError( 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

198 'At least one of `validate_by_alias` or `validate_by_name` must be set to True.', 

199 code='validate-by-alias-and-name-false', 

200 ) 

201 

202 return core_schema.CoreConfig( 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

203 **{ # pyright: ignore[reportArgumentType] 

204 k: v 

205 for k, v in ( 

206 ('title', config.get('title') or title or None), 

207 ('extra_fields_behavior', config.get('extra')), 

208 ('allow_inf_nan', config.get('allow_inf_nan')), 

209 ('str_strip_whitespace', config.get('str_strip_whitespace')), 

210 ('str_to_lower', config.get('str_to_lower')), 

211 ('str_to_upper', config.get('str_to_upper')), 

212 ('strict', config.get('strict')), 

213 ('ser_json_timedelta', config.get('ser_json_timedelta')), 

214 ('ser_json_bytes', config.get('ser_json_bytes')), 

215 ('val_json_bytes', config.get('val_json_bytes')), 

216 ('ser_json_inf_nan', config.get('ser_json_inf_nan')), 

217 ('from_attributes', config.get('from_attributes')), 

218 ('loc_by_alias', config.get('loc_by_alias')), 

219 ('revalidate_instances', config.get('revalidate_instances')), 

220 ('validate_default', config.get('validate_default')), 

221 ('str_max_length', config.get('str_max_length')), 

222 ('str_min_length', config.get('str_min_length')), 

223 ('hide_input_in_errors', config.get('hide_input_in_errors')), 

224 ('coerce_numbers_to_str', config.get('coerce_numbers_to_str')), 

225 ('regex_engine', config.get('regex_engine')), 

226 ('validation_error_cause', config.get('validation_error_cause')), 

227 ('cache_strings', config.get('cache_strings')), 

228 ('validate_by_alias', config.get('validate_by_alias')), 

229 ('validate_by_name', config.get('validate_by_name')), 

230 ('serialize_by_alias', config.get('serialize_by_alias')), 

231 ) 

232 if v is not None 

233 } 

234 ) 

235 

236 def __repr__(self): 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

237 c = ', '.join(f'{k}={v!r}' for k, v in self.config_dict.items()) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

238 return f'ConfigWrapper({c})' 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

239 

240 

241class ConfigWrapperStack: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

242 """A stack of `ConfigWrapper` instances.""" 

243 

244 def __init__(self, config_wrapper: ConfigWrapper): 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

245 self._config_wrapper_stack: list[ConfigWrapper] = [config_wrapper] 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

246 

247 @property 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

248 def tail(self) -> ConfigWrapper: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

249 return self._config_wrapper_stack[-1] 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

250 

251 @contextmanager 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

252 def push(self, config_wrapper: ConfigWrapper | ConfigDict | None): 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

253 if config_wrapper is None: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

254 yield 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

255 return 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

256 

257 if not isinstance(config_wrapper, ConfigWrapper): 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

258 config_wrapper = ConfigWrapper(config_wrapper, check=False) 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

259 

260 self._config_wrapper_stack.append(config_wrapper) 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

261 try: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

262 yield 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

263 finally: 

264 self._config_wrapper_stack.pop() 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

265 

266 

267config_defaults = ConfigDict( 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

268 title=None, 

269 str_to_lower=False, 

270 str_to_upper=False, 

271 str_strip_whitespace=False, 

272 str_min_length=0, 

273 str_max_length=None, 

274 # let the model / dataclass decide how to handle it 

275 extra=None, 

276 frozen=False, 

277 populate_by_name=False, 

278 use_enum_values=False, 

279 validate_assignment=False, 

280 arbitrary_types_allowed=False, 

281 from_attributes=False, 

282 loc_by_alias=True, 

283 alias_generator=None, 

284 model_title_generator=None, 

285 field_title_generator=None, 

286 ignored_types=(), 

287 allow_inf_nan=True, 

288 json_schema_extra=None, 

289 strict=False, 

290 revalidate_instances='never', 

291 ser_json_timedelta='iso8601', 

292 ser_json_bytes='utf8', 

293 val_json_bytes='utf8', 

294 ser_json_inf_nan='null', 

295 validate_default=False, 

296 validate_return=False, 

297 protected_namespaces=('model_validate', 'model_dump'), 

298 hide_input_in_errors=False, 

299 json_encoders=None, 

300 defer_build=False, 

301 schema_generator=None, 

302 plugin_settings=None, 

303 json_schema_serialization_defaults_required=False, 

304 json_schema_mode_override=None, 

305 coerce_numbers_to_str=False, 

306 regex_engine='rust-regex', 

307 validation_error_cause=False, 

308 use_attribute_docstrings=False, 

309 cache_strings=True, 

310 validate_by_alias=True, 

311 validate_by_name=False, 

312 serialize_by_alias=False, 

313) 

314 

315 

316def prepare_config(config: ConfigDict | dict[str, Any] | type[Any] | None) -> ConfigDict: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

317 """Create a `ConfigDict` instance from an existing dict, a class (e.g. old class-based config) or None. 

318 

319 Args: 

320 config: The input config. 

321 

322 Returns: 

323 A ConfigDict object created from config. 

324 """ 

325 if config is None: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

326 return ConfigDict() 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

327 

328 if not isinstance(config, dict): 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

329 warnings.warn(DEPRECATION_MESSAGE, DeprecationWarning, stacklevel=4) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

330 config = {k: getattr(config, k) for k in dir(config) if not k.startswith('__')} 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

331 

332 config_dict = cast(ConfigDict, config) 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

333 check_deprecated(config_dict) 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

334 return config_dict 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

335 

336 

337config_keys = set(ConfigDict.__annotations__.keys()) 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

338 

339 

340V2_REMOVED_KEYS = { 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

341 'allow_mutation', 

342 'error_msg_templates', 

343 'fields', 

344 'getter_dict', 

345 'smart_union', 

346 'underscore_attrs_are_private', 

347 'json_loads', 

348 'json_dumps', 

349 'copy_on_model_validation', 

350 'post_init_call', 

351} 

352V2_RENAMED_KEYS = { 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

353 'allow_population_by_field_name': 'validate_by_name', 

354 'anystr_lower': 'str_to_lower', 

355 'anystr_strip_whitespace': 'str_strip_whitespace', 

356 'anystr_upper': 'str_to_upper', 

357 'keep_untouched': 'ignored_types', 

358 'max_anystr_length': 'str_max_length', 

359 'min_anystr_length': 'str_min_length', 

360 'orm_mode': 'from_attributes', 

361 'schema_extra': 'json_schema_extra', 

362 'validate_all': 'validate_default', 

363} 

364 

365 

366def check_deprecated(config_dict: ConfigDict) -> None: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

367 """Check for deprecated config keys and warn the user. 

368 

369 Args: 

370 config_dict: The input config. 

371 """ 

372 deprecated_removed_keys = V2_REMOVED_KEYS & config_dict.keys() 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

373 deprecated_renamed_keys = V2_RENAMED_KEYS.keys() & config_dict.keys() 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

374 if deprecated_removed_keys or deprecated_renamed_keys: 1abcdefghijklmnopqrstuvwxyzABPCDEFGHIJKLMNO

375 renamings = {k: V2_RENAMED_KEYS[k] for k in sorted(deprecated_renamed_keys)} 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

376 renamed_bullets = [f'* {k!r} has been renamed to {v!r}' for k, v in renamings.items()] 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

377 removed_bullets = [f'* {k!r} has been removed' for k in sorted(deprecated_removed_keys)] 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

378 message = '\n'.join(['Valid config keys have changed in V2:'] + renamed_bullets + removed_bullets) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO

379 warnings.warn(message, UserWarning) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO