GeezerVisonThe World Wide Web, restored to 800 pixels of glory. |
| Home|About|Gaming cabinet|Archives|How it works|Starter sites |
GeezerVison is showing msgspec.dev — Extending Extending¶To allow encoding/decoding types other than those natively supported,
These should have the following signatures: def enc_hook(obj: Any) -> Any: """Given an object that msgspec doesn't know how to serialize by default, convert it into an object that it does know how to serialize""" pass def dec_hook(type: Type, obj: Any) -> Any: """Given a type in a schema, convert ``obj`` (composed of natively supported objects) into an object of type ``type``. Any `TypeError` or `ValueError` exceptions raised by this method will be considered "user facing" and converted into a `ValidationError` with additional context. All other exceptions will be raised directly. """ pass def ext_hook(code: int, data: memoryview) -> Any: """MessagePack only. Given an extension type code and data buffer, deserialize whatever custom object the extension type represents""" pass These can be composed together to form complex behaviors as needed. However, most use cases follow one of these patterns:
Both methods are illustrated below. Mapping to/from native types¶This method uses messages composed only of natively supported types. During encoding, custom types are mapped to natively supported types, which are then serialized. This process is then reversed during decoding. custom type -> native types -> encoded message -> native types -> custom type This means that typed decoding is required to roundtrip a message, since no custom type info is sent as part of the message. This method works best for types that are similar to a natively supported type
(e.g. a
Here we define import msgspec from typing import Any, Type def enc_hook(obj: Any) -> Any: if isinstance(obj, complex): # convert the complex to a tuple of real, imag return (obj.real, obj.imag) else: # Raise a NotImplementedError for other types raise NotImplementedError(f"Objects of type {type(obj)} are not supported") def dec_hook(type: Type, obj: Any) -> Any: # `type` here is the value of the custom type annotation being decoded. if type is complex: # Convert ``obj`` (which should be a ``tuple``) to a complex real, imag = obj return complex(real, imag) else: # Raise a NotImplementedError for other types raise NotImplementedError(f"Objects of type {type} are not supported") # Define a message that contains a complex type class MyMessage(msgspec.Struct): field_1: str field_2: complex # Create an encoder and a decoder using the custom callbacks. # Note that typed deserialization is required for successful # roundtripping here, so we pass `MyMessage` to `Decoder`. enc = msgspec.json.Encoder(enc_hook=enc_hook) dec = msgspec.json.Decoder(MyMessage, dec_hook=dec_hook) # An example message msg = MyMessage("some string", complex(1, 2)) # Encode and decode the message to show that things work buf = enc.encode(msg) msg2 = dec.decode(buf) assert msg == msg2 # True Defining a custom extension (MessagePack only)¶The MessagePack specification provides support for defining custom Extensions. Extensions consist of:
By default extensions are serialized to/from >>> ext = msgspec.msgpack.Ext(1, b"some data") # an extension object, with type code 1 >>> msg = msgspec.msgpack.encode(ext) >>> ext2 = msgspec.msgpack.decode(msg) >>> ext == ext2 # deserializes as an Ext object True While manually creating
This method defines a new extension type, and sends this type information
along as part of the message. This means that when properly configured, custom
types can be deserialized even when using untyped deserialization. However, if
you’re communicating with MessagePack libraries other than For example, perhaps you wanted to serialize +---------+---------+ | real | imag | +---------+---------+ 8 bytes 8 bytes Here we define import msgspec import struct from typing import Any # All extension types need a unique integer designator so the decoder knows # which type they're decoding. Here we arbitrarily choose 1, but any integer # between 0 and 127 (inclusive) would work. COMPLEX_TYPE_CODE = 1 def enc_hook(obj: Any) -> Any: if isinstance(obj, complex): # encode the complex number into a 16 byte buffer data = struct.pack('dd', obj.real, obj.imag) # Return an `Ext` object so msgspec serializes it as an extension type. return msgspec.msgpack.Ext(COMPLEX_TYPE_CODE, data) else: # Raise a NotImplementedError for other types raise NotImplementedError(f"Objects of type {type(obj)} are not supported") def ext_hook(code: int, data: memoryview) -> Any: if code == COMPLEX_TYPE_CODE: # This extension type represents a complex number, decode the data # buffer accordingly. real, imag = struct.unpack('dd', data) return complex(real, imag) else: # Raise a NotImplementedError for other extension type codes raise NotImplementedError(f"Extension type code {code} is not supported") # Create an encoder and a decoder using the custom callbacks enc = msgspec.msgpack.Encoder(enc_hook=enc_hook) dec = msgspec.msgpack.Decoder(ext_hook=ext_hook) # Define a message that contains complex numbers msg = {"roots": [0, 0.75, 1 + 0.5j, 1 - 0.5j]} # Encode and decode the message to show that things work buf = enc.encode(msg) msg2 = dec.decode(buf) assert msg == msg2 # True Note Note that the |
| You are visitor 01402503 — GeezerVison does not store the pages you look up. Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required. |