Coverage for pydantic/_internal/_config.py: 100.00%
148 statements
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-20 16:49 +0000
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-20 16:49 +0000
1from __future__ import annotations as _annotations 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
3import warnings 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
4from contextlib import contextmanager 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
5from re import Pattern 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
6from typing import ( 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
7 TYPE_CHECKING,
8 Any,
9 Callable,
10 Literal,
11 cast,
12)
14from pydantic_core import core_schema 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
15from typing_extensions import Self 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
17from ..aliases import AliasGenerator 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
18from ..config import ConfigDict, ExtraValues, JsonDict, JsonEncoder, JsonSchemaExtraCallable 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
19from ..errors import PydanticUserError 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
20from ..warnings import PydanticDeprecatedSince20, PydanticDeprecatedSince210 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
22if not TYPE_CHECKING: 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
23 # See PyCharm issues https://youtrack.jetbrains.com/issue/PY-21915
24 # and https://youtrack.jetbrains.com/issue/PY-51428
25 DeprecationWarning = PydanticDeprecatedSince20 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
27if TYPE_CHECKING: 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
28 from .._internal._schema_generation_shared import GenerateSchema
29 from ..fields import ComputedFieldInfo, FieldInfo
31DEPRECATION_MESSAGE = 'Support for class-based `config` is deprecated, use ConfigDict instead.' 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
34class ConfigWrapper: 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
35 """Internal wrapper for Config which exposes ConfigDict items as attributes."""
37 __slots__ = ('config_dict',) 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
39 config_dict: ConfigDict 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
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 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
44 str_to_lower: bool 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
45 str_to_upper: bool 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
46 str_strip_whitespace: bool 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
47 str_min_length: int 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
48 str_max_length: int | None 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
49 extra: ExtraValues | None 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
50 frozen: bool 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
51 populate_by_name: bool 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
52 use_enum_values: bool 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
53 validate_assignment: bool 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
54 arbitrary_types_allowed: bool 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
55 from_attributes: bool 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
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 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
59 alias_generator: Callable[[str], str] | AliasGenerator | None 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
60 model_title_generator: Callable[[type], str] | None 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
61 field_title_generator: Callable[[str, FieldInfo | ComputedFieldInfo], str] | None 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
62 ignored_types: tuple[type, ...] 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
63 allow_inf_nan: bool 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
64 json_schema_extra: JsonDict | JsonSchemaExtraCallable | None 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
65 json_encoders: dict[type[object], JsonEncoder] | None 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
67 # new in V2
68 strict: bool 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
69 # whether instances of models and dataclasses (including subclass instances) should re-validate, default 'never'
70 revalidate_instances: Literal['always', 'never', 'subclass-instances'] 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
71 ser_json_timedelta: Literal['iso8601', 'float'] 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
72 ser_json_bytes: Literal['utf8', 'base64', 'hex'] 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
73 val_json_bytes: Literal['utf8', 'base64', 'hex'] 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
74 ser_json_inf_nan: Literal['null', 'constants', 'strings'] 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
75 # whether to validate default values during validation, default False
76 validate_default: bool 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
77 validate_return: bool 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
78 protected_namespaces: tuple[str | Pattern[str], ...] 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
79 hide_input_in_errors: bool 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
80 defer_build: bool 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
81 plugin_settings: dict[str, object] | None 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
82 schema_generator: type[GenerateSchema] | None 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
83 json_schema_serialization_defaults_required: bool 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
84 json_schema_mode_override: Literal['validation', 'serialization', None] 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
85 coerce_numbers_to_str: bool 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
86 regex_engine: Literal['rust-regex', 'python-re'] 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
87 validation_error_cause: bool 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
88 use_attribute_docstrings: bool 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
89 cache_strings: bool | Literal['all', 'keys', 'none'] 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
90 validate_by_alias: bool 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
91 validate_by_name: bool 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
92 serialize_by_alias: bool 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
94 def __init__(self, config: ConfigDict | dict[str, Any] | type[Any] | None, *, check: bool = True): 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
95 if check: 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
96 self.config_dict = prepare_config(config) 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
97 else:
98 self.config_dict = cast(ConfigDict, config) 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
100 @classmethod 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
101 def for_model( 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
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`.
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`)
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.
121 Returns:
122 A `ConfigWrapper` instance for `BaseModel`.
123 """
124 config_new = ConfigDict() 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
125 for base in bases: 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
126 config = getattr(base, 'model_config', None) 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
127 if config: 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
128 config_new.update(config.copy()) 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
130 config_class_from_namespace = namespace.get('Config') 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
131 config_dict_from_namespace = namespace.get('model_config') 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
133 if raw_annotations.get('model_config') and config_dict_from_namespace is None: 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
134 raise PydanticUserError( 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKL
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 )
139 if config_class_from_namespace and config_dict_from_namespace: 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
140 raise PydanticUserError('"Config" and "model_config" cannot be used together', code='config-both') 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKL
142 config_from_namespace = config_dict_from_namespace or prepare_config(config_class_from_namespace) 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
144 config_new.update(config_from_namespace) 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
146 for k in list(kwargs.keys()): 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
147 if k in config_keys: 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
148 config_new[k] = kwargs.pop(k) 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
150 return cls(config_new) 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
152 # we don't show `__getattr__` to type checkers so missing attributes cause errors
153 if not TYPE_CHECKING: # pragma: no branch 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
155 def __getattr__(self, name: str) -> Any: 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
156 try: 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
157 return self.config_dict[name] 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
158 except KeyError: 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
159 try: 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
160 return config_defaults[name] 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
161 except KeyError: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKL
162 raise AttributeError(f'Config has no attribute {name!r}') from None 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKL
164 def core_config(self, title: str | None) -> core_schema.CoreConfig: 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
165 """Create a pydantic-core config.
167 We don't use getattr here since we don't want to populate with defaults.
169 Args:
170 title: The title to use if not set in config.
172 Returns:
173 A `CoreConfig` object created from config.
174 """
175 config = self.config_dict 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
177 if config.get('schema_generator') is not None: 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
178 warnings.warn( 1abcdefghijklMmnopqrstuvwxyzNABCDEFGHIJKLO
179 'The `schema_generator` setting has been deprecated since v2.10. This setting no longer has any effect.',
180 PydanticDeprecatedSince210,
181 stacklevel=2,
182 )
184 if (populate_by_name := config.get('populate_by_name')) is not None: 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
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: 1abcdefghijklmnopqrstuvwxyzPABCDEFGHIJKL
188 config['validate_by_alias'] = True 1abcdefghijklmnopqrstuvwxyzPABCDEFGHIJKL
189 config['validate_by_name'] = populate_by_name 1abcdefghijklmnopqrstuvwxyzPABCDEFGHIJKL
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: 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
194 config['validate_by_name'] = True 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKL
196 if (not config.get('validate_by_alias', True)) and (not config.get('validate_by_name', False)): 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
197 raise PydanticUserError( 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKL
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 )
202 return core_schema.CoreConfig( 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
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 )
236 def __repr__(self): 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
237 c = ', '.join(f'{k}={v!r}' for k, v in self.config_dict.items()) 1abcdefghijklMmnopqrstuvwxyzNABCDEFGHIJKLO
238 return f'ConfigWrapper({c})' 1abcdefghijklMmnopqrstuvwxyzNABCDEFGHIJKLO
241class ConfigWrapperStack: 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
242 """A stack of `ConfigWrapper` instances."""
244 def __init__(self, config_wrapper: ConfigWrapper): 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
245 self._config_wrapper_stack: list[ConfigWrapper] = [config_wrapper] 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
247 @property 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
248 def tail(self) -> ConfigWrapper: 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
249 return self._config_wrapper_stack[-1] 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
251 @contextmanager 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
252 def push(self, config_wrapper: ConfigWrapper | ConfigDict | None): 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
253 if config_wrapper is None: 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
254 yield 1abcdefghijklMmnopqrstuvwxyzNABCDEFGHIJKLO
255 return 1abcdefghijklMmnopqrstuvwxyzNABCDEFGHIJKLO
257 if not isinstance(config_wrapper, ConfigWrapper): 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
258 config_wrapper = ConfigWrapper(config_wrapper, check=False) 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
260 self._config_wrapper_stack.append(config_wrapper) 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
261 try: 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
262 yield 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
263 finally:
264 self._config_wrapper_stack.pop() 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
267config_defaults = ConfigDict( 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
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)
316def prepare_config(config: ConfigDict | dict[str, Any] | type[Any] | None) -> ConfigDict: 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
317 """Create a `ConfigDict` instance from an existing dict, a class (e.g. old class-based config) or None.
319 Args:
320 config: The input config.
322 Returns:
323 A ConfigDict object created from config.
324 """
325 if config is None: 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
326 return ConfigDict() 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
328 if not isinstance(config, dict): 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
329 warnings.warn(DEPRECATION_MESSAGE, DeprecationWarning) 1abcdefghijklMmnopqrstuvwxyzNABCDEFGHIJKLO
330 config = {k: getattr(config, k) for k in dir(config) if not k.startswith('__')} 1abcdefghijklMmnopqrstuvwxyzNABCDEFGHIJKLO
332 config_dict = cast(ConfigDict, config) 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
333 check_deprecated(config_dict) 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
334 return config_dict 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
337config_keys = set(ConfigDict.__annotations__.keys()) 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
340V2_REMOVED_KEYS = { 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
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 = { 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
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}
366def check_deprecated(config_dict: ConfigDict) -> None: 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
367 """Check for deprecated config keys and warn the user.
369 Args:
370 config_dict: The input config.
371 """
372 deprecated_removed_keys = V2_REMOVED_KEYS & config_dict.keys() 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
373 deprecated_renamed_keys = V2_RENAMED_KEYS.keys() & config_dict.keys() 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
374 if deprecated_removed_keys or deprecated_renamed_keys: 1abcdefghijklMmnopqrstuvwxyzNPABCDEFGHIJKLO
375 renamings = {k: V2_RENAMED_KEYS[k] for k in sorted(deprecated_renamed_keys)} 1abcdefghijklMmnopqrstuvwxyzNABCDEFGHIJKLO
376 renamed_bullets = [f'* {k!r} has been renamed to {v!r}' for k, v in renamings.items()] 1abcdefghijklMmnopqrstuvwxyzNABCDEFGHIJKLO
377 removed_bullets = [f'* {k!r} has been removed' for k in sorted(deprecated_removed_keys)] 1abcdefghijklMmnopqrstuvwxyzNABCDEFGHIJKLO
378 message = '\n'.join(['Valid config keys have changed in V2:'] + renamed_bullets + removed_bullets) 1abcdefghijklMmnopqrstuvwxyzNABCDEFGHIJKLO
379 warnings.warn(message, UserWarning) 1abcdefghijklMmnopqrstuvwxyzNABCDEFGHIJKLO