Registry / serialization / typing-inspection

typing-inspection

JSON →
library0.4.4pypypi✓ verified 27d ago

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
INSTALL
IMPORT
SIG · TYPING-INSPECTION
T
typing-inspection
serializationpythonv0.4.4
Install
1.7s avg
Import
53ms
Disk
16MB
Pass rate
10/ 10
Env Coverage10 / 10
glibc
3.93.13
musl
3.93.13
Install & Compatibility
Where this runs
tested against v0.4.4 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
musl
py 3.103.95 runs
installs and imports cleanly · install 0.0s · import 0.056s · 18.2MB
glibc
py 3.103.95 runs
installs and imports cleanly · install 1.7s · import 0.050s · 19MB
16MB installed
● package 16MB
Code
Verified usage

Verified import paths — ran on the pinned version, not inferred.

inspect_annotation
from typing_inspection.introspection import inspect_annotation
from typing_inspection import inspect_annotation
All public symbols live in the two explicit submodules (.introspection and .typing_objects); the top-level typing_inspection namespace does not re-export them.
AnnotationSource
from typing_inspection.introspection import AnnotationSource
from typing_inspection import AnnotationSource
AnnotationSource enum must be imported from the .introspection submodule directly.
UNKNOWN
from typing_inspection.introspection import UNKNOWN
from typing_inspection.introspection import INFERRED
The sentinel was renamed from INFERRED to UNKNOWN in v0.3.0; importing INFERRED raises ImportError.
is_union
from typing_inspection.typing_objects import is_union
from typing_inspection import is_union
All typing_objects predicate functions (is_literal, is_any, is_self, is_union, etc.) are in the .typing_objects submodule.
get_literal_values
from typing_inspection.introspection import get_literal_values
Prefer get_literal_values() over direct __args__ access; it properly expands PEP 695 type aliases.
is_union_origin
from typing_inspection.introspection import is_union_origin
Only needed for Python < 3.14; since Python 3.14 Union[t1,t2] and t1|t2 are the same class, so is_union() from typing_objects suffices.
ForbiddenQualifier
from typing_inspection.introspection import ForbiddenQualifier
Exception raised when an invalid type qualifier is used for the given AnnotationSource; catch explicitly if you want to report it as a user error.

Inspect a ClassVar[Annotated[int, 'meta']] annotation, then use typing_objects predicates on the unwrapped type expression.

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)
Debug
Known issues
breakingThe 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`.
affects: <0.3.0
breakingv0.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.
affects: <0.4.0
gotchaNever 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.
affects: all
gotchainspect_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.
affects: all
gotchaUsing `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.
affects: all
gotchaWhen `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.
affects: >=0.4.0
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`.
affects: >=0.4.1 on Python 3.14+
Upgrade
Version history
0.4.4latest on PyPI · released Aug 12, 2026
Audit
Dependencies
typing_extensionsrequiredRequired at runtime; typing_objects predicates check against both stdlib typing and typing_extensions variants to handle version differences.
Agent activity
14 hits · last 30 days
node
12
OpenAI (training)
1
Resources
typing-inspection — pip install typing-inspection · libregistry