Usage¶
structtype provides a single serialization protocol: JSON. All JSON
operations are available as methods on Struct instances, or via
StructAdapter for encoding non-struct objects.
Encoding¶
Struct instances are encoded to JSON using struct_dump_json():
>>> from structtype import Struct
>>> class User(Struct):
... name: str
... groups: set[str] = set()
... email: str | None = None
>>> alice = User("alice")
>>> alice.struct_dump_json()
b'{"name":"alice","groups":[],"email":null}'
For encoding non-struct objects, StructAdapter can be used:
>>> from structtype import StructAdapter
>>> StructAdapter(dict).struct_dump_json({"hello": "world"})
b'{"hello":"world"}'
Decoding¶
JSON is decoded into a struct instance using struct_validate_json():
>>> User.struct_validate_json(b'{"name":"alice","groups":[],"email":null}')
User(name='alice', groups=set(), email=None)
Typed Decoding¶
structtype validates data during decoding against the struct’s type
annotations. If a message doesn’t match the expected type, an error is raised
with a clear message:
>>> User.struct_validate_json(
... b'{"name": "bill", "groups": ["devops", 123]}'
... )
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
structtype.ValidationError: Expected `str`, got `int` - at `$.groups[1]`
“Strict” vs “Lax” Mode¶
structtype won’t perform unsafe implicit conversion by default (“strict”
mode). For example, if an integer is specified and a string is provided instead,
an error is raised rather than casting:
>>> User.struct_validate_json(
... b'{"name":"alice","groups":[1,2,3]}'
... )
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
structtype.ValidationError: Expected `str`, got `int` - at `$.groups[0]`
For cases where you’d like a more lax set of conversion rules, pass
strict=False:
>>> User.struct_validate_json(
... b'{"name":"alice","groups":["admin"],"email":null}',
... strict=False
... )
User(name='alice', groups={'admin'}, email=None)
See Supported Types for how lax mode affects individual types.
Converting to and from Builtin Types¶
In some cases, structtype only needs to process part of a message, and the
rest is handled by another library. For these situations, struct_dump and
struct_validate convert between high-level types and plain builtin types
(dict, list, str, int, …) without going through an encoded
representation.
struct_dumpis the “encoding” half. It applies the same semantics asstruct_dump_json— just with builtin Python types as the output rather than JSON bytes. This includes:Struct-level settings:
rename, Omitting Default Values,array_like, andtagfor tagged unions.Omission of UNSET fields.
Recursive expansion of nested
structtype.Struct,dataclasses.dataclass, attrs,typing.TypedDict, andtyping.NamedTuplevalues.Value-level conversions of types that don’t map directly to builtin types:
bytes/bytearray/memoryviewto base64 string,datetime.datetime/datetime.date/datetime.time/datetime.timedeltato ISO 8601 string,uuid.UUIDanddecimal.Decimalto string,set/frozensettolist,frozendicttodict,enum.Enumto its member value.
struct_validateis the “decoding” half: it takes builtin types and validates them against a schema, producing high-level types.
>>> from structtype import Struct
>>> class User(Struct, omit_defaults=True):
... name: str
... groups: set[str] = set()
... email: str | None = None
>>> alice = User("alice")
>>> # struct_dump applies omit_defaults and expands nested types
... alice.struct_dump()
{'name': 'alice'}
>>> # struct_validate is the inverse operation
... User.struct_validate({"name": "bill", "groups": ["devops"]})
User(name='bill', groups={'devops'}, email=None)
See Converters for a more detailed guide, including how to use these
functions to add structtype support for additional serialization protocols.
Note that struct_to_dict and struct_to_tuple are not equivalent to
struct_dump. They perform a one-to-one conversion of a single struct
instance to a dict or tuple, using the raw attribute names.
None of the semantics listed above apply. Every field is included regardless
of omit_defaults or structtype.UNSET, rename and tag are ignored,
nested structtype.Struct / dataclasses.dataclass / attrs values are left
as-is, and value-level types (bytes, datetime.datetime, uuid.UUID,
decimal.Decimal, enum.Enum, …) are not converted.
Prefer struct_dump when the output is intended for serialization.