Introspecting the typing module — Introspection documentation

# 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.

  Parameters

    - type_ – The object to examine

    - allow_forwardref (`bool`, default: `True`) – Controls whether strings and ForwardRefs are considered types

  Return type

    `bool`

  Returns

    Whether the object is a class or type (or forward reference)

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 the `typing` module (but not custom subclasses thereof) except for `typing.ForwardRef`.

  If `type_` is not a type as defined by `is_type()` and `raising` is `True`, a `TypeError` is raised. (Otherwise, `False` is returned.)

  Parameters

    - type_ – The object to examine

    - raising – Whether to throw a `TypeError` if `type_` is not a type

  Return type

    `bool`

  Returns

    Whether the object is a `typing` type

  Raises

    TypeError – If `type_` is not a type and `raising` is `True`

introspection.typing.is_generic(type_, raising=True)

  Returns whether `type_` is any kind of generic type, for example `List`, `List[T]` or even `List[Tuple[T]]`. This includes “special” types like `Union`, `Tuple` and `Literal` - anything that’s subscriptable is considered generic, except for `typing.Generic` itself.

  If `type_` is not a type as defined by `is_type()` and `raising` is `True`, a `TypeError` is raised. (Otherwise, `False` is returned.)

  Parameters

    - type_ – The object to examine

    - raising – Whether to throw a `TypeError` if `type_` is not a type

  Returns

    Whether the object is a generic type

  Raises

    TypeError – If `type_` is not a type and `raising` is `True`

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 by `is_type()` and `raising` is `True`, a `TypeError` is raised. (Otherwise, `False` is returned.)

  Parameters

    - type_ – The object to examine

    - raising – Whether to throw a `TypeError` if `type_` is not a type

  Returns

    Whether the object is a variadic generic type

  Raises

    TypeError – If `type_` is not a type and `raising` is `True`

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 a `TypeError` if `type_` 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 example `List` (but not `List[int]` or `List[T]`).

  If `type_` is not a type as defined by `is_type()` and `raising` is `True`, a `TypeError` 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 and `raising` is `True`

introspection.typing.is_parameterized_generic(type_, raising=True)

  Returns whether `type_` is a generic type with some type arguments supplied, for example `List[int]` or `List[T]` (but not `List`) - in other words, a `types.GenericAlias`.

  If `type_` is not a type as defined by `is_type()` and `raising` is `True`, a `TypeError` 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 and `raising` is `True`

introspection.typing.is_fully_parameterized_generic(type_, raising=True)

  Returns whether `type_` is a generic type with all type arguments supplied, for example `List[int]` (but not `List[T]` or `List[Tuple[T]]`).

  Unlike `is_parameterized_generic()`, which will only ever return `True` for `types.GenericAlias` objects, this function returns `True` 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 by `is_type()` and `raising` is `True`, a `TypeError` 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 and `raising` is `True`

    - ValueError – If `type_` is not a type and `raising` is `True`

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 of `TypeError` 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 of `TypeError` 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. If `type_` is a type, but not generic, a `ValueError` is raised. If `type_` is a fully parameterized generic class (like `typing.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`. Calling `get_type_parameters` on these will only return a single `TypeVar`:

      >>> 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 of `TypeError` if the input is a type, but not generic.

  Raises

    - TypeError – If `type_` is not a type

    - ValueError – 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 with `eval`. Otherwise, they must be identifiers and will be resolved with `getattr`.

    - 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` and `object` 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