Typing-inspection: A library to inspect type annotations at runtime

Inspecting type annotations at runtime can be hard. Often times, typing members aren’t properly checked, and the stdlib get_origin()/get_args() utility functions are not understood correctly.

Here are a couple examples:

  • For a typing object named TypingObj, it is common to see simple var is typing.TypingObj checks in the wild, which do not account for the possibly different typing_extensions variant [1].
  • get_origin() is not necessarily returning the “unparameterized” version of a generic typing object. For instance, get_origin(typing.Tuple) is tuple, while get_origin(tuple) is None.

Additionally, such checks can be become expensive if repeated a lot (get_origin/args() perform a lot of isinstance calls).

As per a discussion initiated by @leyec, we created the typing-inspection library in the Pydantic org [2]. It provides:

  • a low-level typing_objects module, meant to check if a variable is a typing object, e.g. is_annotated().
  • a high-level introspection module, meant to inspect type annotations (unpacking literal values, type qualifiers, etc).

To better understand how these utilities can be used, I wrote a (probably still incomplete) guide giving a recommended workflow to inspect type annotations, available here.

We are planning on making an initial release, soon, but we’d be pleased to have feedback from developers making use of type hints at runtime. Some design decisions are still under discussion, and as such I opened a bunch of open issues to discuss.


  1. For instance, on Python 3.9, get_origin(typing.Literal[1]) != get_origin(typing_extensions.Literal[1]). ↩︎

  2. Documentation is temporarily published on Github pages, but is subject to change. ↩︎

9 Likes