How-to — Serializer Composition


The Basics

A composite serializer fulfills the same need as a composite converter, which is to handle two disjoint formats between sent and received packet data.

This is typically done using the StapledPacketSerializer:

>>> import pickle
>>> from easynetwork.serializers import *
>>> from easynetwork.serializers.composite import *
>>> s = StapledPacketSerializer(sent_packet_serializer=PickleSerializer(), received_packet_serializer=JSONSerializer())
>>> s.deserialize(b'{"data": 42}')
{'data': 42}
>>> data = s.serialize({"data": 42})
>>> pickle.loads(data)
{'data': 42}

StapledPacketSerializer will return the correct implementation according to the base class of sent_packet_serializer and received_packet_serializer:

>>> from easynetwork.serializers.abc import *
>>>
>>> StapledPacketSerializer(sent_packet_serializer=PickleSerializer(), received_packet_serializer=JSONSerializer())
StapledPacketSerializer(...)
>>> isinstance(_, (AbstractIncrementalPacketSerializer, BufferedIncrementalPacketSerializer))
False
>>>
>>> StapledPacketSerializer(sent_packet_serializer=StringLineSerializer(), received_packet_serializer=JSONSerializer())
StapledIncrementalPacketSerializer(...)
>>> isinstance(_, AbstractIncrementalPacketSerializer)
True
>>>
>>> StapledPacketSerializer(sent_packet_serializer=JSONSerializer(), received_packet_serializer=StringLineSerializer())
StapledBufferedIncrementalPacketSerializer(...)
>>> isinstance(_, BufferedIncrementalPacketSerializer)
True

Use Case: Different Structure Between A Request And A Response

>>> from typing import NamedTuple
>>> from easynetwork.serializers import NamedTupleStructSerializer
>>> from easynetwork.serializers.composite import StapledPacketSerializer
>>> class Request(NamedTuple):
...     type: int
...     data: bytes
...
>>> class Response(NamedTuple):
...     rc: int
...     message: str
...
>>> s = StapledPacketSerializer(
...     sent_packet_serializer=NamedTupleStructSerializer(Request, {"type": "B", "data": "1024s"}, encoding=None),
...     received_packet_serializer=NamedTupleStructSerializer(Response, {"rc": "h", "message": "10s"}, encoding="utf8"),
... )
>>> s.serialize(Request(type=42, data=b"some data to send"))
b'*some data to send\x00\x00\x00\x00\x00...'
>>> s.deserialize(b"\x00\xc8OK\x00\x00\x00\x00\x00\x00\x00\x00")
Response(rc=200, message='OK')