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

137 statements  

« prev     ^ index     » next       coverage.py v7.5.4, created at 2024-07-03 19:29 +0000

1from __future__ import annotations as _annotations 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

2 

3import warnings 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

4from contextlib import contextmanager 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

5from typing import ( 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

6 TYPE_CHECKING, 

7 Any, 

8 Callable, 

9 cast, 

10) 

11 

12from pydantic_core import core_schema 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

13from typing_extensions import ( 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

14 Literal, 

15 Self, 

16) 

17 

18from ..aliases import AliasGenerator 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

19from ..config import ConfigDict, ExtraValues, JsonDict, JsonEncoder, JsonSchemaExtraCallable 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

20from ..errors import PydanticUserError 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

21from ..warnings import PydanticDeprecatedSince20 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

22 

23if not TYPE_CHECKING: 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

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

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

26 DeprecationWarning = PydanticDeprecatedSince20 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

27 

28if TYPE_CHECKING: 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

29 from .._internal._schema_generation_shared import GenerateSchema 

30 from ..fields import ComputedFieldInfo, FieldInfo 

31 

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

33 

34 

35class ConfigWrapper: 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

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

37 

38 __slots__ = ('config_dict',) 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

39 

40 config_dict: ConfigDict 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

41 

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

43 # stop matching 

44 title: str | None 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

45 str_to_lower: bool 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

46 str_to_upper: bool 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

47 str_strip_whitespace: bool 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

48 str_min_length: int 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

49 str_max_length: int | None 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

50 extra: ExtraValues | None 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

51 frozen: bool 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

52 populate_by_name: bool 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

53 use_enum_values: bool 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

54 validate_assignment: bool 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

55 arbitrary_types_allowed: bool 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

56 from_attributes: bool 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

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

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

59 loc_by_alias: bool 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

60 alias_generator: Callable[[str], str] | AliasGenerator | None 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

61 model_title_generator: Callable[[type], str] | None 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

62 field_title_generator: Callable[[str, FieldInfo | ComputedFieldInfo], str] | None 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

63 ignored_types: tuple[type, ...] 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

64 allow_inf_nan: bool 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

65 json_schema_extra: JsonDict | JsonSchemaExtraCallable | None 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

66 json_encoders: dict[type[object], JsonEncoder] | None 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

67 

68 # new in V2 

69 strict: bool 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

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

71 revalidate_instances: Literal['always', 'never', 'subclass-instances'] 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

72 ser_json_timedelta: Literal['iso8601', 'float'] 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

73 ser_json_bytes: Literal['utf8', 'base64'] 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

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

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

76 validate_default: bool 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

77 validate_return: bool 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

78 protected_namespaces: tuple[str, ...] 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

79 hide_input_in_errors: bool 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

80 defer_build: bool 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

81 experimental_defer_build_mode: tuple[Literal['model', 'type_adapter'], ...] 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

82 plugin_settings: dict[str, object] | None 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

83 schema_generator: type[GenerateSchema] | None 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

84 json_schema_serialization_defaults_required: bool 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

85 json_schema_mode_override: Literal['validation', 'serialization', None] 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

86 coerce_numbers_to_str: bool 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

87 regex_engine: Literal['rust-regex', 'python-re'] 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

88 validation_error_cause: bool 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

89 use_attribute_docstrings: bool 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

90 cache_strings: bool | Literal['all', 'keys', 'none'] 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

91 

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

93 if check: 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

94 self.config_dict = prepare_config(config) 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

95 else: 

96 self.config_dict = cast(ConfigDict, config) 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

97 

98 @classmethod 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

99 def for_model(cls, bases: tuple[type[Any], ...], namespace: dict[str, Any], kwargs: dict[str, Any]) -> Self: 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

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

101 

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

103 - options from `kwargs` 

104 - options from the `namespace` 

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

106 

107 Args: 

108 bases: A tuple of base classes. 

109 namespace: The namespace of the class being created. 

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

111 

112 Returns: 

113 A `ConfigWrapper` instance for `BaseModel`. 

