Skip to main content

readie

readie is the Python client for Readie, a service that runs Python functions in gVisor sandboxes restored from checkpoints. Decorate a function with @remote, and calls to it run on a Readie worker instead of in your process.

pip install readie

The client requires Python 3.12. See Python version.

For guides, concepts, and the SDK reference, see the documentation at readie.org.

Quick example

from readie import remote
import asyncio


@remote
def add(a, b):
    return a + b


print(add(1, 2))  # blocking


async def add_async(a, b):
    return await add.aio(a, b)


print(asyncio.run(add_async(1, 2)))  # from an event loop

The client serializes the decorated function with cloudpickle, and a Python interpreter inside a gVisor sandbox runs it. The function must therefore be picklable, and its imports must exist in the worker's image or be declared with packages (see Packages).

Python version

The client and the sandbox must run the same Python minor version, because a pickled function is portable only within one minor version. The sandbox runs Python 3.12, so readie.Client() raises IncompatiblePythonError unless the local interpreter is Python 3.12.

Authentication

If the service requires a bearer token, set the READIE_AUTH_TOKEN environment variable before creating the client. If the variable is unset, the client sends no token.

Resource budgets

Declare how much memory a function needs on the decorator. Each budget takes a byte count or a size string such as "512Mi" or "4Gi". An unset budget falls back to the cluster default.

@remote(gpu=True, memory="2Gi", max_memory="8Gi")
def train(rows): ...

memory is the container's initial limit, and max_memory is the ceiling that the worker can expand to when the function needs more. gpu_memory and max_gpu_memory set the same limits for GPU device memory. gpu=True sends the call to a GPU worker, and a gpu_memory budget implies it.

The client also extracts the function's imports statically and forwards them, so that the router can pick a checkpoint that already imported them. This is automatic and needs no configuration.

Packages

Declare the PyPI requirements that a function needs beyond what the checkpoint's root filesystem already contains. The executor installs them with uv before every call:

@remote(packages=["numpy==1.26.0", "requests"])
def fetch(url): ...

Each entry is a requirement string, either a bare name or a full spec such as "numpy==1.26.0". The client normalizes the entries and removes duplicates by distribution name when the function is decorated, so "Requests" and "requests" collapse to one entry.

Installation is unconditional. It runs on every call, even when the package appears to be present, because each call restores a fresh, isolated container and there is nothing to verify the claim against.

Client options

The module-level client is created on first use. To change its options, call readie.configure before the first remote call:

import readie

readie.configure(timeout=120.0, chunk_size=64 * 1024, stream_logs=True)
Option Description
timeout Deadline for a whole call, in seconds. The default is no deadline.
chunk_size Payload bytes per stream message. The default is 1 MiB.
stream_logs If true, print the function's output as it arrives instead of only on failure. The default is true.

When a remote function raises

If the remote function raises, the client raises readie.RemoteExecutionError with the traceback from the process that raised:

try:
    train()
except readie.RemoteExecutionError as error:
    print(error.remote_type)  # "ValueError"
    print(error.remote_traceback)  # the frames inside the sandbox
    print(error.worker_id, error.container_id)

The client does not reconstruct the exception object. Unpickling it would require its class to be importable locally, and for a library that exists only in the worker image, the resulting ImportError would replace the real error with a misleading one.

EmptyResultError indicates a different failure: the worker returned nothing at all, which means the executor died before it could report an outcome. A function that returns None returns a value and does not raise EmptyResultError.

Sessions

By default, every call is independent and gets a fresh container. To reuse a warm container and the Python state it holds, open a session:

with readie.default_client().session() as s:
    load_data.bind(s)()  # cold start
    train.bind(s)()  # resumes the same interpreter

The router serializes calls within one session. A session maps to one container that runs one interpreter behind one socket, so its calls cannot run at the same time. Unrelated sessions run in parallel.

client.session() is a convenience wrapper. Session is a plain class that you can construct directly, so the context-manager form is optional:

s = readie.Session()
load_data.bind(s)()
train.bind(s)()
# ... later, possibly in another function
s.close()

A call can run inside a session in three equivalent ways: at decoration time, through a bound copy, or per call.

@remote(session=s)  # every call through this name uses s
def f(): ...


g = train.bind(s)  # a copy of an existing @remote bound to s; the original
# is module-level and shared, so it is left unchanged

readie.default_client().call(train.func, session=s)  # one call, through the client directly

Session also accepts an explicit id, for example Session(session_id="sess-..."). This lets you reconstruct a session in another process, or after the current process restarts, as long as the session's container still exists.

Closing and expiry

Closing a session is a local operation. It stops this client from using the id, and no message reaches the router. The router never removes a session on a timer or a cap of its own. It retires a session id only after the container behind the session is gone, typically because the worker removed the container after its idle timeout.

A session can therefore outlive close(). The following two cases differ:

  • A session_id that the router has never seen, including the id of a new Session(), is not an error. The call cold-starts, exactly like a call with no session.
  • A session_id whose container the router has already reclaimed raises readie.SessionExpiredError. The router raises the error instead of cold-starting under an id that appears to carry warm state. Open a new Session instead of retrying the expired one.

Metadata

Release files for readie 0.3.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for readie 0.3.1
File Size Uploaded Provenance
readie-0.3.1.tar.gz 64.8 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for readie 0.3.1
File Interpreter ABI Platform
readie-0.3.1-py3-none-any.whl Python 3 none any Details

Total release size: 105.4 kB

Release files / readie-0.3.1.tar.gz

Download URL readie-0.3.1.tar.gz
Size 64.8 kB
Tags Source
SHA-256 checksum
How to use checksums
dd22b794a578a53d0b899cef0b506edad3f44c5186f46d66dd189dcc42e5198d
BLAKE2b-256 checksum
How to use checksums
477724de11a82e250e41e1caf44620194281b1f9475d5a898e5646e1f5ac8670
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.22 {"installer":{"name":"uv","version":"0.12.22","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

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 Oct 3, 2026.

Transparency log

Release files / readie-0.3.1-py3-none-any.whl

Download URL readie-0.3.1-py3-none-any.whl
Size 40.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a4a370ff21c756212b804279e21fd47a0c629c30dca689031f4112e0df39effc
BLAKE2b-256 checksum
How to use checksums
0f34ea681b2f2e902ac9c9ab2bb132c67c30094c5f2797ca3c4766cb2e958af4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.22 {"installer":{"name":"uv","version":"0.12.22","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

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 Oct 3, 2026.

Transparency log

Security for readie 0.3.1

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.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for readie-0.3.1.tar.gz

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 Oct 3, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page