Skip to content

Python

Python binding

Python is the reference implementation for Aster. It provides the full RPC framework, trust model, and iroh networking stack as an async Python library.

Shipping 0.1.2 on PyPI as aster-rpc. The Python binding is the first-class implementation and defines the reference behavior for cross-language interop. All features documented on this site are available in Python.

Terminal window
pip install aster-rpc # framework
pip install aster-cli # optional: shell, contract gen, trust commands

Requirements: Python 3.9 – 3.13, macOS / Linux / Windows.

The package includes a native extension (compiled Rust via PyO3), so wheels are provided for common platforms. Building from source requires a Rust toolchain and maturin.

import asyncio
from dataclasses import dataclass
from aster import AsterServer, AsterClient, service, rpc
@dataclass
class HelloRequest:
name: str = ""
@dataclass
class HelloResponse:
message: str = ""
@service
class HelloService:
@rpc
async def say_hello(self, req: HelloRequest) -> HelloResponse:
return HelloResponse(message=f"Hello, {req.name}!")
async def main():
# Producer
async with AsterServer(services=[HelloService()]) as srv:
addr = srv.address
# Consumer
async with AsterClient(address=addr) as client:
hello = await client.client(HelloService)
resp = await hello.say_hello(HelloRequest(name="World"))
print(resp.message) # "Hello, World!"
asyncio.run(main())

Define services and methods with decorators on plain Python classes:

Decorator Purpose
@service Mark a class as an Aster RPC service.
@rpc Unary RPC method.
@server_stream Server-streaming method (async generator).
@client_stream Client-streaming method.
@bidi_stream Bidirectional streaming method.
@wire_type("ns/Type") Stable wire identity for a dataclass.
API Purpose
AsterServer(services=[...]) High-level declarative producer. Handles admission, hooks, and ALPN routing.
Server(endpoint, services=[...]) Lower-level server. Manual endpoint and connection management.
API Purpose
AsterClient(address="aster1...") High-level declarative consumer. Handles admission and service discovery.
create_client(ServiceClass, connection=conn) Lower-level client. Wraps an existing QUIC connection.
API Purpose
AsterConfig Unified configuration dataclass. Loads from env vars, TOML files, or code.
AsterConfig.from_env() Build config from ASTER_* environment variables.
AsterConfig.from_file("aster.toml") Build config from TOML file with env overrides.
config.print_config() Display resolved config with provenance.
API Purpose
generate_root_keypair() Generate an ed25519 root keypair (offline use).
sign_credential(...) Sign an enrollment credential with the root private key.
ConsumerEnrollmentCredential Dataclass representing a signed enrollment token.

Built-in middleware chain:

Interceptor Purpose
DeadlineInterceptor Enforce and propagate call deadlines.
AuthInterceptor Token-based authentication.
RetryInterceptor Automatic retry for idempotent methods.
CircuitBreakerInterceptor Circuit breaker pattern for failing endpoints.
AuditLogInterceptor Log all RPC calls for audit.
MetricsInterceptor Collect call latency and error metrics.
CapabilityInterceptor Enforce requires capability checks.
API Purpose
@service(scoped="session") Producer-side: per-connection service instances (the class __init__ receives a peer argument).
await client.session("ServiceName") Consumer-side: open a multiplexed session against a session-scoped service. Returns a SessionProxyClient whose method calls share one bidi stream.

The Python binding is structured as a four-layer stack:

Python (aster package) Pure Python: decorators, server, client,
codec, interceptors, trust, sessions
|
| PyO3
v
Rust bindings (PyO3) Thin wrappers exposing async methods
as Python awaitables
|
v
core crate (Rust) Authoritative backend: all transport
logic, QUIC endpoint management
|
v
iroh crates iroh, iroh-blobs, iroh-docs, iroh-gossip

The PyO3 module starts a single shared Tokio runtime. All async Rust functions are bridged to Python awaitables via pyo3-async-runtimes. The Python layer uses asyncio for all async operations.

Tests use pytest with pytest-asyncio (auto mode):

Terminal window
pip install pytest pytest-asyncio pytest-timeout
pytest tests/python/ -v --timeout=30

The conftest.py provides fixtures for common setups: node, node_pair, endpoint_pair.