zerial package

Module contents

class zerial.Sequence(item_type, restructure_factory=<class 'list'>, destructure_factory=<class 'list'>, apparent_type=NOTHING)[source]

Bases: zerial._base.Ztype, typing.Generic

Metadata type for a sequence of items.

Handles any version of N number of items of type T. Works for sets, tuples, lists, and anything else that follows that interface.

Attribute item_type:
 The type of the object contained in this sequence. Note that this can itself be another complex object or another Ztype, so these data types can be arbitrarily nested.
Attribute restructure_factory:
 The callable that will convert a stored sequence into a live data type. Basically, the function that can rebuild your data into the collection type you want.
Attribute destructure_factory:
 The callable that will convert a live sequence into storage data. Normally this will always be list, unless your serialization format supports other sequence types.
Attribute apparent_type:
 To be deprecated
default_apparent_type()[source]
destruct(inst, ztr)[source]

Unstructure inst into a mapping.

The Ztructurer doing the destructuring is passed for its options and to permit further recursive descent if necessary.

Works with the Ztructurer to take apart more complex types.

restruct(data, ztr)[source]

Structure the mapping into the appropriate type.

The Ztructurer doing the rebuilding is passed for its options and to permit recursive rebuilding if needed.

Works with Ztructurer to rebuild more complext types.

class zerial.Mapping(key_type: Type[K], val_type: Type[V], restructure_factory=<class 'dict'>, destructure_factory=<class 'dict'>, extract_pairs=operator.methodcaller('items'), apparent_type=typing.MutableMapping)[source]

Bases: zerial._base.Ztype, typing.Generic

Ztype wrapper for a simple mapping/dict

Since many serialization formats require that keys for mappings be strings, we require that the key_type be convertible to-and-from string. This limits us to pretty primitive types, like int and str.

Attribute key_type:
 

The type of the keys of the mapping. Currently only supports types that can do a straight-forward one-to-one convertion to and from str.

Attribute val_type:
 

The type of the values of the mapping. Can be any type that will can be serialized, including other Ztype objects, allowing arbirarily complex value types.

Attribute restructure_factory:
 

The container type that will be used to rebuild your data type upon being restructured. It will be called with an iterable of key-value pairs. The default is dict, but if you want, say, a collections.defaultdict to come out with a default function of int, you could give this:

@zerial.record
@attr.s
class MyRecord:
    my_field = attr.ib(
        type=typing.Mapping[str, int],
        metadata=zerial.data(zerial.Mapping(
            str, int, partial(defaultdict, int)
        )),
    )

This will result in my_field being restructured ready for you to do all the fun defaultdict stuff you’ve always wanted to do like my_record.my_field[arbitrary_key] += 1, because zerial ensures that it gets restructured that way.

Attribute destructure_factory:
 

The container type that will be used to take apart your data to destructure it. Can be useful if your mapping is ordered, in which case you’d want to save it as a list to preserve the order even in a serialized dict. This feature is unstable and may be replaced by something more sophisticated in the future.

Attribute extract_pairs:
 

Function to extract item pairs from the object created by destructure_factory. By default, this calls .items() on the object it receives, but if you were to destructure into a list, you’ll need to pass None here (which is converted to the identity function lambda x: x) since a list of pairs is already, well, a list of pairs. This feature is unstable and may be replaced by something better in the future.

destruct(inst, ztr)[source]

Unstructure inst into a mapping.

The Ztructurer doing the destructuring is passed for its options and to permit further recursive descent if necessary.

Works with the Ztructurer to take apart more complex types.

restruct(mapping, ztr)[source]

Structure the mapping into the appropriate type.

The Ztructurer doing the rebuilding is passed for its options and to permit recursive rebuilding if needed.

Works with Ztructurer to rebuild more complext types.

class zerial.Variant(type_records, default=<object object>, name: str = NOTHING, enum: enum.Enum = NOTHING)[source]

Bases: zerial._base.Ztype

Variant that allows multiple types to occupy the same attribute slot.

