File: inspect.rst

package info (click to toggle)
python-msgspec 0.19.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 6,356 kB
  • sloc: javascript: 23,944; ansic: 20,540; python: 20,465; makefile: 29; sh: 19
file content (150 lines) | stat: -rw-r--r-- 4,779 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
Inspecting Types
----------------

.. currentmodule:: msgspec.inspect

.. 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 :doc:`jsonschema` 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.

.. code-block:: python

    >>> 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 :doc:`constraints` will include the constraint information as well:

.. code-block:: python

    >>> 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 :doc:`structs` are also supported:

.. code-block:: python

    >>> 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.

.. code-block:: python

    >>> 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 :ref:`API docs <inspect-api>` for a complete list of types.

For an example of using these functions, you might find our builtin
:doc:`jsonschema` generator implementation useful - the code for this can be
found `here
<https://github.com/jcrist/msgspec/blob/main/msgspec/_json_schema.py>`__. In
particular, take a look at the large if-else statement in ``_to_schema``.


.. _OpenAPI: https://www.openapis.org/
.. _hypothesis: https://hypothesis.readthedocs.io/en/latest/