typing-inspection
raw JSON → 0.4.2 verified Tue May 12 auth: no python install: verified quickstart: verified
typing-inspection provides runtime tools to inspect Python type annotations at runtime. Maintained by the Pydantic team, it is split into two submodules: `typing_inspection.typing_objects` (predicate functions like `is_union`, `is_literal`, `is_any`, etc. that correctly handle both `typing` and `typing_extensions` variants) and `typing_inspection.introspection` (higher-level helpers such as `inspect_annotation`, `get_literal_values`, and `is_union_origin`). Current version is 0.4.2 (released 2025-10-01); the project has released frequently since its initial release in February 2025.
pip install typing-inspection Warnings
breaking The INFERRED sentinel was renamed to UNKNOWN in v0.3.0. Any code importing or comparing against INFERRED will get an ImportError or a broken identity check. ↓
fix Replace `from typing_inspection.introspection import INFERRED` with `from typing_inspection.introspection import UNKNOWN` and update all `is INFERRED` checks to `is UNKNOWN`.
breaking v0.4.0 added a new `DATACLASS` value to the AnnotationSource enum to support `dataclasses.InitVar` as a type qualifier. Exhaustive match/if-elif chains over AnnotationSource members will silently miss it. ↓
fix Add a branch for `AnnotationSource.DATACLASS` wherever you enumerate AnnotationSource values. Also import `dataclasses.InitVar` handling if you introspect dataclass fields.
gotcha Never use identity checks like `get_origin(x) is typing.Union` or `get_origin(x) is typing_extensions.Union`; typing_extensions may ship a different Union object than stdlib typing. ↓
fix Use `from typing_inspection.typing_objects import is_union` and call `is_union(get_origin(x))`, which checks both variants automatically.
gotcha inspect_annotation() raises ForbiddenQualifier if a type qualifier is not allowed for the given AnnotationSource (e.g. using Required outside a TypedDict context). Not catching this causes unhandled exceptions at runtime. ↓
fix Catch `ForbiddenQualifier` explicitly, or pass `annotation_source=AnnotationSource.ANY` if you want to permit all qualifiers regardless of context.
gotcha Using `type_expr.__args__` directly to get Literal values silently misses PEP 695 type aliases (Python 3.12+), which are lazily evaluated and may not be expanded. Additionally, `get_literal_values` returns a generator that must be iterated to retrieve values. ↓
fix Always use `get_literal_values(type_expr)` from `typing_inspection.introspection` instead of accessing `.__args__` directly on Literal forms, and remember to iterate over the returned generator object (e.g., using `list()` or a for-loop) to extract the literal values.
gotcha When `unpack_type_aliases='eager'` is passed to inspect_annotation(), any undefined symbol in a PEP 695 type alias raises NameError at runtime. The default is 'skip' (aliases not expanded). ↓
fix Use `unpack_type_aliases='lenient'` to fall back gracefully to skipping the alias if name resolution fails, instead of raising NameError.
deprecated `is_union_origin()` is effectively superseded on Python 3.14+, where both Union[t1,t2] and t1|t2 produce the same typing.Union class. The function remains available but its main use case disappears. ↓
fix For codebases targeting Python 3.14+ exclusively, replace `is_union_origin(get_origin(x))` with `is_union(get_origin(x))` from `typing_inspection.typing_objects`.
Install compatibility verified last tested: 2026-05-12
python os / libc status wheel install import disk
3.10 alpine (musl) - - 0.06s 18.2M
3.10 slim (glibc) - - 0.02s 19M
3.11 alpine (musl) - - 0.09s 20.1M
3.11 slim (glibc) - - 0.07s 21M
3.12 alpine (musl) - - 0.07s 11.9M
3.12 slim (glibc) - - 0.07s 12M
3.13 alpine (musl) - - 0.07s 11.6M
3.13 slim (glibc) - - 0.06s 12M
3.9 alpine (musl) - - 0.04s 17.7M
3.9 slim (glibc) - - 0.03s 18M
Imports
- inspect_annotation wrong
from typing_inspection import inspect_annotationcorrectfrom typing_inspection.introspection import inspect_annotation - AnnotationSource wrong
from typing_inspection import AnnotationSourcecorrectfrom typing_inspection.introspection import AnnotationSource - UNKNOWN wrong
from typing_inspection.introspection import INFERREDcorrectfrom typing_inspection.introspection import UNKNOWN - is_union wrong
from typing_inspection import is_unioncorrectfrom typing_inspection.typing_objects import is_union - get_literal_values
from typing_inspection.introspection import get_literal_values - is_union_origin
from typing_inspection.introspection import is_union_origin - ForbiddenQualifier
from typing_inspection.introspection import ForbiddenQualifier
Quickstart verified last tested: 2026-04-23
from typing import ClassVar, Union, get_origin
from typing import Annotated
from typing_inspection.introspection import (
AnnotationSource,
UNKNOWN,
inspect_annotation,
get_literal_values,
is_union_origin,
)
from typing_inspection.typing_objects import is_any, is_literal, is_union
# --- Unwrap an annotation expression ---
result = inspect_annotation(
ClassVar[Annotated[int, "meta"]],
annotation_source=AnnotationSource.CLASS,
)
print(result)
# InspectedAnnotation(type=int, qualifiers={'class_var'}, metadata=['meta'])
# Check the UNKNOWN sentinel (bare ClassVar / Final with no inner type)
bare_result = inspect_annotation(ClassVar, annotation_source=AnnotationSource.CLASS)
if bare_result.type is UNKNOWN:
print("No explicit inner type; infer from assignment or default to Any")
# --- typing_objects predicates handle both typing + typing_extensions ---
from typing import Literal
origin = get_origin(Literal[1, 2])
print(is_literal(origin)) # True
# Safe union detection across typing / typing_extensions / PEP 604
union_origin = get_origin(Union[int, str])
print(is_union_origin(union_origin)) # True
# Retrieve Literal values (expands PEP 695 type aliases correctly)
values = get_literal_values(Literal["a", "b", 1])
print(values) # ('a', 'b', 1)