Python API¶
The isola package exposes an async API for compiling sandbox templates and running code inside isolated runtimes.
Install¶
Runtime Resolution¶
Use resolve_runtime(runtime, *, version=None) to fetch the runtime bundle config directly:
When runtime_path is omitted from SandboxManager.compile_template(...), the SDK resolves the runtime automatically, downloads the matching release asset on first use, verifies its digest, and caches it under ~/.cache/isola/runtimes/.
Supported runtime names:
"python""js"
Lifecycle¶
The normal flow is:
- Create a
SandboxManager await manager.compile_template(...)await template.create(...)async with sandbox: ...await sandbox.load_script(...)await sandbox.run(...)or iteratesandbox.run_stream(...)
import asyncio
from isola import SandboxManager
async def main() -> None:
async with SandboxManager() as manager:
template = await manager.compile_template("python")
sandbox = await template.create()
async with sandbox:
await sandbox.load_script("def hello(name):\n return f'hello {name}'")
result = await sandbox.run("hello", ["world"])
print(result)
asyncio.run(main())
Core Types¶
SandboxManager¶
Creates reusable sandbox templates.
manager = SandboxManager()
template = await manager.compile_template(runtime, *, version=None, **template_config)
manager.close()
compile_template(...) accepts:
runtime:"python"or"js"version: optional release tag to resolve when auto-downloading a runtimeruntime_path: directory or path used to initialize the runtime bundleruntime_lib_dir: runtime library directory, required for Python runtimes that are provided manuallycache_dir: template cache directorymax_memory: template memory limit in bytesprelude: code injected before user scriptsmounts:list[MountConfig]env:dict[str, str]
SandboxManager supports both sync and async context-manager cleanup.
SandboxTemplate¶
Instantiates sandboxes from a compiled template.
create(...) accepts:
max_memory: per-sandbox memory limit in bytesmounts:list[MountConfig]env:dict[str, str]hostcalls:dict[str, async callable]used for guestsandbox.asyncio.hostcall(...)http_handler: async callable used for outbound guest HTTP requests
Sandbox¶
Runs guest code inside an instantiated sandbox.
Public methods:
await load_script(code)await run(name, args=None) -> JsonValue | Nonerun_stream(name, args=None) -> AsyncIterator[Event]close()await aclose()
Use async with sandbox: before executing code. Entering the async context starts the sandbox.
Arguments and Streaming¶
run(...) and run_stream(...) accept positional JSON values directly:
Use Arg(value, name="...") to pass a named argument:
Use StreamArg for JSON streams passed into guest code:
from isola import StreamArg
stream = StreamArg.from_iterable([1, 2, 3])
result = await sandbox.run("consume", [stream])
Available constructors:
StreamArg.from_iterable(values, *, name=None, capacity=1024)StreamArg.from_async_iterable(values, *, name=None, capacity=1024)
Hostcalls¶
Guest Python code can call back into the host with sandbox.asyncio.hostcall(...).
from sandbox.asyncio import hostcall
async def lookup_user(payload: dict[str, object]) -> object:
user_id = int(payload["user_id"])
return {"user_id": user_id, "name": f"user-{user_id}"}
sandbox = await template.create(hostcalls={"lookup_user": lookup_user})
await sandbox.load_script(
"from sandbox.asyncio import hostcall\n"
"\n"
"async def lookup_user(user_id):\n"
" return await hostcall('lookup_user', {'user_id': user_id})\n"
)
result = await sandbox.run("lookup_user", [7])
Configure hostcalls and HTTP behavior when the sandbox is created.
Each hostcall handler receives the decoded JSON payload for its registered call name and must return a JSON-serializable value.
Events and Results¶
run(...) returns the final value directly:
run_stream(...) yields typed Event objects for fine-grained control:
async for event in sandbox.run_stream("compute"):
match event:
case ResultEvent(data=value):
print("intermediate:", value)
case EndEvent(data=value):
print("final:", value)
case StdoutEvent(data=line):
print("stdout:", line)
case StderrEvent(data=line):
print("stderr:", line)
case ErrorEvent(data=msg):
print("error:", msg)
case LogEvent(data=msg):
print("log:", msg)
Event is a union of: ResultEvent, EndEvent, StdoutEvent, StderrEvent, ErrorEvent, LogEvent. Each carries a typed data field (JsonValue for result/end, str for the rest).
Filesystem and Environment¶
Use MountConfig to mount host paths into the guest:
from isola import MountConfig
mount = MountConfig(
host="./data",
guest="/workspace",
dir_perms="read",
file_perms="read",
)
dir_perms and file_perms accept:
"read""write""read-write"
Environment variables can be supplied in both template and sandbox config via env={"KEY": "value"}.
HTTP Bridge¶
When guest code makes outbound HTTP requests, the sandbox uses an async Python handler that returns HttpResponse.
from collections.abc import AsyncIterator
from isola import HttpRequest, HttpResponse
async def body() -> AsyncIterator[bytes]:
yield b"hello "
yield b"world"
async def http_handler(request: HttpRequest) -> HttpResponse:
return HttpResponse(
status=200,
headers={"content-type": "text/plain"},
body=body(),
)
Request and response models:
HttpRequest(method, url, headers, body)HttpResponse(status, headers=None, body=None)
HttpResponse.body may be:
bytesAsyncIterable[bytes]None
Errors¶
The package exports these exception types:
IsolaErrorInvalidArgumentErrorInternalErrorStreamFullErrorStreamClosedError