Introspecting the typing
module¶
New in version 1.1.
The introspection.typing
submodule provides functions for the purpose
of dissecting typing
types. It is recommended to familiarize yourself
with the typing
module’s core concepts by reading PEP 0483 before
working with its internals.
Note
Sometimes there are discrepancies between what is correct and what the typing
module
actually lets you do. For example, in python 3.9 most types accept an arbitrary number of
type arguments:
>>> list[int, str]
list[int, str]
In cases like this, where the implementation is more lenient than the specification, the functions in this module will return what’s correct according to the specification. Like so:
>>> is_variadic_generic(list)
False
Other times, the implementation won’t let you do things that should be possible.
For example, in python 3.6 it wasn’t possible to parameterize a typing.ClassVar
more than once:
>>> ClassVar[T][int]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.6/typing.py", line 1404, in __getitem__
.format(cls.__name__[1:]))
TypeError: ClassVar cannot be further subscripted
In such cases, this module will respect the limitations of the implementation:
>>> is_fully_parameterized_generic(ClassVar[T])
True
- introspection.typing.is_type(type_, allow_forwardref=True)¶
Returns whether
type_
is a type - i.e. something that is a valid type annotation.Examples:
>>> is_type(int) True >>> is_type(None) True >>> is_type(typing.List) True >>> is_type(typing.List[str]) True >>> is_type('Foo') # this is a forward reference True >>> is_type(3) False
New in version 1.2: The
allow_forwardref
parameter.
- introspection.typing.is_typing_type(type_, raising=True)¶
Returns whether
type_
is a type added by PEP 0484. This includes parameterized generics and all types defined in thetyping
module (but not custom subclasses thereof) except fortyping.ForwardRef
.If
type_
is not a type as defined byis_type()
andraising
isTrue
, aTypeError
is raised. (Otherwise,False
is returned.)
- introspection.typing.is_generic(type_, raising=True)¶
Returns whether
type_
is any kind of generic type, for exampleList
,List[T]
or evenList[Tuple[T]]
. This includes “special” types likeUnion
,Tuple
andLiteral
- anything that’s subscriptable is considered generic, except fortyping.Generic
itself.If
type_
is not a type as defined byis_type()
andraising
isTrue
, aTypeError
is raised. (Otherwise,False
is returned.)- Parameters
type_ – The object to examine
raising – Whether to throw a
TypeError
iftype_
is not a type
- Returns
Whether the object is a generic type
- Raises
TypeError – If
type_
is not a type andraising
isTrue
- introspection.typing.is_variadic_generic(type_, raising=True)¶
Returns whether
type_
is a generic type that accepts an arbitrary number of type arguments. (e.g.Union
,Tuple
,Literal
, etc.)If
type_
is not a type as defined byis_type()
andraising
isTrue
, aTypeError
is raised. (Otherwise,False
is returned.)- Parameters
type_ – The object to examine
raising – Whether to throw a
TypeError
iftype_
is not a type
- Returns
Whether the object is a variadic generic type
- Raises
TypeError – If
type_
is not a type andraising
isTrue
- introspection.typing.is_forwardref(type_, raising=True)¶
Returns whether
type_
is a forward reference.Examples:
>>> is_forwardref('List') True >>> is_forwardref(typing.ForwardRef('List')) True >>> is_forwardref(List) False
New in version 1.2.
- Parameters
type_ – The object to examine
raising (
bool
, default:True
) – Whether to throw aTypeError
iftype_
is not a type
- Returns
Whether the object is a class or type (or forward reference)
- introspection.typing.is_generic_base_class(type_, raising=True)¶
Returns whether
type_
is a generic base class, for exampleList
(but notList[int]
orList[T]
).If
type_
is not a type as defined byis_type()
andraising
isTrue
, aTypeError
is raised. (Otherwise,False
is returned.)- Parameters
type_ – The object to examine
raising – Whether to throw a
TypeError
on invalid input
- Returns
Whether the object is a generic class with no type arguments
- Raises
TypeError – If
type_
is not a type andraising
isTrue
- introspection.typing.is_parameterized_generic(type_, raising=True)¶
Returns whether
type_
is a generic type with some type arguments supplied, for exampleList[int]
orList[T]
(but notList
) - in other words, atypes.GenericAlias
.If
type_
is not a type as defined byis_type()
andraising
isTrue
, aTypeError
is raised. (Otherwise,False
is returned.)- Parameters
type_ – The object to examine
raising – Whether to throw a
TypeError
on invalid input
- Returns
Whether the object is a generic type with type arguments
- Raises
TypeError – If
type_
is not a type andraising
isTrue
- introspection.typing.is_fully_parameterized_generic(type_, raising=True)¶
Returns whether
type_
is a generic type with all type arguments supplied, for exampleList[int]
(but notList[T]
orList[Tuple[T]]
).Unlike
is_parameterized_generic()
, which will only ever returnTrue
fortypes.GenericAlias
objects, this function returnsTrue
for any input that was once generic, but no longer accepts any more type parameters. For example:>>> is_parameterized_generic(typing.ByteString) False >>> is_fully_parameterized_generic(typing.ByteString) True
If
type_
is not a type as defined byis_type()
andraising
isTrue
, aTypeError
is raised. (Otherwise,False
is returned.)- Parameters
type_ – The object to examine
raising – Whether to throw a
TypeError
on invalid input
- Returns
Whether the object is a generic type with type arguments
- Raises
TypeError – If
type_
is not a type andraising
isTrue
ValueError – If
type_
is not a type andraising
isTrue
- introspection.typing.get_generic_base_class(type_)¶
Given a parameterized generic type as input, returns the corresponding generic base class.
Example:
>>> get_generic_base_class(typing.List[int]) typing.List
Changed in version 1.5.1: Now throws
ValueError
instead ofTypeError
if the input is a type, but not generic.- Parameters
type_ – A parameterized generic type
- Returns
The input type without its type arguments
- introspection.typing.get_type_arguments(type_)¶
Given a parameterized generic type as input, returns a tuple of its type arguments.
Example:
>>> get_type_arguments(typing.List[int]) (<class 'int'>,) >>> get_type_arguments(typing.Callable[[str], None]) ([<class 'str'>], None)
Note that some generic types (like
typing.Optional
) won’t accept a tuple as input, so take care when you try to parameterize something with this function’s return value:>>> get_type_arguments(typing.Optional[int]) (<class 'int'>,) >>> typing.Optional[(int,)] TypeError: typing.Optional requires a single type. Got (<class 'int'>,).
Changed in version 1.5.1: Now throws
ValueError
instead ofTypeError
if the input is a type, but not generic.- Parameters
type_ – A parameterized generic type
- Returns
The input type’s type arguments
- introspection.typing.get_type_parameters(type_)¶
Returns the TypeVars of a generic type.
If
type_
is not a type,TypeError
is raised. Iftype_
is a type, but not generic, aValueError
is raised. Iftype_
is a fully parameterized generic class (liketyping.ByteString
), an empty tuple is returned.Examples:
>>> get_type_parameters(List) (~T,) >>> get_type_parameters(Generator) (+T_co, -T_contra, +V_co) >>> get_type_parameters(List[Tuple[T, int, T]]) (~T,) >>> get_type_parameters(ByteString) ()
In most cases, the returned TypeVars correspond directly to the type parameters the type accepts. However, some special cases exist. Firstly, there are generics which accept any number of type arguments, like
Tuple
. Callingget_type_parameters
on these will only return a singleTypeVar
:>>> get_type_parameters(Union) (+T_co,) >>> get_type_parameters(Tuple) (+T_co,)
Secondly, there are special generic types that the
typing
module internally doesn’t implement with TypeVars. Despite this,get_type_parameters
still supports them:>>> get_type_parameters(Optional) (+T_co,) >>> get_type_parameters(ClassVar) (+T_co,) >>> get_type_parameters(Callable) (-A_contra, +R_co)
Changed in version 1.2: Now throws
ValueError
instead ofTypeError
if the input is a type, but not generic.- Raises
TypeError – If
type_
is not a typeValueError – If
type_
is a type, but not generic
- introspection.typing.get_type_name(type_)¶
Returns the name of a type.
Examples:
>>> get_type_name(list) 'list' >>> get_type_name(typing.List) 'List'
- Parameters
type_ – The type whose name to retrieve
- Returns
The type’s name
- Raises
TypeError – If
type_
isn’t a type or is a parameterized generic type
- introspection.typing.resolve_forward_refs(annotation, module=None, eval_=True, strict=True)¶
Resolves forward references in a type annotation.
Examples:
>>> resolve_forward_refs(List['int']) typing.List[int] >>> resolve_forward_refs('ellipsis') <class 'ellipsis'>
- Parameters
annotation – The annotation in which forward references should be resolved
module – The module in which forward references will be evaluated
eval_ – If
True
, references may contain arbitrary code that will be evaluated witheval
. Otherwise, they must be identifiers and will be resolved withgetattr
.strict – Whether to raise an exception if a forward reference can’t be resolved
- Returns
A new annotation with no forward references
- introspection.typing.annotation_to_string(annotation, implicit_typing=True)¶
Converts a type annotation to string. The result is valid python code.
Examples:
>>> annotation_to_string(int) 'int' >>> annotation_to_string(None) 'None' >>> annotation_to_string(typing.List[int]) 'List[int]'
- Parameters
annotation – A class or type annotation
implicit_typing – Whether to omit the “typing.” prefix from
typing
types’ names
- Returns
A string that, when evaluated, returns
annotation
- introspection.typing.annotation_for_callable(callable_)¶
Given a callable object as input, returns a matching type annotation.
Examples:
>>> annotation_for_callable(len) typing.Callable[[typing.Sized], int]
Note: How
*args
,**kwargs
, and keyword-only parameters are handled is currently undefined.New in version 1.5.
- introspection.typing.to_python(type_, strict=False)¶
Given a
typing
type as input, returns the corresponding “regular” python class.Examples:
>>> to_python(typing.List) <class 'list'> >>> to_python(typing.Iterable) <class 'collections.abc.Iterable'>
Note that
typing.Any
andobject
are two distinct types:>>> to_python(typing.Any) typing.Any >>> to_python(object) <class 'object'>
Generics parameterized with
typing.Any
or other pointless constraints are converted to their regular python counterparts:>>> to_python(typing.List[typing.Any]) <class 'list'> >>> to_python(typing.Callable[..., typing.Any]) <class 'collections.abc.Callable'> >>> to_python(typing.Type[object]) <class 'type'>
The function recurses on the type arguments of parameterized generics:
>>> to_python(typing.List[typing.Set], strict=False) typing.List[set]
Forward references are handled, as well:
>>> to_python(typing.List['Set'], strict=False) typing.List[set]
- Parameters
type_ – The type to convert to a python class
strict – Whether to raise an exception if the input type has no python equivalent
- Returns
The class corresponding to the input type
- introspection.typing.to_typing(type_, strict=False)¶
Given a python class as input, returns the corresponding
typing
annotation.Examples:
>>> to_typing(list) typing.List >>> to_typing(typing.List[tuple]) typing.List[typing.Tuple] >>> to_typing(typing.List['tuple']) typing.List[typing.Tuple]
- Parameters
type_ – The class to convert to a typing annotation
strict – Whether to raise an exception if the input class has no
typing
equivalent
- Returns
The corresponding annotation from the
typing
module