114 """ 

115 config_new = ConfigDict() 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

116 for base in bases: 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

117 config = getattr(base, 'model_config', None) 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

118 if config: 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

119 config_new.update(config.copy()) 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

120 

121 config_class_from_namespace = namespace.get('Config') 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

122 config_dict_from_namespace = namespace.get('model_config') 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

123 

124 raw_annotations = namespace.get('__annotations__', {}) 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

125 if raw_annotations.get('model_config') and not config_dict_from_namespace: 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

126 raise PydanticUserError( 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKL

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

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

129 ) 

130 

131 if config_class_from_namespace and config_dict_from_namespace: 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

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

133 

134 config_from_namespace = config_dict_from_namespace or prepare_config(config_class_from_namespace) 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

135 

136 config_new.update(config_from_namespace) 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

137 

138 for k in list(kwargs.keys()): 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

139 if k in config_keys: 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

140 config_new[k] = kwargs.pop(k) 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

141 

142 return cls(config_new) 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

143 

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

145 if not TYPE_CHECKING: # pragma: no branch 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

146 

147 def __getattr__(self, name: str) -> Any: 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

148 try: 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

149 return self.config_dict[name] 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

150 except KeyError: 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

151 try: 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

152 return config_defaults[name] 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

153 except KeyError: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKL

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

155 

156 def core_config(self, obj: Any) -> core_schema.CoreConfig: 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

157 """Create a pydantic-core config, `obj` is just used to populate `title` if not set in config. 

158 

159 Pass `obj=None` if you do not want to attempt to infer the `title`. 

160 

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

162 

163 Args: 

164 obj: An object used to populate `title` if not set in config. 

165 

166 Returns: 

167 A `CoreConfig` object created from config. 

168 """ 

169 

170 def dict_not_none(**kwargs: Any) -> Any: 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

171 return {k: v for k, v in kwargs.items() if v is not None} 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

172 

173 core_config = core_schema.CoreConfig( 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

174 **dict_not_none( 

175 title=self.config_dict.get('title') or (obj and obj.__name__), 

176 extra_fields_behavior=self.config_dict.get('extra'), 

177 allow_inf_nan=self.config_dict.get('allow_inf_nan'), 

178 populate_by_name=self.config_dict.get('populate_by_name'), 

179 str_strip_whitespace=self.config_dict.get('str_strip_whitespace'), 

180 str_to_lower=self.config_dict.get('str_to_lower'), 

181 str_to_upper=self.config_dict.get('str_to_upper'), 

182 strict=self.config_dict.get('strict'), 

183 ser_json_timedelta=self.config_dict.get('ser_json_timedelta'), 

184 ser_json_bytes=self.config_dict.get('ser_json_bytes'), 

185 ser_json_inf_nan=self.config_dict.get('ser_json_inf_nan'), 

186 from_attributes=self.config_dict.get('from_attributes'), 

187 loc_by_alias=self.config_dict.get('loc_by_alias'), 

188 revalidate_instances=self.config_dict.get('revalidate_instances'), 

189 validate_default=self.config_dict.get('validate_default'), 

190 str_max_length=self.config_dict.get('str_max_length'), 

191 str_min_length=self.config_dict.get('str_min_length'), 

192 hide_input_in_errors=self.config_dict.get('hide_input_in_errors'), 

193 coerce_numbers_to_str=self.config_dict.get('coerce_numbers_to_str'), 

194 regex_engine=self.config_dict.get('regex_engine'), 

195 validation_error_cause=self.config_dict.get('validation_error_cause'), 

196 cache_strings=self.config_dict.get('cache_strings'), 

197 ) 

198 ) 

199 return core_config 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

200 

201 def __repr__(self): 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

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

203 return f'ConfigWrapper({c})' 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKL

204 

205 

206class ConfigWrapperStack: 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

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

208 

209 def __init__(self, config_wrapper: ConfigWrapper): 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

210 self._config_wrapper_stack: list[ConfigWrapper] = [config_wrapper] 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

211 

212 @property 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

213 def tail(self) -> ConfigWrapper: 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

214 return self._config_wrapper_stack[-1] 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

215 

216 @contextmanager 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

217 def push(self, config_wrapper: ConfigWrapper | ConfigDict | None): 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

218 if config_wrapper is None: 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

219 yield 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKL

220 return 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKL

221 

222 if not isinstance(config_wrapper, ConfigWrapper): 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

223 config_wrapper = ConfigWrapper(config_wrapper, check=False) 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

224 

225 self._config_wrapper_stack.append(config_wrapper) 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

226 try: 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

227 yield 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

228 finally: 

229 self._config_wrapper_stack.pop() 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

230 

231 

232config_defaults = ConfigDict( 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

233 title=None, 

234 str_to_lower=False, 

235 str_to_upper=False, 

236 str_strip_whitespace=False, 

237 str_min_length=0, 

238 str_max_length=None, 

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

240 extra=None, 

241 frozen=False, 

242 populate_by_name=False, 

243 use_enum_values=False, 

244 validate_assignment=False, 

245 arbitrary_types_allowed=False, 

246 from_attributes=False, 

247 loc_by_alias=True, 

248 alias_generator=None, 

249 model_title_generator=None, 

250 field_title_generator=None, 

251 ignored_types=(), 

252 allow_inf_nan=True, 

253 json_schema_extra=None, 

254 strict=False, 

255 revalidate_instances='never', 

256 ser_json_timedelta='iso8601', 

257 ser_json_bytes='utf8', 

258 ser_json_inf_nan='null', 

259 validate_default=False, 

260 validate_return=False, 

261 protected_namespaces=('model_',), 

262 hide_input_in_errors=False, 

263 json_encoders=None, 

264 defer_build=False, 

265 experimental_defer_build_mode=('model',), 

266 plugin_settings=None, 

267 schema_generator=None, 

268 json_schema_serialization_defaults_required=False, 

269 json_schema_mode_override=None, 

270 coerce_numbers_to_str=False, 

271 regex_engine='rust-regex', 

272 validation_error_cause=False, 

273 use_attribute_docstrings=False, 

274 cache_strings=True, 

275) 

276 

277 

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

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

280 

281 Args: 

282 config: The input config. 

283 

284 Returns: 

285 A ConfigDict object created from config. 

286 """ 

