Extension Types

u-msgpack-python supports two mechanisms for packing and unpacking MessagePack Ext types: the ext_handlers keyword option, and the ext_serializable() decorator.

Ext Handlers

The packing functions accept an optional ext_handlers dictionary that maps custom types to callables that pack the type into an Ext object. The callable should accept the custom type object as an argument and return a packed umsgpack.Ext object.

Example for packing set, complex, and decimal.Decimal types into Ext objects with type codes 0x20, 0x30, and 0x40, respectively:

>>> umsgpack.packb([1, True, {"foo", 2}, complex(3, 4), decimal.Decimal("0.31")],
...  ext_handlers = {
...   set: lambda obj: umsgpack.Ext(0x20, umsgpack.packb(list(obj))),
...   complex: lambda obj: umsgpack.Ext(0x30, struct.pack("ff", obj.real, obj.imag)),
...   decimal.Decimal: lambda obj: umsgpack.Ext(0x40, str(obj).encode()),
... })
b'\x95\x01\xc3\xc7\x06 \x92\xa3foo\x02\xd70\x00\x00@@\x00\x00\x80@\xd6@0.31'
>>> 

Similarly, the unpacking functions accept an optional ext_handlers dictionary that maps Ext type codes to callables that unpack the Ext into a custom object. The callable should accept a umsgpack.Ext object as an argument and return an unpacked custom type object.

Example for unpacking Ext objects with type codes 0x20, 0x30, and 0x40, into set, complex, and decimal.Decimal typed objects, respectively:

>>> umsgpack.unpackb(b'\x95\x01\xc3\xc7\x06 \x92\xa3foo\x02\xd70\x00\x00@@\x00\x00\x80@\xd6@0.31',
...  ext_handlers = {
...   0x20: lambda ext: set(umsgpack.unpackb(ext.data)),
...   0x30: lambda ext: complex(*struct.unpack("ff", ext.data)),
...   0x40: lambda ext: decimal.Decimal(ext.data.decode()),
... })
[1, True, {'foo', 2}, (3+4j), Decimal('0.31')]
>>> 

Example for packing and unpacking a custom class:

class Point(object):
    def __init__(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z

    def __str__(self):
        return "Point({}, {}, {})".format(self.x, self.y, self.z)

    def pack(self):
        return struct.pack(">iii", self.x, self.y, self.z)

    @staticmethod
    def unpack(data):
        return Point(*struct.unpack(">iii", data))

# Pack
obj = Point(1,2,3)
data = umsgpack.packb(obj, ext_handlers = {Point: lambda obj: umsgpack.Ext(0x10, obj.pack())})

# Unpack
obj = umsgpack.unpackb(data, ext_handlers = {0x10: lambda ext: Point.unpack(ext.data)})
print(obj) # -> Point(1, 2, 3)

Ext Serializable

The ext_serializable() decorator registers application classes for automatic packing and unpacking with the specified Ext type. The decorator accepts the Ext type code as an argument. The application class should implement a packb() method that returns serialized bytes, and an unpackb() class method or static method that accepts serialized bytes and returns an instance of the application class.

Example for registering, packing, and unpacking a custom class with Ext type code 0x10:

@umsgpack.ext_serializable(0x10)
class Point(object):
    def __init__(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z

    def __str__(self):
        return "Point({}, {}, {})".format(self.x, self.y, self.z)

    def packb(self):
        return struct.pack(">iii", self.x, self.y, self.z)

    @staticmethod
    def unpackb(data):
        return Point(*struct.unpack(">iii", data))

# Pack
obj = Point(1,2,3)
data = umsgpack.packb(obj)

# Unpack
obj = umsgpack.unpackb(data)
print(obj) # -> Point(1, 2, 3)