Inspecting Types#
Warning
This module is experimental. While we don’t expect any breaking changes, we also don’t promise not to break things between releases while this interface stabilizes.
msgspec
provides type-introspection support, which can be used to build
tooling on top of msgspec-compatible types. Possible use cases include:
Generating OpenAPI specifications from msgspec-compatible types (note that the builtin JSON Schema support may be a better starting point for this).
Generating example instances of types for testing or documentation purposes
Integration with hypothesis for testing
The main function here is msgspec.inspect.type_info
for converting a type
annotation into a corresponding msgspec.inspect.Type
object. There’s also
msgspec.inspect.multi_type_info
which converts an iterable of annotations;
this function is more efficient than calling type_info
in a loop.
>>> import msgspec
>>> msgspec.inspect.type_info(bool)
BoolType()
>>> msgspec.inspect.type_info(int)
IntType(gt=None, ge=None, lt=None, le=None, multiple_of=None)
>>> msgspec.inspect.type_info(list[int]) # nested types are traversed
ListType(
item_type=IntType(gt=None, ge=None, lt=None, le=None, multiple_of=None),
min_length=None,
max_length=None
)
>>> msgspec.inspect.multi_type_info([bool, int]) # inspect multiple types
(BoolType(), IntType(gt=None, ge=None, lt=None, le=None, multiple_of=None))
Types with Constraints will include the constraint information as well:
>>> from typing import Annotated
>>> from msgspec import Meta
>>> PositiveInt = Annotated[int, Meta(gt=0)]
>>> msgspec.inspect.type_info(PositiveInt)
IntType(gt=0, ge=None, lt=None, le=None, multiple_of=None)
Compound types like Structs are also supported:
>>> class User(msgspec.Struct):
... name: str
... groups: list[str] = []
... email: str | None = None
>>> msgspec.inspect.type_info(User)
StructType(
cls=User,
fields=(
Field(
name='name',
encode_name='name',
type=StrType(min_length=None, max_length=None, pattern=None),
required=True,
default=UNSET,
default_factory=UNSET
),
Field(
name='groups',
encode_name='groups',
type=ListType(
item_type=StrType(min_length=None, max_length=None, pattern=None),
min_length=None,
max_length=None
),
required=False,
default=[],
default_factory=UNSET
),
Field(
name='email',
encode_name='email',
type=UnionType(
types=(
StrType(min_length=None, max_length=None, pattern=None),
NoneType()
)
),
required=False,
default=None,
default_factory=UNSET
)
),
tag_field=None,
tag=None,
array_like=False,
forbid_unknown_fields=False
)
Types with additional metadata like extra_json_schema
or title
will be
wrapped in a msgspec.inspect.Metadata
object. Note that all JSON schema
specific fields are merged into a single extra_json_schema
dict.
>>> UnixName = Annotated[
... str,
... Meta(
... min_length=1,
... max_length=32,
... pattern="^[a-z_][a-z0-9_-]*$",
... description="A valid UNIX username"
... )
... ]
>>> msgspec.inspect.type_info(UnixName)
Metadata(
type=StrType(
min_length=1,
max_length=32,
pattern='^[a-z_][a-z0-9_-]*$'
),
extra_json_schema={'description': 'A valid UNIX username'}
)
Every type supported by msgspec
has a corresponding msgspec.inspect.Type
subclass. See the API docs for a complete list of types.
For an example of using these functions, you might find our builtin
JSON Schema generator implementation useful - the code for this can be
found here. In
particular, take a look at the large if-else statement in _to_schema
.