287 if config is None: 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

288 return ConfigDict() 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

289 

290 if not isinstance(config, dict): 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

291 warnings.warn(DEPRECATION_MESSAGE, DeprecationWarning) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKL

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

293 

294 config_dict = cast(ConfigDict, config) 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

295 check_deprecated(config_dict) 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

296 return config_dict 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

297 

298 

299config_keys = set(ConfigDict.__annotations__.keys()) 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

300 

301 

302V2_REMOVED_KEYS = { 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

303 'allow_mutation', 

304 'error_msg_templates', 

305 'fields', 

306 'getter_dict', 

307 'smart_union', 

308 'underscore_attrs_are_private', 

309 'json_loads', 

310 'json_dumps', 

311 'copy_on_model_validation', 

312 'post_init_call', 

313} 

314V2_RENAMED_KEYS = { 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

315 'allow_population_by_field_name': 'populate_by_name', 

316 'anystr_lower': 'str_to_lower', 

317 'anystr_strip_whitespace': 'str_strip_whitespace', 

318 'anystr_upper': 'str_to_upper', 

319 'keep_untouched': 'ignored_types', 

320 'max_anystr_length': 'str_max_length', 

321 'min_anystr_length': 'str_min_length', 

322 'orm_mode': 'from_attributes', 

323 'schema_extra': 'json_schema_extra', 

324 'validate_all': 'validate_default', 

325} 

326 

327 

328def check_deprecated(config_dict: ConfigDict) -> None: 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

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

330 

331 Args: 

332 config_dict: The input config. 

333 """ 

334 deprecated_removed_keys = V2_REMOVED_KEYS & config_dict.keys() 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

335 deprecated_renamed_keys = V2_RENAMED_KEYS.keys() & config_dict.keys() 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

336 if deprecated_removed_keys or deprecated_renamed_keys: 1abcdefghijklmnopqrstuvwxyzMNOPQRSTUVABCDEFGHIJKL

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

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

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

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

341 warnings.warn(message, UserWarning) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKL