Module adcp.server.builder
Decorator-based server builder for ADCP.
An alternative to the class-based ADCPHandler for simple agents:
from adcp.server import adcp_server, serve
from adcp.server.responses import capabilities_response, products_response
server = adcp_server("my-seller", version="1.0.0")
@server.get_products
async def get_products(params, context=None):
return products_response(MY_PRODUCTS)
@server.get_adcp_capabilities
async def capabilities(params, context=None):
return capabilities_response(["media_buy"])
if __name__ == "__main__":
serve(server, name="my-seller")
Functions
def adcp_server(name: str, **kwargs: Any) ‑> ADCPServerBuilder-
Expand source code
def adcp_server(name: str, **kwargs: Any) -> ADCPServerBuilder: """Create a decorator-based ADCP server builder. Args: name: Server name. **kwargs: Additional configuration (e.g., version="1.0.0"). Returns: An ADCPServerBuilder instance. """ return ADCPServerBuilder(name, **kwargs)Create a decorator-based ADCP server builder.
Args
name- Server name.
**kwargs- Additional configuration (e.g., version="1.0.0").
Returns
An ADCPServerBuilder instance.
Classes
class ADCPServerBuilder (name: str, *, version: str = '1.0.0')-
Expand source code
class ADCPServerBuilder: """Declarative server builder using decorators. Use ``adcp_server()`` to create an instance, then register handlers with decorators. The builder can be passed directly to ``serve()``. Example:: server = adcp_server("my-seller") @server.get_products async def get_products(params, context=None): return products_response(MY_PRODUCTS) serve(server, name="my-seller") """ def __init__(self, name: str, *, version: str = "1.0.0") -> None: self.name = name self.version = version self._handlers: dict[str, Callable[..., Any]] = {} def __getattr__(self, task_name: str) -> Callable[..., Any]: """Return a decorator that registers a handler for the given task.""" if task_name.startswith("_"): raise AttributeError(task_name) def decorator(fn: Callable[..., Any]) -> Callable[..., Any]: if ( task_name not in HANDLER_TO_DOMAIN and task_name != "get_adcp_capabilities" ): raise ValueError( f"'{task_name}' is not a known ADCP task. " f"Check for typos." ) self._handlers[task_name] = fn return fn return decorator def _detect_domains(self) -> list[str]: """Detect which ADCP domains the registered handlers cover.""" domains: set[str] = set() for handler_name in self._handlers: domain = HANDLER_TO_DOMAIN.get(handler_name) if domain: domains.add(domain) return sorted(domains) def build_handler(self) -> ADCPHandler: """Build an ADCPHandler from registered decorators. If ``get_adcp_capabilities`` is not registered, it will be auto-generated from the detected domains. """ handlers = dict(self._handlers) # Auto-generate capabilities if not provided if "get_adcp_capabilities" not in handlers: domains = self._detect_domains() if domains: from adcp.server.responses import capabilities_response async def auto_capabilities( params: Any, context: Any = None ) -> dict[str, Any]: return capabilities_response(domains) handlers["get_adcp_capabilities"] = auto_capabilities # Create a dynamic subclass class DynamicHandler(ADCPHandler): pass for task_name, fn in handlers.items(): # Wrap standalone functions to accept self async def _bound_method( self: Any, params: Any, context: Any = None, _fn: Callable[..., Any] = fn, ) -> Any: return await _fn(params, context) setattr(DynamicHandler, task_name, _bound_method) return DynamicHandler()Declarative server builder using decorators.
Use
adcp_server()to create an instance, then register handlers with decorators. The builder can be passed directly toserve().Example::
server = adcp_server("my-seller") @server.get_products async def get_products(params, context=None): return products_response(MY_PRODUCTS) serve(server, name="my-seller")Methods
def build_handler(self) ‑> ADCPHandler-
Expand source code
def build_handler(self) -> ADCPHandler: """Build an ADCPHandler from registered decorators. If ``get_adcp_capabilities`` is not registered, it will be auto-generated from the detected domains. """ handlers = dict(self._handlers) # Auto-generate capabilities if not provided if "get_adcp_capabilities" not in handlers: domains = self._detect_domains() if domains: from adcp.server.responses import capabilities_response async def auto_capabilities( params: Any, context: Any = None ) -> dict[str, Any]: return capabilities_response(domains) handlers["get_adcp_capabilities"] = auto_capabilities # Create a dynamic subclass class DynamicHandler(ADCPHandler): pass for task_name, fn in handlers.items(): # Wrap standalone functions to accept self async def _bound_method( self: Any, params: Any, context: Any = None, _fn: Callable[..., Any] = fn, ) -> Any: return await _fn(params, context) setattr(DynamicHandler, task_name, _bound_method) return DynamicHandler()Build an ADCPHandler from registered decorators.
If
get_adcp_capabilitiesis not registered, it will be auto-generated from the detected domains.