Little Actors for Python
Define durable actors in Python and generate typed Python clients. Python 3.11+ is supported. Actor state, placement, routing, and WebSocket delivery use the same Rust runtime as the TypeScript SDK.
pnpm dlx durable-actors init my-actors --template python
cd my-actors
pnpm install
uv sync
pnpm exec durable-actors dev
The shared TypeScript CLI manages development, generation, and Python type checking. It selects the project's .venv (or the active environment); DURABLE_ACTORS_PYTHON overrides the interpreter. Install Node.js 22+, Python 3.11+, and uv. The CLI downloads the matching native runtime on macOS and Linux. When developing this repository, set DURABLE_ACTORS_BINARY to an absolute path to your cargo build --locked executable.
Define actors
from pydantic import BaseModel
from durable_actors import Actor, emitted, ephemeral
class Message(BaseModel):
text: str
class Chat(Actor):
count: int = 0
messages: list[Message] = emitted(default_factory=list)
busy: bool = ephemeral(False)
def append(self, message: Message) -> list[Message]:
self.messages.append(message)
return self.messages
Public def methods become synchronous RPCs. Annotated fields persist by default. emitted() persists a field and broadcasts its saved changes; ephemeral() keeps a field temporary. Mutable defaults are copied for each actor, and both helpers accept default_factory for values constructed on activation. Use ephemeral(default_factory=...) for locks, caches, and service clients, and ClassVar for class constants. Classes extend Actor directly and use field defaults instead of constructors. Prefix helper methods with _. Synchronous handlers run on a worker thread, with calls serialized per actor. Socket hooks can also use ordinary def; self.get_connections() returns typed sockets.
Add @reentrant (imported from durable_actors) to a def method to let other invocations enter before it finishes. Synchronous reentrant handlers overlap on worker threads; coordinate shared mutations and keep blocking I/O outside shared locks. Ordinary calls still serialize with each other. As in TypeScript, enabling reentrancy disables error rollback for the entire actor class. See the execution semantics for details.
Generate and use a client
With the actor server running, generate clients in your application:
pnpm add -D durable-actors
uv add 'durable-actors[codegen]'
pnpm exec durable-actors generate --out-dir generated
You can also generate directly from a trusted source entrypoint:
pnpm exec durable-actors generate src/actors.py --out-dir generated
from generated import actors
chat = actors.Chat.get("lobby")
messages: actors.Chat.Methods.append.Result = chat.append(actors.Chat.Message(text="hello"))
print(messages[0].text)
The CLI runs strict mypy on local actor definitions before generation and on the generated package afterward. dev checks definitions before startup and every reload; an invalid edit leaves the previous code running.
Generated RPC methods return typed values directly. The SDK creates a shared HTTP client when needed, reads configuration from the environment, and closes its connection pool at process exit. You only need the actor ID.
The generated package exposes actors, matching the TypeScript client namespace. Use actors.Chat.get(id) for a handle, actors.Chat.Stub for its type, and actors.Chat.Methods.append.Args / .Result for method types. Socket types live at actors.Chat.Metadata, .Incoming, .Outgoing, and .State; concrete models such as actors.Chat.Message are also available there. The package includes docstrings, independent Pydantic models, and py.typed. Consumers need only durable-actors, not the actor project or the code generator. Regenerate after changing the actor contract, and include the generated package in your application's type checks.
Typing uses inline annotations and the PEP 561 package marker. Both mypy and Pyright check the SDK and generated clients. Pydantic validates inputs, outputs, and persisted state at runtime. Python annotations remain ordinary annotations: chat.append(42) is rejected by a type checker and by runtime validation.
Subscribe to state
Actors with emitted fields have a typed subscribe method:
chat = actors.Chat.get("lobby")
subscription = chat.subscribe(lambda state: print(state.messages))
chat.append(actors.Chat.Message(text="hello"))
The SDK receives the initial state and applies later patches in the background. Each callback gets a complete typed snapshot of the emitted fields, and RPC calls continue normally. Call subscription.close() when finished. Callbacks run serially on a background thread; the subscription does not keep an otherwise finished process alive.
Pass on_error=handler to handle connection, validation, or callback failures. A failure stops the subscription; its exception is available as subscription.error and is logged if no handler is supplied. Actors with required connection metadata also require metadata=... when subscribing.
See the Python reference for supported types, sockets, reentrancy, deployment, and CLI options.
Resource settings and backend helpers
Use @sandbox(cpu=2, memory_mib=2048, idle_timeout_ms=60_000, regions=["canada"]) above an actor class to override deployment defaults. Import sandbox from durable_actors.
Source classes also support Chat.get("lobby") with typed synchronous methods, including calls from other actors. Generated handles expose broadcast(message); actors.Chat.Authorization, actors.Chat.prepare_websocket(...), and ActorProxy.handle(...) issue typed browser access grants. ActorSessionTransport renews short-lived application credentials. The Python reference covers these APIs and their docstrings.
Metadata
Release files for durable-actors 0.5.5
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| durable_actors-0.5.5.tar.gz | 137.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| durable_actors-0.5.5-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 190.7 kB
Release files / durable_actors-0.5.5.tar.gz
| Download URL | durable_actors-0.5.5.tar.gz |
|---|---|
| Size | 137.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8583ac16027bf975fda5c9a3d33df78d2f0d22e99d35ea4fea095d1bd2d9260d
|
|
BLAKE2b-256 checksum How to use checksums |
85cbf41e9a212256a8adfc34bc053332e32ad0f60e3e943c5880a53886bf733e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 29, 2026.
Transparency logRelease files / durable_actors-0.5.5-py3-none-any.whl
| Download URL | durable_actors-0.5.5-py3-none-any.whl |
|---|---|
| Size | 53.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8a2c6134594c39977765d717ee506495b86cebf135885b1452279d7bdfbc1192
|
|
BLAKE2b-256 checksum How to use checksums |
68c668c77fd39a89bd6e8c818f096f4da0534c1ede4fb67ff6e333af51f24b3f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 29, 2026.
Transparency log