Source code for aiomas.codecs

"""
This package imports the codecs that can be used for de- and encoding incoming
and outgoing messages:

- :class:`JSON` uses `JSON <http://www.json.org/>`_
- :class:`MsgPack` uses `msgpack <http://msgpack.org/>`_

All codecs should implement the base class :class:`Codec`.

"""
__all__ = ['Codec', 'JSON', 'MsgPack']

import json

import msgpack


[docs]class Codec: """Base class for all Codecs. Subclasses must implement :meth:`encode()` and :meth:`decode()`. """ def __init__(self): self._serializers = {} self._deserializers = {}
[docs] def encode(self, data): """Encode the given *data* and return a :class:`bytes` object.""" raise NotImplementedError
[docs] def decode(self, data): """Decode *data* from :class:`bytes` to the original data structure.""" raise NotImplementedError
[docs] def add_serializer(self, type, serialize, deserialize): """Add methods to *serialize* and *deserialize* objects typed *type*. This can be used to de-/encode objects that the codec otherwise couldn't encode. *serialize* will receive the unencoded object and needs to return an encodable serialization of it. *deserialize* will receive an objects representation and should return an instance of the original object. """ typeid = len(self._serializers) self._serializers[type] = (typeid, serialize) self._deserializers[typeid] = deserialize
[docs] def serialize_obj(self, obj): """Serialize *obj* to something that the codec can encode.""" otype = type(obj) if otype not in self._serializers: # Fallback to a generic serializer (if available) otype = object try: typeid, serialize = self._serializers[otype] except KeyError: raise TypeError('No serializer found for type "%s"' % otype) \ from None return {'__type__': (typeid, serialize(obj))}
[docs] def deserialize_obj(self, obj_repr): """Deserialize the original object from *obj_repr*.""" # This method is called for *all* dicts so we have to check if it # contains a desrializable type. if '__type__' in obj_repr: typeid, data = obj_repr['__type__'] obj_repr = self._deserializers[typeid](data) return obj_repr
[docs]class JSON(Codec): """A :class:`Codec` that uses *JSON* to encode and decode messages.""" def encode(self, data): return json.dumps(data, default=self.serialize_obj).encode() def decode(self, data): return json.loads(data.decode(), object_hook=self.deserialize_obj)
[docs]class MsgPack(Codec): """A :class:`Codec` that uses *msgpack* to encode and decode messages.""" def encode(self, data): return msgpack.packb(data, default=self.serialize_obj) def decode(self, data): return msgpack.unpackb(data, object_hook=self.deserialize_obj, use_list=False, encoding='utf-8')