1import sys
2from typing import Any, Callable
3
4from .version import version_short
5
6MOVED_IN_V2 = {
7 'pydantic.utils:version_info': 'pydantic.version:version_info',
8 'pydantic.error_wrappers:ValidationError': 'pydantic:ValidationError',
9 'pydantic.utils:to_camel': 'pydantic.alias_generators:to_pascal',
10 'pydantic.utils:to_lower_camel': 'pydantic.alias_generators:to_camel',
11 'pydantic:PyObject': 'pydantic.types:ImportString',
12 'pydantic.types:PyObject': 'pydantic.types:ImportString',
13 'pydantic.generics:GenericModel': 'pydantic.BaseModel',
14}
15
16DEPRECATED_MOVED_IN_V2 = {
17 'pydantic.tools:schema_of': 'pydantic.deprecated.tools:schema_of',
18 'pydantic.tools:parse_obj_as': 'pydantic.deprecated.tools:parse_obj_as',
19 'pydantic.tools:schema_json_of': 'pydantic.deprecated.tools:schema_json_of',
20 'pydantic.json:pydantic_encoder': 'pydantic.deprecated.json:pydantic_encoder',
21 'pydantic:validate_arguments': 'pydantic.deprecated.decorator:validate_arguments',
22 'pydantic.json:custom_pydantic_encoder': 'pydantic.deprecated.json:custom_pydantic_encoder',
23 'pydantic.json:timedelta_isoformat': 'pydantic.deprecated.json:timedelta_isoformat',
24 'pydantic.decorator:validate_arguments': 'pydantic.deprecated.decorator:validate_arguments',
25 'pydantic.class_validators:validator': 'pydantic.deprecated.class_validators:validator',
26 'pydantic.class_validators:root_validator': 'pydantic.deprecated.class_validators:root_validator',
27 'pydantic.config:BaseConfig': 'pydantic.deprecated.config:BaseConfig',
28 'pydantic.config:Extra': 'pydantic.deprecated.config:Extra',
29}
30
31REDIRECT_TO_V1 = {
32 f'pydantic.utils:{obj}': f'pydantic.v1.utils:{obj}'
33 for obj in (
34 'deep_update',
35 'GetterDict',
36 'lenient_issubclass',
37 'lenient_isinstance',
38 'is_valid_field',
39 'update_not_none',
40 'import_string',
41 'Representation',
42 'ROOT_KEY',
43 'smart_deepcopy',
44 'sequence_like',
45 )
46}
47
48
49REMOVED_IN_V2 = {
50 'pydantic:ConstrainedBytes',
51 'pydantic:ConstrainedDate',
52 'pydantic:ConstrainedDecimal',
53 'pydantic:ConstrainedFloat',
54 'pydantic:ConstrainedFrozenSet',
55 'pydantic:ConstrainedInt',
56 'pydantic:ConstrainedList',
57 'pydantic:ConstrainedSet',
58 'pydantic:ConstrainedStr',
59 'pydantic:JsonWrapper',
60 'pydantic:NoneBytes',
61 'pydantic:NoneStr',
62 'pydantic:NoneStrBytes',
63 'pydantic:Protocol',
64 'pydantic:Required',
65 'pydantic:StrBytes',
66 'pydantic:compiled',
67 'pydantic.config:get_config',
68 'pydantic.config:inherit_config',
69 'pydantic.config:prepare_config',
70 'pydantic:create_model_from_namedtuple',
71 'pydantic:create_model_from_typeddict',
72 'pydantic.dataclasses:create_pydantic_model_from_dataclass',
73 'pydantic.dataclasses:make_dataclass_validator',
74 'pydantic.dataclasses:set_validation',
75 'pydantic.datetime_parse:parse_date',
76 'pydantic.datetime_parse:parse_time',
77 'pydantic.datetime_parse:parse_datetime',
78 'pydantic.datetime_parse:parse_duration',
79 'pydantic.error_wrappers:ErrorWrapper',
80 'pydantic.errors:AnyStrMaxLengthError',
81 'pydantic.errors:AnyStrMinLengthError',
82 'pydantic.errors:ArbitraryTypeError',
83 'pydantic.errors:BoolError',
84 'pydantic.errors:BytesError',
85 'pydantic.errors:CallableError',
86 'pydantic.errors:ClassError',
87 'pydantic.errors:ColorError',
88 'pydantic.errors:ConfigError',
89 'pydantic.errors:DataclassTypeError',
90 'pydantic.errors:DateError',
91 'pydantic.errors:DateNotInTheFutureError',
92 'pydantic.errors:DateNotInThePastError',
93 'pydantic.errors:DateTimeError',
94 'pydantic.errors:DecimalError',
95 'pydantic.errors:DecimalIsNotFiniteError',
96 'pydantic.errors:DecimalMaxDigitsError',
97 'pydantic.errors:DecimalMaxPlacesError',
98 'pydantic.errors:DecimalWholeDigitsError',
99 'pydantic.errors:DictError',
100 'pydantic.errors:DurationError',
101 'pydantic.errors:EmailError',
102 'pydantic.errors:EnumError',
103 'pydantic.errors:EnumMemberError',
104 'pydantic.errors:ExtraError',
105 'pydantic.errors:FloatError',
106 'pydantic.errors:FrozenSetError',
107 'pydantic.errors:FrozenSetMaxLengthError',
108 'pydantic.errors:FrozenSetMinLengthError',
109 'pydantic.errors:HashableError',
110 'pydantic.errors:IPv4AddressError',
111 'pydantic.errors:IPv4InterfaceError',
112 'pydantic.errors:IPv4NetworkError',
113 'pydantic.errors:IPv6AddressError',
114 'pydantic.errors:IPv6InterfaceError',
115 'pydantic.errors:IPv6NetworkError',
116 'pydantic.errors:IPvAnyAddressError',
117 'pydantic.errors:IPvAnyInterfaceError',
118 'pydantic.errors:IPvAnyNetworkError',
119 'pydantic.errors:IntEnumError',
120 'pydantic.errors:IntegerError',
121 'pydantic.errors:InvalidByteSize',
122 'pydantic.errors:InvalidByteSizeUnit',
123 'pydantic.errors:InvalidDiscriminator',
124 'pydantic.errors:InvalidLengthForBrand',
125 'pydantic.errors:JsonError',
126 'pydantic.errors:JsonTypeError',
127 'pydantic.errors:ListError',
128 'pydantic.errors:ListMaxLengthError',
129 'pydantic.errors:ListMinLengthError',
130 'pydantic.errors:ListUniqueItemsError',
131 'pydantic.errors:LuhnValidationError',
132 'pydantic.errors:MissingDiscriminator',
133 'pydantic.errors:MissingError',
134 'pydantic.errors:NoneIsAllowedError',
135 'pydantic.errors:NoneIsNotAllowedError',
136 'pydantic.errors:NotDigitError',
137 'pydantic.errors:NotNoneError',
138 'pydantic.errors:NumberNotGeError',
139 'pydantic.errors:NumberNotGtError',
140 'pydantic.errors:NumberNotLeError',
141 'pydantic.errors:NumberNotLtError',
142 'pydantic.errors:NumberNotMultipleError',
143 'pydantic.errors:PathError',
144 'pydantic.errors:PathNotADirectoryError',
145 'pydantic.errors:PathNotAFileError',
146 'pydantic.errors:PathNotExistsError',
147 'pydantic.errors:PatternError',
148 'pydantic.errors:PyObjectError',
149 'pydantic.errors:PydanticTypeError',
150 'pydantic.errors:PydanticValueError',
151 'pydantic.errors:SequenceError',
152 'pydantic.errors:SetError',
153 'pydantic.errors:SetMaxLengthError',
154 'pydantic.errors:SetMinLengthError',
155 'pydantic.errors:StrError',
156 'pydantic.errors:StrRegexError',
157 'pydantic.errors:StrictBoolError',
158 'pydantic.errors:SubclassError',
159 'pydantic.errors:TimeError',
160 'pydantic.errors:TupleError',
161 'pydantic.errors:TupleLengthError',
162 'pydantic.errors:UUIDError',
163 'pydantic.errors:UUIDVersionError',
164 'pydantic.errors:UrlError',
165 'pydantic.errors:UrlExtraError',
166 'pydantic.errors:UrlHostError',
167 'pydantic.errors:UrlHostTldError',
168 'pydantic.errors:UrlPortError',
169 'pydantic.errors:UrlSchemeError',
170 'pydantic.errors:UrlSchemePermittedError',
171 'pydantic.errors:UrlUserInfoError',
172 'pydantic.errors:WrongConstantError',
173 'pydantic.main:validate_model',
174 'pydantic.networks:stricturl',
175 'pydantic:parse_file_as',
176 'pydantic:parse_raw_as',
177 'pydantic:stricturl',
178 'pydantic.tools:parse_file_as',
179 'pydantic.tools:parse_raw_as',
180 'pydantic.types:ConstrainedBytes',
181 'pydantic.types:ConstrainedDate',
182 'pydantic.types:ConstrainedDecimal',
183 'pydantic.types:ConstrainedFloat',
184 'pydantic.types:ConstrainedFrozenSet',
185 'pydantic.types:ConstrainedInt',
186 'pydantic.types:ConstrainedList',
187 'pydantic.types:ConstrainedSet',
188 'pydantic.types:ConstrainedStr',
189 'pydantic.types:JsonWrapper',
190 'pydantic.types:NoneBytes',
191 'pydantic.types:NoneStr',
192 'pydantic.types:NoneStrBytes',
193 'pydantic.types:StrBytes',
194 'pydantic.typing:evaluate_forwardref',
195 'pydantic.typing:AbstractSetIntStr',
196 'pydantic.typing:AnyCallable',
197 'pydantic.typing:AnyClassMethod',
198 'pydantic.typing:CallableGenerator',
199 'pydantic.typing:DictAny',
200 'pydantic.typing:DictIntStrAny',
201 'pydantic.typing:DictStrAny',
202 'pydantic.typing:IntStr',
203 'pydantic.typing:ListStr',
204 'pydantic.typing:MappingIntStrAny',
205 'pydantic.typing:NoArgAnyCallable',
206 'pydantic.typing:NoneType',
207 'pydantic.typing:ReprArgs',
208 'pydantic.typing:SetStr',
209 'pydantic.typing:StrPath',
210 'pydantic.typing:TupleGenerator',
211 'pydantic.typing:WithArgsTypes',
212 'pydantic.typing:all_literal_values',
213 'pydantic.typing:display_as_type',
214 'pydantic.typing:get_all_type_hints',
215 'pydantic.typing:get_args',
216 'pydantic.typing:get_origin',
217 'pydantic.typing:get_sub_types',
218 'pydantic.typing:is_callable_type',
219 'pydantic.typing:is_classvar',
220 'pydantic.typing:is_finalvar',
221 'pydantic.typing:is_literal_type',
222 'pydantic.typing:is_namedtuple',
223 'pydantic.typing:is_new_type',
224 'pydantic.typing:is_none_type',
225 'pydantic.typing:is_typeddict',
226 'pydantic.typing:is_typeddict_special',
227 'pydantic.typing:is_union',
228 'pydantic.typing:new_type_supertype',
229 'pydantic.typing:resolve_annotations',
230 'pydantic.typing:typing_base',
231 'pydantic.typing:update_field_forward_refs',
232 'pydantic.typing:update_model_forward_refs',
233 'pydantic.utils:ClassAttribute',
234 'pydantic.utils:DUNDER_ATTRIBUTES',
235 'pydantic.utils:PyObjectStr',
236 'pydantic.utils:ValueItems',
237 'pydantic.utils:almost_equal_floats',
238 'pydantic.utils:get_discriminator_alias_and_values',
239 'pydantic.utils:get_model',
240 'pydantic.utils:get_unique_discriminator_alias',
241 'pydantic.utils:in_ipython',
242 'pydantic.utils:is_valid_identifier',
243 'pydantic.utils:path_type',
244 'pydantic.utils:validate_field_name',
245 'pydantic:validate_model',
246}
247
248
249def getattr_migration(module: str) -> Callable[[str], Any]:
250 """Implement PEP 562 for objects that were either moved or removed on the migration
251 to V2.
252
253 Args:
254 module: The module name.
255
256 Returns:
257 A callable that will raise an error if the object is not found.
258 """
259 # This avoids circular import with errors.py.
260 from .errors import PydanticImportError
261
262 def wrapper(name: str) -> object:
263 """Raise an error if the object is not found, or warn if it was moved.
264
265 In case it was moved, it still returns the object.
266
267 Args:
268 name: The object name.
269
270 Returns:
271 The object.
272 """
273 if name == '__path__':
274 raise AttributeError(f'module {module!r} has no attribute {name!r}')
275
276 import warnings
277
278 from ._internal._validators import import_string
279
280 import_path = f'{module}:{name}'
281 if import_path in MOVED_IN_V2.keys():
282 new_location = MOVED_IN_V2[import_path]
283 warnings.warn(f'`{import_path}` has been moved to `{new_location}`.')
284 return import_string(MOVED_IN_V2[import_path])
285 if import_path in DEPRECATED_MOVED_IN_V2:
286 # skip the warning here because a deprecation warning will be raised elsewhere
287 return import_string(DEPRECATED_MOVED_IN_V2[import_path])
288 if import_path in REDIRECT_TO_V1:
289 new_location = REDIRECT_TO_V1[import_path]
290 warnings.warn(
291 f'`{import_path}` has been removed. We are importing from `{new_location}` instead.'
292 'See the migration guide for more details: https://docs.pydantic.dev/latest/migration/'
293 )
294 return import_string(REDIRECT_TO_V1[import_path])
295 if import_path == 'pydantic:BaseSettings':
296 raise PydanticImportError(
297 '`BaseSettings` has been moved to the `pydantic-settings` package. '
298 f'See https://docs.pydantic.dev/{version_short()}/migration/#basesettings-has-moved-to-pydantic-settings '
299 'for more details.'
300 )
301 if import_path in REMOVED_IN_V2:
302 raise PydanticImportError(f'`{import_path}` has been removed in V2.')
303 globals: dict[str, Any] = sys.modules[module].__dict__
304 if name in globals:
305 return globals[name]
306 raise AttributeError(f'module {module!r} has no attribute {name!r}')
307
308 return wrapper