Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/pydantic/v1/typing.py: 17%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1import functools
2import operator
3import sys
4import typing
5from collections.abc import Callable
6from os import PathLike
7from typing import ( # type: ignore
8 TYPE_CHECKING,
9 AbstractSet,
10 Any,
11 Callable as TypingCallable,
12 ClassVar,
13 Dict,
14 ForwardRef,
15 Generator,
16 Iterable,
17 List,
18 Mapping,
19 NewType,
20 Optional,
21 Sequence,
22 Set,
23 Tuple,
24 Type,
25 TypeVar,
26 Union,
27 _eval_type,
28 cast,
29 get_type_hints,
30)
32from typing_extensions import (
33 Annotated,
34 Final,
35 Literal,
36 NotRequired as TypedDictNotRequired,
37 Required as TypedDictRequired,
38)
40try:
41 from typing import _TypingBase as typing_base # type: ignore
42except ImportError:
43 from typing import _Final as typing_base # type: ignore
45try:
46 from typing import GenericAlias as TypingGenericAlias # type: ignore
47except ImportError:
48 # python < 3.9 does not have GenericAlias (list[int], tuple[str, ...] and so on)
49 TypingGenericAlias = ()
51try:
52 from types import UnionType as TypesUnionType # type: ignore
53except ImportError:
54 # python < 3.10 does not have UnionType (str | int, byte | bool and so on)
55 TypesUnionType = ()
58if sys.version_info < (3, 9):
60 def evaluate_forwardref(type_: ForwardRef, globalns: Any, localns: Any) -> Any:
61 return type_._evaluate(globalns, localns)
63elif sys.version_info < (3, 12, 4):
65 def evaluate_forwardref(type_: ForwardRef, globalns: Any, localns: Any) -> Any:
66 # Even though it is the right signature for python 3.9, mypy complains with
67 # `error: Too many arguments for "_evaluate" of "ForwardRef"` hence the cast...
68 # Python 3.13/3.12.4+ made `recursive_guard` a kwarg, so name it explicitly to avoid:
69 # TypeError: ForwardRef._evaluate() missing 1 required keyword-only argument: 'recursive_guard'
70 return cast(Any, type_)._evaluate(globalns, localns, recursive_guard=set())
72elif sys.version_info < (3, 14):
74 def evaluate_forwardref(type_: ForwardRef, globalns: Any, localns: Any) -> Any:
75 # Pydantic 1.x will not support PEP 695 syntax, but provide `type_params` to avoid
76 # warnings:
77 return cast(Any, type_)._evaluate(globalns, localns, type_params=(), recursive_guard=set())
79else:
81 def evaluate_forwardref(type_: ForwardRef, globalns: Any, localns: Any) -> Any:
82 # Pydantic 1.x will not support PEP 695 syntax, but provide `type_params` to avoid
83 # warnings:
84 return typing.evaluate_forward_ref(
85 type_,
86 globals=globalns,
87 locals=localns,
88 type_params=(),
89 _recursive_guard=set(),
90 )
93if sys.version_info < (3, 9):
94 # Ensure we always get all the whole `Annotated` hint, not just the annotated type.
95 # For 3.7 to 3.8, `get_type_hints` doesn't recognize `typing_extensions.Annotated`,
96 # so it already returns the full annotation
97 get_all_type_hints = get_type_hints
99else:
101 def get_all_type_hints(obj: Any, globalns: Any = None, localns: Any = None) -> Any:
102 return get_type_hints(obj, globalns, localns, include_extras=True)
105_T = TypeVar('_T')
107AnyCallable = TypingCallable[..., Any]
108NoArgAnyCallable = TypingCallable[[], Any]
110# workaround for https://github.com/python/mypy/issues/9496
111AnyArgTCallable = TypingCallable[..., _T]
114# Annotated[...] is implemented by returning an instance of one of these classes, depending on
115# python/typing_extensions version.
116AnnotatedTypeNames = {'AnnotatedMeta', '_AnnotatedAlias'}
119LITERAL_TYPES: Set[Any] = {Literal}
120if hasattr(typing, 'Literal'):
121 LITERAL_TYPES.add(typing.Literal)
124if sys.version_info < (3, 8):
126 def get_origin(t: Type[Any]) -> Optional[Type[Any]]:
127 if type(t).__name__ in AnnotatedTypeNames:
128 # weirdly this is a runtime requirement, as well as for mypy
129 return cast(Type[Any], Annotated)
130 return getattr(t, '__origin__', None)
132else:
133 from typing import get_origin as _typing_get_origin
135 def get_origin(tp: Type[Any]) -> Optional[Type[Any]]:
136 """
137 We can't directly use `typing.get_origin` since we need a fallback to support
138 custom generic classes like `ConstrainedList`
139 It should be useless once https://github.com/cython/cython/issues/3537 is
140 solved and https://github.com/pydantic/pydantic/pull/1753 is merged.
141 """
142 if type(tp).__name__ in AnnotatedTypeNames:
143 return cast(Type[Any], Annotated) # mypy complains about _SpecialForm
144 return _typing_get_origin(tp) or getattr(tp, '__origin__', None)
147if sys.version_info < (3, 8):
148 from typing import _GenericAlias
150 def get_args(t: Type[Any]) -> Tuple[Any, ...]:
151 """Compatibility version of get_args for python 3.7.
153 Mostly compatible with the python 3.8 `typing` module version
154 and able to handle almost all use cases.
155 """
156 if type(t).__name__ in AnnotatedTypeNames:
157 return t.__args__ + t.__metadata__
158 if isinstance(t, _GenericAlias):
159 res = t.__args__
160 if t.__origin__ is Callable and res and res[0] is not Ellipsis:
161 res = (list(res[:-1]), res[-1])
162 return res
163 return getattr(t, '__args__', ())
165else:
166 from typing import get_args as _typing_get_args
168 def _generic_get_args(tp: Type[Any]) -> Tuple[Any, ...]:
169 """
170 In python 3.9, `typing.Dict`, `typing.List`, ...
171 do have an empty `__args__` by default (instead of the generic ~T for example).
172 In order to still support `Dict` for example and consider it as `Dict[Any, Any]`,
173 we retrieve the `_nparams` value that tells us how many parameters it needs.
174 """
175 if hasattr(tp, '_nparams'):
176 return (Any,) * tp._nparams
177 # Special case for `tuple[()]`, which used to return ((),) with `typing.Tuple`
178 # in python 3.10- but now returns () for `tuple` and `Tuple`.
179 # This will probably be clarified in pydantic v2
180 try:
181 if tp == Tuple[()] or sys.version_info >= (3, 9) and tp == tuple[()]: # type: ignore[misc]
182 return ((),)
183 # there is a TypeError when compiled with cython
184 except TypeError: # pragma: no cover
185 pass
186 return ()
188 def get_args(tp: Type[Any]) -> Tuple[Any, ...]:
189 """Get type arguments with all substitutions performed.
191 For unions, basic simplifications used by Union constructor are performed.
192 Examples::
193 get_args(Dict[str, int]) == (str, int)
194 get_args(int) == ()
195 get_args(Union[int, Union[T, int], str][int]) == (int, str)
196 get_args(Union[int, Tuple[T, int]][str]) == (int, Tuple[str, int])
197 get_args(Callable[[], T][int]) == ([], int)
198 """
199 if type(tp).__name__ in AnnotatedTypeNames:
200 return tp.__args__ + tp.__metadata__
201 # the fallback is needed for the same reasons as `get_origin` (see above)
202 return _typing_get_args(tp) or getattr(tp, '__args__', ()) or _generic_get_args(tp)
205if sys.version_info < (3, 9):
207 def convert_generics(tp: Type[Any]) -> Type[Any]:
208 """Python 3.9 and older only supports generics from `typing` module.
209 They convert strings to ForwardRef automatically.
211 Examples::
212 typing.List['Hero'] == typing.List[ForwardRef('Hero')]
213 """
214 return tp
216else:
218 def convert_generics(tp: Type[Any]) -> Type[Any]:
219 """
220 Recursively searches for `str` type hints and replaces them with ForwardRef.
222 Examples::
223 convert_generics(list['Hero']) == list[ForwardRef('Hero')]
224 convert_generics(dict['Hero', 'Team']) == dict[ForwardRef('Hero'), ForwardRef('Team')]
225 convert_generics(typing.Dict['Hero', 'Team']) == typing.Dict[ForwardRef('Hero'), ForwardRef('Team')]
226 convert_generics(list[str | 'Hero'] | int) == list[str | ForwardRef('Hero')] | int
227 """
228 origin = get_origin(tp)
229 if not origin or not hasattr(tp, '__args__'):
230 return tp
232 args = get_args(tp)
234 # typing.Annotated needs special treatment
235 if origin is Annotated:
236 return Annotated[(convert_generics(args[0]), *args[1:])] # type: ignore
238 # recursively replace `str` instances inside of `GenericAlias` with `ForwardRef(arg)`
239 converted = tuple(
240 ForwardRef(arg) if isinstance(arg, str) and isinstance(tp, TypingGenericAlias) else convert_generics(arg)
241 for arg in args
242 )
244 if converted == args:
245 return tp
246 elif isinstance(tp, TypingGenericAlias):
247 return TypingGenericAlias(origin, converted)
248 elif isinstance(tp, TypesUnionType):
249 # recreate types.UnionType (PEP604, Python >= 3.10)
250 return functools.reduce(operator.or_, converted) # type: ignore
251 else:
252 try:
253 setattr(tp, '__args__', converted)
254 except AttributeError:
255 pass
256 return tp
259if sys.version_info < (3, 10):
261 def is_union(tp: Optional[Type[Any]]) -> bool:
262 return tp is Union
264 WithArgsTypes = (TypingGenericAlias,)
266else:
267 import types
268 import typing
270 def is_union(tp: Optional[Type[Any]]) -> bool:
271 return tp is Union or tp is types.UnionType # noqa: E721
273 WithArgsTypes = (typing._GenericAlias, types.GenericAlias, types.UnionType)
276StrPath = Union[str, PathLike]
279if TYPE_CHECKING:
280 from pydantic.v1.fields import ModelField
282 TupleGenerator = Generator[Tuple[str, Any], None, None]
283 DictStrAny = Dict[str, Any]
284 DictAny = Dict[Any, Any]
285 SetStr = Set[str]
286 ListStr = List[str]
287 IntStr = Union[int, str]
288 AbstractSetIntStr = AbstractSet[IntStr]
289 DictIntStrAny = Dict[IntStr, Any]
290 MappingIntStrAny = Mapping[IntStr, Any]
291 CallableGenerator = Generator[AnyCallable, None, None]
292 ReprArgs = Sequence[Tuple[Optional[str], Any]]
294 MYPY = False
295 if MYPY:
296 AnyClassMethod = classmethod[Any]
297 else:
298 # classmethod[TargetType, CallableParamSpecType, CallableReturnType]
299 AnyClassMethod = classmethod[Any, Any, Any]
301__all__ = (
302 'AnyCallable',
303 'NoArgAnyCallable',
304 'NoneType',
305 'is_none_type',
306 'display_as_type',
307 'resolve_annotations',
308 'is_callable_type',
309 'is_literal_type',
310 'all_literal_values',
311 'is_namedtuple',
312 'is_typeddict',
313 'is_typeddict_special',
314 'is_new_type',
315 'new_type_supertype',
316 'is_classvar',
317 'is_finalvar',
318 'update_field_forward_refs',
319 'update_model_forward_refs',
320 'TupleGenerator',
321 'DictStrAny',
322 'DictAny',
323 'SetStr',
324 'ListStr',
325 'IntStr',
326 'AbstractSetIntStr',
327 'DictIntStrAny',
328 'CallableGenerator',
329 'ReprArgs',
330 'AnyClassMethod',
331 'CallableGenerator',
332 'WithArgsTypes',
333 'get_args',
334 'get_origin',
335 'get_sub_types',
336 'typing_base',
337 'get_all_type_hints',
338 'is_union',
339 'StrPath',
340 'MappingIntStrAny',
341)
344NoneType = None.__class__
347NONE_TYPES: Tuple[Any, Any, Any] = (None, NoneType, Literal[None])
350if sys.version_info < (3, 8):
351 # Even though this implementation is slower, we need it for python 3.7:
352 # In python 3.7 "Literal" is not a builtin type and uses a different
353 # mechanism.
354 # for this reason `Literal[None] is Literal[None]` evaluates to `False`,
355 # breaking the faster implementation used for the other python versions.
357 def is_none_type(type_: Any) -> bool:
358 return type_ in NONE_TYPES
360elif sys.version_info[:2] == (3, 8):
362 def is_none_type(type_: Any) -> bool:
363 for none_type in NONE_TYPES:
364 if type_ is none_type:
365 return True
366 # With python 3.8, specifically 3.8.10, Literal "is" check sare very flakey
367 # can change on very subtle changes like use of types in other modules,
368 # hopefully this check avoids that issue.
369 if is_literal_type(type_): # pragma: no cover
370 return all_literal_values(type_) == (None,)
371 return False
373else:
375 def is_none_type(type_: Any) -> bool:
376 return type_ in NONE_TYPES
379def display_as_type(v: Type[Any]) -> str:
380 if not isinstance(v, typing_base) and not isinstance(v, WithArgsTypes) and not isinstance(v, type):
381 v = v.__class__
383 if is_union(get_origin(v)):
384 return f'Union[{", ".join(map(display_as_type, get_args(v)))}]'
386 if isinstance(v, WithArgsTypes):
387 # Generic alias are constructs like `list[int]`
388 return str(v).replace('typing.', '')
390 try:
391 return v.__name__
392 except AttributeError:
393 # happens with typing objects
394 return str(v).replace('typing.', '')
397def resolve_annotations(raw_annotations: Dict[str, Type[Any]], module_name: Optional[str]) -> Dict[str, Type[Any]]:
398 """
399 Partially taken from typing.get_type_hints.
401 Resolve string or ForwardRef annotations into type objects if possible.
402 """
403 base_globals: Optional[Dict[str, Any]] = None
404 if module_name:
405 try:
406 module = sys.modules[module_name]
407 except KeyError:
408 # happens occasionally, see https://github.com/pydantic/pydantic/issues/2363
409 pass
410 else:
411 base_globals = module.__dict__
413 annotations = {}
414 for name, value in raw_annotations.items():
415 if isinstance(value, str):
416 if (3, 10) > sys.version_info >= (3, 9, 8) or sys.version_info >= (3, 10, 1):
417 value = ForwardRef(value, is_argument=False, is_class=True)
418 else:
419 value = ForwardRef(value, is_argument=False)
420 try:
421 if sys.version_info >= (3, 13):
422 value = _eval_type(value, base_globals, None, type_params=())
423 else:
424 value = _eval_type(value, base_globals, None)
425 except NameError:
426 # this is ok, it can be fixed with update_forward_refs
427 pass
428 annotations[name] = value
429 return annotations
432def is_callable_type(type_: Type[Any]) -> bool:
433 return type_ is Callable or get_origin(type_) is Callable
436def is_literal_type(type_: Type[Any]) -> bool:
437 return Literal is not None and get_origin(type_) in LITERAL_TYPES
440def literal_values(type_: Type[Any]) -> Tuple[Any, ...]:
441 return get_args(type_)
444def all_literal_values(type_: Type[Any]) -> Tuple[Any, ...]:
445 """
446 This method is used to retrieve all Literal values as
447 Literal can be used recursively (see https://www.python.org/dev/peps/pep-0586)
448 e.g. `Literal[Literal[Literal[1, 2, 3], "foo"], 5, None]`
449 """
450 if not is_literal_type(type_):
451 return (type_,)
453 values = literal_values(type_)
454 return tuple(x for value in values for x in all_literal_values(value))
457def is_namedtuple(type_: Type[Any]) -> bool:
458 """
459 Check if a given class is a named tuple.
460 It can be either a `typing.NamedTuple` or `collections.namedtuple`
461 """
462 from pydantic.v1.utils import lenient_issubclass
464 return lenient_issubclass(type_, tuple) and hasattr(type_, '_fields')
467def is_typeddict(type_: Type[Any]) -> bool:
468 """
469 Check if a given class is a typed dict (from `typing` or `typing_extensions`)
470 In 3.10, there will be a public method (https://docs.python.org/3.10/library/typing.html#typing.is_typeddict)
471 """
472 from pydantic.v1.utils import lenient_issubclass
474 return lenient_issubclass(type_, dict) and hasattr(type_, '__total__')
477def _check_typeddict_special(type_: Any) -> bool:
478 return type_ is TypedDictRequired or type_ is TypedDictNotRequired
481def is_typeddict_special(type_: Any) -> bool:
482 """
483 Check if type is a TypedDict special form (Required or NotRequired).
484 """
485 return _check_typeddict_special(type_) or _check_typeddict_special(get_origin(type_))
488test_type = NewType('test_type', str)
491def is_new_type(type_: Type[Any]) -> bool:
492 """
493 Check whether type_ was created using typing.NewType
494 """
495 return isinstance(type_, test_type.__class__) and hasattr(type_, '__supertype__') # type: ignore
498def new_type_supertype(type_: Type[Any]) -> Type[Any]:
499 while hasattr(type_, '__supertype__'):
500 type_ = type_.__supertype__
501 return type_
504def _check_classvar(v: Optional[Type[Any]]) -> bool:
505 if v is None:
506 return False
508 return v.__class__ == ClassVar.__class__ and getattr(v, '_name', None) == 'ClassVar'
511def _check_finalvar(v: Optional[Type[Any]]) -> bool:
512 """
513 Check if a given type is a `typing.Final` type.
514 """
515 if v is None:
516 return False
518 return v.__class__ == Final.__class__ and (sys.version_info < (3, 8) or getattr(v, '_name', None) == 'Final')
521def is_classvar(ann_type: Type[Any]) -> bool:
522 if _check_classvar(ann_type) or _check_classvar(get_origin(ann_type)):
523 return True
525 # this is an ugly workaround for class vars that contain forward references and are therefore themselves
526 # forward references, see #3679
527 if ann_type.__class__ == ForwardRef and ann_type.__forward_arg__.startswith('ClassVar['):
528 return True
530 return False
533def is_finalvar(ann_type: Type[Any]) -> bool:
534 return _check_finalvar(ann_type) or _check_finalvar(get_origin(ann_type))
537def update_field_forward_refs(field: 'ModelField', globalns: Any, localns: Any) -> None:
538 """
539 Try to update ForwardRefs on fields based on this ModelField, globalns and localns.
540 """
541 prepare = False
542 if field.type_.__class__ == ForwardRef:
543 prepare = True
544 field.type_ = evaluate_forwardref(field.type_, globalns, localns or None)
545 if field.outer_type_.__class__ == ForwardRef:
546 prepare = True
547 field.outer_type_ = evaluate_forwardref(field.outer_type_, globalns, localns or None)
548 if prepare:
549 field.prepare()
551 if field.sub_fields:
552 for sub_f in field.sub_fields:
553 update_field_forward_refs(sub_f, globalns=globalns, localns=localns)
555 if field.discriminator_key is not None:
556 field.prepare_discriminated_union_sub_fields()
559def update_model_forward_refs(
560 model: Type[Any],
561 fields: Iterable['ModelField'],
562 json_encoders: Dict[Union[Type[Any], str, ForwardRef], AnyCallable],
563 localns: 'DictStrAny',
564 exc_to_suppress: Tuple[Type[BaseException], ...] = (),
565) -> None:
566 """
567 Try to update model fields ForwardRefs based on model and localns.
568 """
569 if model.__module__ in sys.modules:
570 globalns = sys.modules[model.__module__].__dict__.copy()
571 else:
572 globalns = {}
574 globalns.setdefault(model.__name__, model)
576 for f in fields:
577 try:
578 update_field_forward_refs(f, globalns=globalns, localns=localns)
579 except exc_to_suppress:
580 pass
582 for key in set(json_encoders.keys()):
583 if isinstance(key, str):
584 fr: ForwardRef = ForwardRef(key)
585 elif isinstance(key, ForwardRef):
586 fr = key
587 else:
588 continue
590 try:
591 new_key = evaluate_forwardref(fr, globalns, localns or None)
592 except exc_to_suppress: # pragma: no cover
593 continue
595 json_encoders[new_key] = json_encoders.pop(key)
598def get_class(type_: Type[Any]) -> Union[None, bool, Type[Any]]:
599 """
600 Tries to get the class of a Type[T] annotation. Returns True if Type is used
601 without brackets. Otherwise returns None.
602 """
603 if type_ is type:
604 return True
606 if get_origin(type_) is None:
607 return None
609 args = get_args(type_)
610 if not args or not isinstance(args[0], type):
611 return True
612 else:
613 return args[0]
616def get_sub_types(tp: Any) -> List[Any]:
617 """
618 Return all the types that are allowed by type `tp`
619 `tp` can be a `Union` of allowed types or an `Annotated` type
620 """
621 origin = get_origin(tp)
622 if origin is Annotated:
623 return get_sub_types(get_args(tp)[0])
624 elif is_union(origin):
625 return [x for t in get_args(tp) for x in get_sub_types(t)]
626 else:
627 return [tp]