lodum.msgpack
1# SPDX-FileCopyrightText: 2025-present Michael R. Bernstein <zopemaven@gmail.com> 2# 3# SPDX-License-Identifier: Apache-2.0 4try: 5 import msgpack # type: ignore[import-untyped] 6except ImportError: 7 msgpack = None # type: ignore 8from typing import Any, Iterator, Type, TypeVar 9 10from .core import Loader, BaseDumper, BaseLoader 11from .exception import DeserializationError 12from .internal import dump, load, DEFAULT_MAX_SIZE 13 14T = TypeVar("T") 15 16# --- Public API --- 17 18 19def dumps(obj: Any) -> bytes: 20 """ 21 Encodes a Python object to MsgPack bytes. 22 23 Args: 24 obj: The object to encode. Must be lodum-enabled or a supported type. 25 26 Returns: 27 The MsgPack-encoded bytes. 28 29 Raises: 30 ImportError: If msgpack is not installed. 31 """ 32 if msgpack is None: 33 raise ImportError( 34 "msgpack is required for MsgPack serialization. Install it with 'pip install lodum[msgpack]'." 35 ) 36 dumper = MsgPackDumper() 37 dumped_data = dump(obj, dumper) 38 return msgpack.packb(dumped_data, use_bin_type=True) 39 40 41def loads(cls: Type[T], packed_bytes: bytes, max_size: int = DEFAULT_MAX_SIZE) -> T: 42 """ 43 Decodes MsgPack bytes into a Python object of the specified type. 44 45 Args: 46 cls: The class to instantiate. 47 packed_bytes: The MsgPack data to decode. 48 max_size: Maximum allowed size of the input bytes. 49 50 Returns: 51 An instance of cls populated with the decoded data. 52 53 Raises: 54 DeserializationError: If the input is invalid or exceeds max_size. 55 ImportError: If msgpack is not installed. 56 """ 57 if len(packed_bytes) > max_size: 58 raise DeserializationError( 59 f"Input size ({len(packed_bytes)}) exceeds maximum allowed ({max_size})" 60 ) 61 62 if msgpack is None: 63 raise ImportError( 64 "msgpack is required for MsgPack deserialization. Install it with 'pip install lodum[msgpack]'." 65 ) 66 try: 67 data = msgpack.unpackb(packed_bytes, raw=False) 68 except Exception as e: 69 raise DeserializationError(f"Failed to parse MsgPack: {e}") 70 loader = MsgPackLoader(data) 71 return load(cls, loader) 72 73 74# --- MsgPack Dumper Implementation --- 75 76 77class MsgPackDumper(BaseDumper): 78 pass 79 80 81# --- MsgPack Loader Implementation --- 82 83 84class MsgPackLoader(BaseLoader): 85 def load_list(self) -> Iterator["Loader"]: 86 if not isinstance(self._data, list): 87 raise DeserializationError( 88 f"Expected list, got {type(self._data).__name__}" 89 ) 90 return (MsgPackLoader(item) for item in self._data) 91 92 def load_dict(self) -> Iterator[tuple[str, "Loader"]]: 93 if not isinstance(self._data, dict): 94 raise DeserializationError( 95 f"Expected dict, got {type(self._data).__name__}" 96 ) 97 return ((k, MsgPackLoader(v)) for k, v in self._data.items()) 98 99 def load_bytes_value(self, value: Any) -> bytes: 100 if not isinstance(value, bytes): 101 raise DeserializationError(f"Expected bytes, got {type(value).__name__}") 102 return value
def
dumps(obj: Any) -> bytes:
20def dumps(obj: Any) -> bytes: 21 """ 22 Encodes a Python object to MsgPack bytes. 23 24 Args: 25 obj: The object to encode. Must be lodum-enabled or a supported type. 26 27 Returns: 28 The MsgPack-encoded bytes. 29 30 Raises: 31 ImportError: If msgpack is not installed. 32 """ 33 if msgpack is None: 34 raise ImportError( 35 "msgpack is required for MsgPack serialization. Install it with 'pip install lodum[msgpack]'." 36 ) 37 dumper = MsgPackDumper() 38 dumped_data = dump(obj, dumper) 39 return msgpack.packb(dumped_data, use_bin_type=True)
Encodes a Python object to MsgPack bytes.
Args: obj: The object to encode. Must be lodum-enabled or a supported type.
Returns: The MsgPack-encoded bytes.
Raises: ImportError: If msgpack is not installed.
def
loads(cls: Type[~T], packed_bytes: bytes, max_size: int = 10485760) -> ~T:
42def loads(cls: Type[T], packed_bytes: bytes, max_size: int = DEFAULT_MAX_SIZE) -> T: 43 """ 44 Decodes MsgPack bytes into a Python object of the specified type. 45 46 Args: 47 cls: The class to instantiate. 48 packed_bytes: The MsgPack data to decode. 49 max_size: Maximum allowed size of the input bytes. 50 51 Returns: 52 An instance of cls populated with the decoded data. 53 54 Raises: 55 DeserializationError: If the input is invalid or exceeds max_size. 56 ImportError: If msgpack is not installed. 57 """ 58 if len(packed_bytes) > max_size: 59 raise DeserializationError( 60 f"Input size ({len(packed_bytes)}) exceeds maximum allowed ({max_size})" 61 ) 62 63 if msgpack is None: 64 raise ImportError( 65 "msgpack is required for MsgPack deserialization. Install it with 'pip install lodum[msgpack]'." 66 ) 67 try: 68 data = msgpack.unpackb(packed_bytes, raw=False) 69 except Exception as e: 70 raise DeserializationError(f"Failed to parse MsgPack: {e}") 71 loader = MsgPackLoader(data) 72 return load(cls, loader)
Decodes MsgPack bytes into a Python object of the specified type.
Args: cls: The class to instantiate. packed_bytes: The MsgPack data to decode. max_size: Maximum allowed size of the input bytes.
Returns: An instance of cls populated with the decoded data.
Raises: DeserializationError: If the input is invalid or exceeds max_size. ImportError: If msgpack is not installed.
class
MsgPackDumper(lodum.core.BaseDumper):
Base implementation of the Dumper protocol to reduce duplication.
class
MsgPackLoader(lodum.core.BaseLoader):
85class MsgPackLoader(BaseLoader): 86 def load_list(self) -> Iterator["Loader"]: 87 if not isinstance(self._data, list): 88 raise DeserializationError( 89 f"Expected list, got {type(self._data).__name__}" 90 ) 91 return (MsgPackLoader(item) for item in self._data) 92 93 def load_dict(self) -> Iterator[tuple[str, "Loader"]]: 94 if not isinstance(self._data, dict): 95 raise DeserializationError( 96 f"Expected dict, got {type(self._data).__name__}" 97 ) 98 return ((k, MsgPackLoader(v)) for k, v in self._data.items()) 99 100 def load_bytes_value(self, value: Any) -> bytes: 101 if not isinstance(value, bytes): 102 raise DeserializationError(f"Expected bytes, got {type(value).__name__}") 103 return value
Base implementation of the Loader protocol to reduce duplication.