Python
Python is the reference implementation for Aster. It provides the full RPC framework, trust model, and iroh networking stack as an async Python library.
Status
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.
Installation
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.
Quick example
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())
API surface
Decorators
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. |
Server
| 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. |
Client
| 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. |
Configuration
| 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. |
Trust
| 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. |
Interceptors
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. |
Sessions
| 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. |
Architecture
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.
Testing
Tests use pytest with pytest-asyncio (auto mode):
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.
Further reading
- Hello Service -- complete walkthrough of the simplest service
- Define a Service -- decorators, wire types, streaming, sessions
- Dial a Service -- connecting, admission, error handling
- Configuration -- full AsterConfig reference
- CLI Reference -- command-line tools