Source code for testplan.common.serialization.base

import warnings
from abc import ABC, abstractmethod
from typing import Any, Dict, Iterable

import dill

try:
    from typing import Self
except ImportError:
    from typing_extensions import Self

FIFTY_MEGA = 52428800


[docs]class SerializationError(Exception): """general serialization error"""
[docs]class DeserializationError(Exception): """general deserialization error"""
[docs]def serialize(obj: Any) -> bytes: try: data = dill.dumps(obj) if len(data) > FIFTY_MEGA: warnings.warn( f"Too big object {obj} of type {type(obj)} after serialization." ) return data except TypeError as exc: raise SerializationError( f"{str(exc).capitalize()}, unexpected type within {obj} of type {type(obj)}." ) except dill.PickleError as exc: raise SerializationError( f"Failed to serialize {obj} of type {type(obj)}." ) from exc
[docs]def deserialize(data: bytes) -> Any: try: return dill.loads(data) except EOFError: raise DeserializationError("No data input for deserialization.") except TypeError as exc: raise DeserializationError(f"{str(exc).capitalize()}.") except dill.PickleError as exc: raise DeserializationError(f"Failed to deserialize {data}.") from exc
[docs]class SelectiveSerializable(ABC): @property @abstractmethod def serializable_attrs(self) -> Iterable[str]: """Attributes to be included in serialization."""
[docs] def dumps(self) -> bytes: """serialize""" data = {} for attr in self.serializable_attrs: data[attr] = getattr(self, attr) return serialize(data)
[docs] def loads(self, obj: bytes) -> Self: """deserialize""" data: Dict[str, Any] = deserialize(obj) for attr, value in data.items(): setattr(self, attr, value) return self