Public API

Entry points

class compages.Structurer(handlers: Mapping[Any, StructureHandler] = {})[source]
structure_into(structure_into: type[_T] | TypedNewType[_T], val: Any, user_context: Any | None = None) _T[source]

Structures (deserializes) the given value into the type structure_into with an optional user_context (which will be passed to the handlers).

Raises StructuringError for any structuring-related error.

class compages.Unstructurer(handlers: Mapping[Any, UnstructureHandler] = {})[source]
unstructure_as(unstructure_as: type[_T] | TypedNewType[_T], val: _T, user_context: Any | None = None) Any[source]

Unstructures (serializes) the given value as the type unstructure_as with an optional user_context (which will be passed to the handlers).

Calls isinstance_ext() at the beginning, raising UnstructuringError on failure.

Raises UnstructuringError for any unstructuring-related error.

Custom handlers

class compages.StructureHandler[source]

A base class for structuring logic attached to a type.

simple_structure(value: Any) Any[source]

Structures the given value.

Use for the cases where the information from context is not needed. If structure() is not defined, this method must be defined.

structure(context: StructurerContext, value: Any) Any[source]

Structures the given value returning an instance of context.structure_into.

If not defined, falls back to simple_structure().

class compages.StructurerContext[source]

A context object passed to handlers during structuring.

nested_structure_into(structure_into: type[_T] | TypedNewType[_T], val: Any) _T[source]

Calls Structurer.structure_into() of self.structurer passing on the user context.

structure_into: type[Any] | TypedNewType[Any]

The requested return value type.

Can be a regular type, a newtype, or a generic type.

structurer: Structurer

The current structurer.

user_context: Any

The custom object the user passed to Unstructurer.unstructure_as().

class compages.UnstructureHandler[source]

A base class for unstructuring logic attached to a type.

simple_unstructure(value: Any) Any[source]

Unstructures the given value.

Use for the cases where the information from context is not needed. If unstructure() is not defined, this method must be defined.

unstructure(context: UnstructurerContext, value: Any) Any[source]

Unstructures (serializes) the given value given context.

It is guaranteed that isinstance_ext(val, get_lookup_order(context.unstructure_as)) == True (see isinstance_ext() and get_lookup_order()).

class compages.UnstructurerContext[source]

A context object passed to handlers during unstructuring.

nested_unstructure_as(unstructure_as: type[_T] | TypedNewType[_T], val: _T) Any[source]

Calls Unstructurer.unstructure_as() of self.unstructurer passing on the user context.

unstructure_as: type[Any] | TypedNewType[Any]

The type which the value should be treated as.

Can be a regular type, a newtype, or a generic type.

unstructurer: Unstructurer

The current unstructurer.

user_context: Any

The custom object the user passed to Unstructurer.unstructure_as().

class compages.StructLikeOptions(to_unstructured_name: ~collections.abc.Callable[[str, ~typing.Any], str] = <function StructLikeOptions.<lambda>>, unstructure_skip_defaults: bool = True, structure_fill_in_defaults: bool = True)[source]

Options for handlers working with struct-like types (dataclasses, named tuples etc).

to_unstructured_name(_metadata)

A function converting a field name of a typed representation into a field name of the corresponding unstructured representation.

The second argument is the metadata attached to the field (if any).

structure_fill_in_defaults: bool = True

If the field value is missing when structuring, substitute the default.

If this value is False, an error will be raised instead.

unstructure_skip_defaults: bool = True

If the field value equals to the default when unstructuring, do not output it.

Type resolution

class compages.DataclassBase[source]

A marker type for built-in dataclasses (since they don’t have a common base type). Use to attach dataclass-related handlers (e.g. IntoDataclassFromMapping).

class compages.NamedTupleBase[source]

A marker type for built-in named tuples (since they don’t have a common base type). Use to attach NamedTuple-related handlers (e.g. IntoNamedTupleFromMapping).

Type resolution (hazmat)

These functions define the logic of type lookup in structurers and unstructurers. They are not supposed to be used by themselves, they are exported to keep the documentation of that logic in one place.

class compages.TypedNewType[source]

Bases: Protocol, Generic[_T_co]

