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 simplevar is typing.TypingObj
checks in the wild, which do not account for the possibly differenttyping_extensions
variant [1]. get_origin()
is not necessarily returning the “unparameterized” version of a generic typing object. For instance,get_origin(typing.Tuple)
istuple
, whileget_origin(tuple)
isNone
.
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.