This is an implementation of a sum type (called enums or variants, depending on the source) for serialization. It allows multiple types to be saved in the same slot, and deserialized intelligently into the correct type. It accomplishes this by storing a name corresponding to the type along with the type information.

Attribute _type_records:
 Iterable of types, or a mapping of names to types. The types should be concrete types, in the sense that they can instantiate a real object of their class from provided data. They are treated as invariant. If you have multiple subclasses of a type, they must all be specified here. The Variant has to be able to store the type in the destructured data and consistently map it to the desired runtime type in the restuctured model, so it needs a full accounting of which types are available to it at definition time. If passed a mapping, the keys are taken as the type names. If passed a plain iterable, the type names are taken from the __name__ attribute of the class. Collisions are invalid, so if you have two types with the same __name__, use a mapping to give them unique names in this context.
Attribute default:
 Default type to use if no type information is found in the destructured data. This permits previously non-variant field to become variants without invalidating previously saved data.
NO_DEFAULT = <object object>
apparent_type

Special type indicating an unconstrained type.

  • Any is compatible with every type.
  • Any assumed to have all methods.
  • All values assumed to be instances of Any.

Note that all the above statements are true from the point of view of static type checkers. At runtime, Any should not be used with instance or class checks.

destruct(inst, ztr)[source]

Unstructure inst into a mapping.

The Ztructurer doing the destructuring is passed for its options and to permit further recursive descent if necessary.

Works with the Ztructurer to take apart more complex types.

name
restruct(data, ztr)[source]

Structure the mapping into the appropriate type.

The Ztructurer doing the rebuilding is passed for its options and to permit recursive rebuilding if needed.

Works with Ztructurer to rebuild more complext types.

types
class zerial.Serializer(to_outer: Callable[T, U], to_inner: Callable[U, T])[source]

Bases: zerial._base.Ztype, typing.Generic

When you just need a serializer that goes forward and back.

Attribute to_outer:
 Function that destructures the data.
Attribute to_inner:
 Function that restructures the data.

If the other metadata types fail, or there are obvious standard string representations of your data type (like in dates), you can just use a Serializer to take care of it for you:

import datetime

@zerial.record
@attr.s
class ImportantDate:
    name = attr.ib(type=str)
    date = attr.ib(
        type=datetime.date,
        metadata=zerial.data(zerial.Serializer(
            lambda d: d.isoformat(),
            lambda s: datetime.datetime.strptime(s, '%Y-%m-%d').date(),
        )),
    )

It doesn’t necessarily have to be a string either. If your mapping variant is too complex for Mapping, then you could use this class as a last resort for defining a method of destructuring it.

destruct(inst, _)[source]

Unstructure inst into a mapping.

The Ztructurer doing the destructuring is passed for its options and to permit further recursive descent if necessary.

Works with the Ztructurer to take apart more complex types.

restruct(data, _)[source]

Structure the mapping into the appropriate type.

The Ztructurer doing the rebuilding is passed for its options and to permit recursive rebuilding if needed.

Works with Ztructurer to rebuild more complext types.

class zerial.Ztructurer(dict_factory=<class 'dict'>, metachar: str = '%', permitted_passthrus: tuple = (<class 'bool'>, <class 'int'>, <class 'float'>, <class 'str'>), is_serializable_field=operator.attrgetter('init'), encoders=NOTHING, can_structure=<function has>)[source]

Bases: object

can_encode(type)[source]
can_pass_thru(val)[source]
can_structure(tobj)[source]
destructure(inst, type=None)[source]
get_encoder(type)[source]
get_metakey(key)[source]
record(cls)[source]

Decorator to indicate that a class is serializable

Currently does nothing special, but in the future it may be used to add automated features, and could potentially become required to serialize objects in certain contexts.

restructure(type, mapping)[source]
zerial.zdata(ztype)[source]
zerial.Zapping

alias of zerial._data.Mapping

zerial.Zariant

alias of zerial._data.Variant

zerial.Zequence

alias of zerial._data.Sequence

zerial.Zerializer

alias of zerial._data.Serializer