Unfortunately, typing.NewType in Python is not generic, so we cannot express the concept of “the type of instances of of this type, given the type’s type annotation”.

This protocol covers any instance of typing.NewType and has the same properties as type[_T].

compages.get_lookup_order(tp: type[Any] | TypedNewType[Any]) list[type[Any] | TypedNewType[Any]][source]

Returns the structuring/unstructuring handler lookup order for regular types, generic types, or newtypes.

The order is the following:

  • For a regular type, it equals to its .mro() without the last element (builtins.object).

  • For a :py:class`typing.NewType` instance, the order is the tp followed by the lookup order for tp.__supertype__.

  • For a generic (something with a non-None typing.get_origin()), the order is tp followed by the lookup order for the origin.

  • For a dataclass, a DataclassBase marker type is appended to the end of the returned list.

  • For a named tuple, a NamedTupleBase marker type is inserted just before tuple.

Note

If you want to assign a handler for generic unions, note that typing.Union[...] has the origin typing.Union, but type1 | type2 | ... has the origin types.UnionType.

compages.isinstance_ext(val: Any, lookup_order: list[type[Any] | TypedNewType[Any]]) bool[source]

An extended isinstance() working with newtypes and generic types.

Instead of an actual type tp takes the return value of get_lookup_order(tp) (for performance reasons).

If tp is a regular type, returns isinstance(val, tp).

If tp is a NewType, returns isinstance(val, base_tp) where base_tp is the first regular supertype of the newtype hierarchy.

If tp is a generic, isinstance_ext() does not attempt to introspect the value (not that it has any means to, at this level), only checking for isinstance() with the origin. That is, isinstance_ext(val, list[int]) == isinstance(val, list), regardless of what type the elements of val are (checking that is the responsibility of handlers).

All generics are currently assumed to be covariant.

As a corollary or that, isinstance_ext(val, UnionType[...]) is always True.

Built-in structuring handlers

class compages.IntoBool[source]

Bases: StructureHandler

If val is a bool, structures into itself, otherwise raises a StructuringError.

class compages.IntoBytes[source]

Bases: StructureHandler

If val is a bytes, structures into itself, otherwise raises a StructuringError.

class compages.IntoDataclassFromMapping(options: ~compages._struct_like.StructLikeOptions = StructLikeOptions(to_unstructured_name=<function StructLikeOptions.<lambda>>, unstructure_skip_defaults=True, structure_fill_in_defaults=True))[source]

Bases: StructureHandler

Attempts to structure into a dataclass() instance from a Mapping type.

class compages.IntoDataclassFromSequence(options: ~compages._struct_like.StructLikeOptions = StructLikeOptions(to_unstructured_name=<function StructLikeOptions.<lambda>>, unstructure_skip_defaults=True, structure_fill_in_defaults=True))[source]

Bases: StructureHandler

Attempts to structure into a dataclass() instance from a Sequence type.

class compages.IntoDict[source]

Bases: StructureHandler

Attempts to structure into a dict given its type arguments.

If the requested type is an unqalified dict, it is treated as dict[Any, Any].

class compages.IntoFloat[source]

Bases: StructureHandler

If val is a float or int, converts into float, otherwise raises a StructuringError.

class compages.IntoInt[source]

Bases: StructureHandler

If val is an int (but not bool), structures into itself, otherwise raises a StructuringError.

class compages.IntoList[source]

Bases: StructureHandler

Attempts to structure into a list given its type arguments.

If the requested type is an unqalified list, it is treated as list[Any].

class compages.IntoNamedTupleFromMapping(options: ~compages._struct_like.StructLikeOptions = StructLikeOptions(to_unstructured_name=<function StructLikeOptions.<lambda>>, unstructure_skip_defaults=True, structure_fill_in_defaults=True))[source]

Bases: StructureHandler

Attempts to structure into a NamedTuple instance from a Mapping type.

class compages.IntoNamedTupleFromSequence(options: ~compages._struct_like.StructLikeOptions = StructLikeOptions(to_unstructured_name=<function StructLikeOptions.<lambda>>, unstructure_skip_defaults=True, structure_fill_in_defaults=True))[source]

Bases: StructureHandler

Attempts to structure into a NamedTuple instance from a Sequence type.

