Skip to content

Serialization Package

paglets.serialization provides dataclass wire conversion and qualified-name resolution.

Responsibilities

  • Convert dataclass instances to JSON-compatible wire dictionaries.
  • Reconstruct dataclass instances from wire dictionaries.
  • Resolve importable classes and objects by qualified name.
  • Preserve binary values through JSON-safe tagged values where needed.

Main Modules

paglets.serialization.codec
Implements qualified_name, resolve_qualified_name, dataclass_to_wire, and dataclass_from_wire.

Implementation Notes

The runtime requires importable class names for paglet classes, state classes, service payload classes, and discovered agent classes. This is why paglet classes cannot be defined in transient modules such as __main__.

Host-to-host movement uses pickle transport for full state payloads, but JSON inspection and service messages use dataclass wire conversion.

API Reference

paglets.serialization.codec

dataclass_from_wire(cls: type, payload: WirePayload) -> Any

Restore a dataclass instance from a wire dict.

Source code in src/paglets/serialization/codec.py
def dataclass_from_wire(cls: type, payload: WirePayload) -> Any:
    """Restore a dataclass instance from a wire dict."""

    if not is_dataclass(cls) or not isinstance(cls, type):
        raise SerializationError(f"{cls!r} is not a dataclass class")
    if not isinstance(payload, dict):
        raise SerializationError(f"Expected dict payload for {cls!r}, got {type(payload)!r}")

    type_hints = get_type_hints(cls)
    kwargs: dict[str, Any] = {}
    for field in fields(cls):
        if field.name in payload:
            field_type = type_hints.get(field.name, field.type)
            kwargs[field.name] = _from_wire_value(field_type, payload[field.name])
    try:
        return cls(**kwargs)
    except TypeError as exc:
        raise SerializationError(f"Could not construct {cls!r} from {payload!r}") from exc

dataclass_to_wire(instance: Any) -> WirePayload

Serialize a dataclass instance to explicit movement/control values.

This is intentionally one approach: paglet state is explicit dataclass state. Runtime fields on the paglet object itself are transient and never move.

Source code in src/paglets/serialization/codec.py
def dataclass_to_wire(instance: Any) -> WirePayload:
    """Serialize a dataclass instance to explicit movement/control values.

    This is intentionally one approach: paglet state is explicit dataclass state.
    Runtime fields on the paglet object itself are transient and never move.
    """

    if not is_dataclass(instance) or isinstance(instance, type):
        raise SerializationError("Paglet state must be a dataclass instance")
    return {field.name: _to_wire_value(getattr(instance, field.name)) for field in fields(instance)}

qualified_name(obj: type | object) -> str

Return an importable module:qualname for a class or object.

Source code in src/paglets/serialization/codec.py
def qualified_name(obj: type | object) -> str:
    """Return an importable ``module:qualname`` for a class or object."""

    cls = obj if isinstance(obj, type) else obj.__class__
    module = getattr(cls, "__module__", None)
    qualname = getattr(cls, "__qualname__", None)
    if not module or not qualname:
        raise SerializationError(f"Cannot qualify {obj!r}")
    if "<locals>" in qualname:
        raise SerializationError(f"{module}:{qualname} is local and cannot be imported on another host")
    return f"{module}:{qualname}"

resolve_qualified_name(name: str) -> Any

Resolve a module:qualname produced by :func:qualified_name.

Source code in src/paglets/serialization/codec.py
def resolve_qualified_name(name: str) -> Any:
    """Resolve a ``module:qualname`` produced by :func:`qualified_name`."""

    if ":" not in name:
        raise SerializationError(f"Expected module:qualname, got {name!r}")
    module_name, qualname = name.split(":", 1)
    try:
        module = importlib.import_module(module_name)
    except Exception as exc:  # pragma: no cover - exact import errors vary
        raise SerializationError(f"Cannot import module {module_name!r}") from exc
    obj: Any = module
    try:
        for part in qualname.split("."):
            obj = getattr(obj, part)
    except AttributeError as exc:
        raise SerializationError(f"Cannot resolve {name!r}") from exc
    return obj
  • Core covers state requirements.
  • Remote covers transport payload paths.