Serialization
Defines CBOR serialization interfaces and provides useful serialization classes.
- pycardano.serialization.default_encoder(encoder: CBOREncoder, value: Union[CBORSerializable, IndefiniteList])
A fallback function that encodes CBORSerializable to CBOR
- class pycardano.serialization.IndefiniteList(li: Union[bytes, bytearray, str, int, float, Decimal, bool, None, tuple, list, IndefiniteList, dict, defaultdict, OrderedDict, datetime, Pattern, CBORSimpleValue, CBORTag, set, Fraction, frozenset, FrozenDict, FrozenList, IndefiniteFrozenList, ByteString])
Bases:
UserList
- class pycardano.serialization.CBORSerializable
Bases:
object
CBORSerializable standardizes the interfaces a class should implement in order for it to be serialized to and deserialized from CBOR.
Two required interfaces to implement are
to_primitive()
andfrom_primitive()
.to_primitive()
converts an object to a CBOR primitive type (seePrimitive
), which could be then encoded by CBOR library.from_primitive()
restores an object from a CBOR primitive type.To convert a CBORSerializable to CBOR, use
to_cbor()
. To restore a CBORSerializable from CBOR, usefrom_cbor()
.Note
to_primitive()
needs to return a pure CBOR primitive type, meaning that the returned value and all its child elements have to be CBOR primitives, which could mean a good amount of work. An alternative but simpler approach is to implementto_shallow_primitive()
instead. to_shallow_primitive allows the returned object to be either CBORPrimitive
or aCBORSerializable
, as long as theCBORSerializable
does not refer to itself, which could cause infinite loops.- to_shallow_primitive() Union[bytes, bytearray, str, int, float, Decimal, bool, None, tuple, list, IndefiniteList, dict, defaultdict, OrderedDict, datetime, Pattern, CBORSimpleValue, CBORTag, set, Fraction, frozenset, FrozenDict, FrozenList, IndefiniteFrozenList, ByteString]
Convert the instance to a CBOR primitive. If the primitive is a container, e.g. list, dict, the type of its elements could be either a Primitive or a CBORSerializable.
- Returns:
A CBOR primitive.
- Return type:
Primitive
- Raises:
SerializeException – When the object could not be converted to CBOR primitive types.
- to_primitive() Union[bytes, bytearray, str, int, float, Decimal, bool, None, tuple, list, IndefiniteList, dict, defaultdict, OrderedDict, datetime, Pattern, CBORSimpleValue, CBORTag, set, Fraction, frozenset, FrozenDict, FrozenList, IndefiniteFrozenList, ByteString]
Convert the instance and its elements to CBOR primitives recursively.
- Returns:
A CBOR primitive.
- Return type:
Primitive
- Raises:
SerializeException – When the object or its elements could not be converted to CBOR primitive types.
- validate()
Validate the data stored in the current instance. Defaults to always pass.
- Raises:
InvalidDataException – When the data is invalid.
- to_validated_primitive() Union[bytes, bytearray, str, int, float, Decimal, bool, None, tuple, list, IndefiniteList, dict, defaultdict, OrderedDict, datetime, Pattern, CBORSimpleValue, CBORTag, set, Fraction, frozenset, FrozenDict, FrozenList, IndefiniteFrozenList, ByteString]
Convert the instance and its elements to CBOR primitives recursively with data validated by
validate()
method.- Returns:
A CBOR primitive.
- Return type:
Primitive
- Raises:
SerializeException – When the object or its elements could not be converted to CBOR primitive types.
- classmethod from_primitive(value: Any, type_args: Optional[tuple] = None) CBORBase
Turn a CBOR primitive to its original class type.
- Parameters:
cls (CBORBase) – The original class type.
value (
Primitive
) – A CBOR primitive.type_args (Optional[tuple]) – Type arguments for the class.
- Returns:
A CBOR serializable object.
- Return type:
CBORBase
- Raises:
DeserializeException – When the object could not be restored from primitives.
- to_cbor() bytes
Encode a Python object into CBOR bytes.
- Returns:
Python object encoded in cbor bytes.
- Return type:
bytes
Examples
>>> class Test(CBORSerializable): ... def __init__(self, number1, number2): ... self.number1 = number1 ... self.number2 = number2 ... ... def to_primitive(value): ... return [value.number1, value.number2] ... ... @classmethod ... def from_primitive(cls, value): ... return cls(value[0], value[1]) ... ... def __repr__(self): ... return f"Test({self.number1}, {self.number2})" >>> a = Test(1, 2) >>> a.to_cbor().hex() '820102'
- to_cbor_hex() str
Encode a Python object into CBOR hex.
- Returns:
Python object encoded in cbor hex string.
- Return type:
str
- classmethod from_cbor(payload: Union[str, bytes]) CBORSerializable
Restore a CBORSerializable object from a CBOR.
- Parameters:
payload (Union[str, bytes]) – CBOR bytes or hex string to restore from.
- Returns:
Restored CBORSerializable object.
- Return type:
Examples
Basic use case:
>>> class Test(CBORSerializable): ... def __init__(self, number1, number2): ... self.number1 = number1 ... self.number2 = number2 ... ... def to_primitive(value): ... return [value.number1, value.number2] ... ... @classmethod ... def from_primitive(cls, value): ... return cls(value[0], value[1]) ... ... def __repr__(self): ... return f"Test({self.number1}, {self.number2})" >>> a = Test(1, 2) >>> cbor_hex = a.to_cbor_hex() >>> print(Test.from_cbor(cbor_hex)) Test(1, 2)
For a CBORSerializable that has CBORSerializables as attributes, we will need to pass each child value to the
from_primitive()
method of its corresponding CBORSerializable. Example:>>> class TestParent(CBORSerializable): ... def __init__(self, number1, test): ... self.number1 = number1 ... self.test = test ... ... def to_shallow_primitive(value): # Implementing `to_shallow_primitive` simplifies the work. ... return [value.number1, value.test] ... ... @classmethod ... def from_primitive(cls, value): ... test = Test.from_primitive(value[1]) # Restore test by passing `value[1]` to ... # `Test.from_primitive` ... return cls(value[0], test) ... ... def __repr__(self): ... return f"TestParent({self.number1}, {self.test})" >>> a = Test(1, 2) >>> b = TestParent(3, a) >>> b TestParent(3, Test(1, 2)) >>> cbor_hex = b.to_cbor_hex() >>> cbor_hex '8203820102' >>> print(TestParent.from_cbor(cbor_hex)) TestParent(3, Test(1, 2))
- class pycardano.serialization.ArrayCBORSerializable
Bases:
CBORSerializable
A base class that can serialize its child dataclass into a CBOR array.
The class is useful when the position of each item in a list have its own semantic meaning.
Examples
Basic usages:
>>> from dataclasses import dataclass >>> @dataclass ... class Test1(ArrayCBORSerializable): ... a: str ... b: str=None >>> @dataclass ... class Test2(ArrayCBORSerializable): ... c: str ... test1: Test1 >>> t = Test2(c="c", test1=Test1(a="a")) >>> t Test2(c='c', test1=Test1(a='a', b=None)) >>> cbor_hex = t.to_cbor_hex() >>> cbor_hex '826163826161f6' >>> Test2.from_cbor(cbor_hex) Test2(c='c', test1=Test1(a='a', b=None))
A value of None will be encoded as nil (#7.22) in cbor. This will become a problem if the field is meant to be optional. To exclude an optional attribute from cbor, we can use field constructor with a metadata field “optional” set to True and default value set to None.
Note
In ArrayCBORSerializable, all non-optional fields have to be declared before any optional field.
Example:
>>> from dataclasses import dataclass, field >>> @dataclass ... class Test1(ArrayCBORSerializable): ... a: str ... b: str=field(default=None, metadata={"optional": True}) >>> @dataclass ... class Test2(ArrayCBORSerializable): ... c: str ... test1: Test1 >>> t = Test2(c="c", test1=Test1(a="a")) >>> t Test2(c='c', test1=Test1(a='a', b=None)) >>> t.to_primitive() # Notice below that attribute "b" is not included in converted primitive. ['c', ['a']] >>> cbor_hex = t.to_cbor_hex() >>> cbor_hex '826163816161' >>> Test2.from_cbor(cbor_hex) Test2(c='c', test1=Test1(a='a', b=None))
- to_shallow_primitive() Union[bytes, bytearray, str, int, float, Decimal, bool, None, tuple, list, IndefiniteList, dict, defaultdict, OrderedDict, datetime, Pattern, CBORSimpleValue, CBORTag, set, Fraction, frozenset, FrozenDict, FrozenList, IndefiniteFrozenList, ByteString]
- Returns:
A CBOR primitive.
- Return type:
Primitive
- Raises:
SerializeException – When the object could not be converted to CBOR primitive types.
- classmethod from_primitive(values: Union[list, tuple]) ArrayBase
Restore a primitive value to its original class type.
- Parameters:
cls (ArrayBase) – The original class type.
values (List[Primitive]) – A list whose elements are CBOR primitives.
- Returns:
Restored object.
- Return type:
ArrayBase
- Raises:
DeserializeException – When the object could not be restored from primitives.
- class pycardano.serialization.MapCBORSerializable
Bases:
CBORSerializable
A base class that can serialize its child dataclass into a CBOR Map.
The class is useful when each key in a map have its own semantic meaning.
Examples
Basic usage:
>>> from dataclasses import dataclass, field >>> @dataclass ... class Test1(MapCBORSerializable): ... a: str="" ... b: str="" >>> @dataclass ... class Test2(MapCBORSerializable): ... c: str=None ... test1: Test1=field(default_factory=Test1) >>> t = Test2(test1=Test1(a="a")) >>> t Test2(c=None, test1=Test1(a='a', b='')) >>> t.to_primitive() {'c': None, 'test1': {'a': 'a', 'b': ''}} >>> cbor_hex = t.to_cbor_hex() >>> cbor_hex 'a26163f6657465737431a261616161616260' >>> Test2.from_cbor(cbor_hex) Test2(c=None, test1=Test1(a='a', b=''))
In the example above, all keys in the map share the same name as their corresponding attributes. However, sometimes we want to use different keys when serializing some attributes, this could be achieved by adding a “key” value to the metadata of a field. Example:
>>> from dataclasses import dataclass, field >>> @dataclass ... class Test1(MapCBORSerializable): ... a: str=field(default="", metadata={"key": "0"}) ... b: str=field(default="", metadata={"key": "1"}) >>> @dataclass ... class Test2(MapCBORSerializable): ... c: str=field(default=None, metadata={"key": "0", "optional": True}) ... test1: Test1=field(default_factory=Test1, metadata={"key": "1"}) >>> t = Test2(test1=Test1(a="a")) >>> t Test2(c=None, test1=Test1(a='a', b='')) >>> t.to_primitive() {'1': {'0': 'a', '1': ''}} >>> cbor_hex = t.to_cbor_hex() >>> cbor_hex 'a16131a261306161613160' >>> Test2.from_cbor(cbor_hex) Test2(c=None, test1=Test1(a='a', b=''))
- to_shallow_primitive() Union[bytes, bytearray, str, int, float, Decimal, bool, None, tuple, list, IndefiniteList, dict, defaultdict, OrderedDict, datetime, Pattern, CBORSimpleValue, CBORTag, set, Fraction, frozenset, FrozenDict, FrozenList, IndefiniteFrozenList, ByteString]
Convert the instance to a CBOR primitive. If the primitive is a container, e.g. list, dict, the type of its elements could be either a Primitive or a CBORSerializable.
- Returns:
A CBOR primitive.
- Return type:
Primitive
- Raises:
SerializeException – When the object could not be converted to CBOR primitive types.
- classmethod from_primitive(values: Union[dict, FrozenDict]) MapBase
Restore a primitive value to its original class type.
- Parameters:
cls (MapBase) – The original class type.
values (
Primitive
) – A CBOR primitive.
- Returns:
Restored object.
- Return type:
MapBase
- Raises:
pycardano.exception.DeserializeException – When the object could not be restored from primitives.
- class pycardano.serialization.DictCBORSerializable(*args, **kwargs)
Bases:
CBORSerializable
A dictionary class where all keys share the same type and all values share the same type.
Examples
>>> @dataclass ... class Test1(ArrayCBORSerializable): ... a: int ... b: str >>> >>> class Test2(DictCBORSerializable): ... KEY_TYPE = str ... VALUE_TYPE = Test1 >>> >>> t = Test2() >>> t["x"] = Test1(a=1, b="x") >>> t["y"] = Test1(a=2, b="y") >>> primitives = t.to_primitive() >>> deserialized = Test2.from_primitive(primitives) >>> assert t == deserialized >>> t[1] = 2 Traceback (most recent call last): ... typeguard.TypeCheckError: int is not an instance of str
- KEY_TYPE
alias of
Type
[Any
]
- VALUE_TYPE
alias of
Type
[Any
]
- validate()
Validate the data stored in the current instance. Defaults to always pass.
- Raises:
InvalidDataException – When the data is invalid.
- to_shallow_primitive() dict
Convert the instance to a CBOR primitive. If the primitive is a container, e.g. list, dict, the type of its elements could be either a Primitive or a CBORSerializable.
- Returns:
A CBOR primitive.
- Return type:
Primitive
- Raises:
SerializeException – When the object could not be converted to CBOR primitive types.
- classmethod from_primitive(value: dict) DictBase
Restore a primitive value to its original class type.
- Parameters:
cls (DictBase) – The original class type.
value (
Primitive
) – A CBOR primitive.
- Returns:
Restored object.
- Return type:
DictBase
- Raises:
DeserializeException – When the object could not be restored from primitives.
- copy() DictCBORSerializable
- class pycardano.serialization.RawCBOR(cbor: bytes)
Bases:
object
A wrapper class for bytes that represents a CBOR value.
- cbor: bytes
- pycardano.serialization.list_hook(cls: Type[CBORBase]) Callable[[List[Union[bytes, bytearray, str, int, float, Decimal, bool, None, tuple, list, IndefiniteList, dict, defaultdict, OrderedDict, datetime, Pattern, CBORSimpleValue, CBORTag, set, Fraction, frozenset, FrozenDict, FrozenList, IndefiniteFrozenList, ByteString]]], List[CBORBase]]
A factory that generates a Callable which turns a list of Primitive to a list of CBORSerializables.
- Parameters:
cls (CBORBase) – The type of CBORSerializable the list will be converted to.
- Returns:
- An Callable that restores a list of Primitive to a list of
CBORSerializables.
- Return type:
Callable[[List[Primitive]], List[CBORBase]]
- pycardano.serialization.limit_primitive_type(*allowed_types)
A helper function to validate primitive type given to from_primitive class methods
Not exposed to public by intention.
- class pycardano.serialization.OrderedSet(iterable: Optional[List[T]] = None, use_tag: bool = True)
Bases:
list
,Generic
[T
],CBORSerializable
- append(item: T) None
Append object to the end of the list.
- extend(items: Iterable[T]) None
Extend list by appending elements from the iterable.
- to_shallow_primitive() Union[CBORTag, List[T]]
Convert the instance to a CBOR primitive. If the primitive is a container, e.g. list, dict, the type of its elements could be either a Primitive or a CBORSerializable.
- Returns:
A CBOR primitive.
- Return type:
Primitive
- Raises:
SerializeException – When the object could not be converted to CBOR primitive types.
- classmethod from_primitive(value: Union[bytes, bytearray, str, int, float, Decimal, bool, None, tuple, list, IndefiniteList, dict, defaultdict, OrderedDict, datetime, Pattern, CBORSimpleValue, CBORTag, set, Fraction, frozenset, FrozenDict, FrozenList, IndefiniteFrozenList, ByteString], type_args: Optional[tuple] = None) OrderedSet[T]
Turn a CBOR primitive to its original class type.
- Parameters:
cls (CBORBase) – The original class type.
value (
Primitive
) – A CBOR primitive.type_args (Optional[tuple]) – Type arguments for the class.
- Returns:
A CBOR serializable object.
- Return type:
CBORBase
- Raises:
DeserializeException – When the object could not be restored from primitives.
- class pycardano.serialization.NonEmptyOrderedSet(iterable: Optional[List[T]] = None, use_tag: bool = True)
Bases:
OrderedSet
[T
]- validate()
Validate the data stored in the current instance. Defaults to always pass.
- Raises:
InvalidDataException – When the data is invalid.
- classmethod from_primitive(value: Union[bytes, bytearray, str, int, float, Decimal, bool, None, tuple, list, IndefiniteList, dict, defaultdict, OrderedDict, datetime, Pattern, CBORSimpleValue, CBORTag, set, Fraction, frozenset, FrozenDict, FrozenList, IndefiniteFrozenList, ByteString], type_args: Optional[tuple] = None) NonEmptyOrderedSet[T]
Turn a CBOR primitive to its original class type.
- Parameters:
cls (CBORBase) – The original class type.
value (
Primitive
) – A CBOR primitive.type_args (Optional[tuple]) – Type arguments for the class.
- Returns:
A CBOR serializable object.
- Return type:
CBORBase
- Raises:
DeserializeException – When the object could not be restored from primitives.
- class pycardano.serialization.CodedSerializable
Bases:
ArrayCBORSerializable
A base class for CBORSerializable types that have a specific code.
This class provides a mechanism to validate the type of the object based on its first element.
Examples
>>> from dataclasses import dataclass, field >>> @dataclass ... class TestCoded(CodedSerializable): ... _CODE = 1 ... value: str >>> >>> # Create and serialize an instance >>> test = TestCoded("hello") >>> primitives = test.to_primitive() >>> primitives [1, 'hello'] >>> >>> # Deserialize valid data >>> restored = TestCoded.from_primitive(primitives) >>> restored.value 'hello' >>> >>> # Attempting to deserialize with wrong code raises exception >>> invalid_data = [2, "hello"] >>> TestCoded.from_primitive(invalid_data) Traceback (most recent call last): ... DeserializeException: Invalid TestCoded type 2
- classmethod from_primitive(values: Union[list, tuple]) CodedSerializable
Restore a primitive value to its original class type.
- Parameters:
cls (ArrayBase) – The original class type.
values (List[Primitive]) – A list whose elements are CBOR primitives.
- Returns:
Restored object.
- Return type:
ArrayBase
- Raises:
DeserializeException – When the object could not be restored from primitives.