class compages.IntoNone[source]

Bases: StructureHandler

If val is None, structures into itself, otherwise raises a StructuringError.

class compages.IntoStr[source]

Bases: StructureHandler

If val is a str, structures into itself, otherwise raises a StructuringError.

class compages.IntoTuple[source]

Bases: StructureHandler

Attempts to structure into a tuple given its type arguments.

If the requested type is an unqalified tuple, it is treated as tuple[Any, ...].

class compages.IntoUnion[source]

Bases: StructureHandler

Attempts to structure into every type in the union in order, returns the result of the first succeeded call.

If none succeeded, raises a StructuringError.

Built-in structuring handlers

class compages.AsBool[source]

Bases: UnstructureHandler

Unstructures anything convertable to a bool as a bool.

class compages.AsBytes[source]

Bases: UnstructureHandler

Unstructures anything convertable to bytes as bytes.

class compages.AsDataclassToDict(options: ~compages._struct_like.StructLikeOptions = StructLikeOptions(to_unstructured_name=<function StructLikeOptions.<lambda>>, unstructure_skip_defaults=True, structure_fill_in_defaults=True))[source]

Bases: UnstructureHandler

Unstructures a dataclass() instance into a dict.

class compages.AsDataclassToList(options: ~compages._struct_like.StructLikeOptions = StructLikeOptions(to_unstructured_name=<function StructLikeOptions.<lambda>>, unstructure_skip_defaults=True, structure_fill_in_defaults=True))[source]

Bases: UnstructureHandler

Unstructures a dataclass() instance into a list.

class compages.AsDict[source]

Bases: UnstructureHandler

Unstructures as a dict given its type arguments.

If the requested type is an unqalified dict, it is treated as dict[Any, Any].

class compages.AsFloat[source]

Bases: UnstructureHandler

Unstructures anything convertable to a float as a float.

class compages.AsInt[source]

Bases: UnstructureHandler

Unstructures anything convertable to an int (but not bool) as an int.

class compages.AsList[source]

Bases: UnstructureHandler

Unstructures as a list given its type arguments.

If the requested type is an unqalified list, it is treated as list[Any].

class compages.AsNamedTupleToDict(options: ~compages._struct_like.StructLikeOptions = StructLikeOptions(to_unstructured_name=<function StructLikeOptions.<lambda>>, unstructure_skip_defaults=True, structure_fill_in_defaults=True))[source]

Bases: UnstructureHandler

Unstructures a NamedTuple instance into a dict.

class compages.AsNamedTupleToList(options: ~compages._struct_like.StructLikeOptions = StructLikeOptions(to_unstructured_name=<function StructLikeOptions.<lambda>>, unstructure_skip_defaults=True, structure_fill_in_defaults=True))[source]

Bases: UnstructureHandler

Unstructures a NamedTuple instance into a list.

class compages.AsNone[source]

Bases: UnstructureHandler

Unstructures None as itself.

class compages.AsStr[source]

Bases: UnstructureHandler

Unstructures anything convertable to a str as str.

class compages.AsTuple[source]

Bases: UnstructureHandler

Unstructures as a tuple given its type arguments.

If the requested type is an unqalified tuple, it is treated as tuple[Any, ...].

class compages.AsUnion[source]

Bases: UnstructureHandler

Attempts to unstructure as every typr in the union in order, returns the result of the first succeeded call.

If none succeeded, raises a UnstructuringError.

Errors

class compages.StructuringError(message: str, inner_errors: list[tuple[StructField | UnionVariant | ListElem | DictKey | DictValue, StructuringError]] = [])[source]

An error during structuring.

Accumulates possible nested errors.

class compages.UnstructuringError(message: str, inner_errors: list[tuple[StructField | UnionVariant | ListElem | DictKey | DictValue, UnstructuringError]] = [])[source]

An error during unstructuring.

Accumulates possible nested errors.

class compages.path.DictKey(key: Any)[source]

A dictionary key.

class compages.path.DictValue(key: Any)[source]

A dictionary value.

class compages.path.ListElem(index: int)[source]

A list element.

class compages.path.StructField(name: str)[source]

A structure field.

class compages.path.UnionVariant(type_: type)[source]

A union variant.