Major refactor of the message pump architecture: - Replace bus.py with stream_pump.py using aiostream for composable stream processing with natural fan-out via flatmap - Add to_id field to MessageState for explicit routing - Fix routing to use to_id.class format (e.g., "greeter.greeting") - Generate XSD schemas from xmlified payload classes - Fix xmlable imports (absolute -> relative) and parse_element ctx New features: - handlers/hello.py: Sample Greeting/GreetingResponse handler - config/organism.yaml: Sample organism configuration - 41 tests (31 unit + 10 integration) all passing Schema changes: - envelope.xsd: Allow any namespace payloads (##other -> ##any) Dependencies added to pyproject.toml: - aiostream>=0.5 (core dependency) - pyhumps, termcolor (for xmlable) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
35 lines
1.2 KiB
Python
35 lines
1.2 KiB
Python
"""xmlable — vendored and extended for AgentServer v2.1"""
|
|
|
|
from lxml import etree, objectify
|
|
from lxml.etree import _Element
|
|
from lxml.objectify import ObjectifiedElement
|
|
from typing import Type, TypeVar, Any
|
|
from io import BytesIO
|
|
|
|
from ._xmlify import xmlify
|
|
from ._errors import XErrorCtx
|
|
|
|
T = TypeVar("T")
|
|
|
|
def _get_xobject(cls: Type[T]) -> Any:
|
|
if not hasattr(cls, "get_xobject"):
|
|
raise ValueError(f"Class {cls.__name__} is not decorated with @xmlify")
|
|
return cls.get_xobject()
|
|
|
|
def parse_element(cls: Type[T], element: _Element | ObjectifiedElement) -> T:
|
|
"""Direct in-memory deserialization from validated lxml Element."""
|
|
xobject = _get_xobject(cls)
|
|
obj_element = objectify.fromstring(etree.tostring(element))
|
|
# Create a root context for error tracing
|
|
ctx = XErrorCtx(trace=[cls.__name__])
|
|
return xobject.xml_in(obj_element, ctx=ctx)
|
|
|
|
def parse_bytes(cls: Type[T], xml_bytes: bytes) -> T:
|
|
tree = objectify.parse(BytesIO(xml_bytes))
|
|
root = tree.getroot()
|
|
return parse_element(cls, root)
|
|
|
|
def parse_string(cls: Type[T], xml_str: str) -> T:
|
|
return parse_bytes(cls, xml_str.encode("utf-8"))
|
|
|
|
__all__ = ["xmlify", "parse_element", "parse_bytes", "parse_string"]
|