Python SDK for the Boxer sandboxed container execution service
Project description
boxer-sdk
Python client SDK for Boxer - a sandboxed container execution service backed by gVisor.
Installation
pip install boxer-sdk
Requires Python 3.9+ and a running Boxer server.
Quick start
from boxer import BoxerClient
with BoxerClient("http://localhost:8080") as client:
result = client.run(
image="python:3.12-slim",
cmd=["python3", "-c", "print('hello world')"],
)
print(result.stdout) # hello world
print(result.exit_code) # 0
print(result.wall_ms) # e.g. 312
Hello world in Python, Node.js, and Perl
Python
result = client.run(
image="python:3.12-slim",
cmd=["python3", "-c", "print('hello world')"],
)
print(result.stdout) # hello world
Node.js
result = client.run(
image="node:20-slim",
cmd=["node", "-e", "console.log('hello world')"],
)
print(result.stdout) # hello world
Perl
result = client.run(
image="perl:5.38-slim",
cmd=["perl", "-e", "print 'hello world\n'"],
)
print(result.stdout) # hello world
Working with files
Upload a script and run it
Upload a file to the Boxer file store, then reference it by path in run.
The file is bind-mounted read-only at /<remote_path> inside the container.
# Python
with open("script.py", "rb") as f:
client.upload_file("script.py", f)
result = client.run(
image="python:3.12-slim",
cmd=["python3", "/script.py"],
files=["script.py"],
)
# Node.js
with open("app.js", "rb") as f:
client.upload_file("app.js", f)
result = client.run(
image="node:20-slim",
cmd=["node", "/app.js"],
files=["app.js"],
)
# Perl
with open("hello.pl", "rb") as f:
client.upload_file("hello.pl", f)
result = client.run(
image="perl:5.38-slim",
cmd=["perl", "/hello.pl"],
files=["hello.pl"],
)
Download output files from the container
Any file the container writes to /output/ is automatically captured and
retrievable via download_file after the run completes.
# Script that writes a file to /output/
code = """
import os, json
os.makedirs('/output', exist_ok=True)
with open('/output/result.json', 'w') as f:
json.dump({'message': 'hello world', 'value': 42}, f)
"""
with open("compute.py", "rb") as f:
client.upload_file("compute.py", f)
result = client.run(
image="python:3.12-slim",
cmd=["python3", "/compute.py"],
files=["compute.py"],
)
# Download the file the container wrote
data = client.download_file(f"output/{result.exec_id}/result.json")
print(data) # b'{"message": "hello world", "value": 42}'
The output path pattern is always output/<exec_id>/<filename>.
Resource limits
from boxer import ResourceLimits
limits = ResourceLimits(
cpu_cores=0.5,
memory_mb=128,
wall_clock_secs=10,
)
result = client.run(
image="python:3.12-slim",
cmd=["python3", "-c", "print('done')"],
limits=limits,
)
Async client
Every method on BoxerClient has an await-able equivalent on AsyncBoxerClient:
import asyncio
from boxer import AsyncBoxerClient
async def main():
async with AsyncBoxerClient("http://localhost:8080") as client:
result = await client.run(
image="python:3.12-slim",
cmd=["python3", "-c", "print('hello world')"],
)
print(result.stdout)
asyncio.run(main())
Error handling
from boxer import BoxerAPIError, BoxerTimeoutError, BoxerOutputLimitError
try:
result = client.run(
image="python:3.12-slim",
cmd=["python3", "-c", "while True: pass"],
limits=ResourceLimits(wall_clock_secs=5),
)
except BoxerTimeoutError:
print("execution timed out")
except BoxerOutputLimitError:
print("output exceeded size limit")
except BoxerAPIError as e:
print(f"API error {e.status_code}: {e}")
Running tests
Tests require a live Boxer server:
pip install -e ".[dev]"
BOXER_URL=http://localhost:8080 pytest tests/ -v
Without BOXER_URL all tests are skipped automatically.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file boxer_sdk-0.1.0.tar.gz.
File metadata
- Download URL: boxer_sdk-0.1.0.tar.gz
- Upload date:
- Size: 7.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.16 {"installer":{"name":"uv","version":"0.9.16","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":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7da916720d77782e5955c2f1d31171d6dd1096c93a0baec0ecc1a7d6d69549f7
|
|
| MD5 |
7f54537ed85e8071d910f33587dcb60e
|
|
| BLAKE2b-256 |
51a00a81321f23c64704e54b6c722ac6bc36781fba20a99030877f256c94b9e1
|
File details
Details for the file boxer_sdk-0.1.0-py3-none-any.whl.
File metadata
- Download URL: boxer_sdk-0.1.0-py3-none-any.whl
- Upload date:
- Size: 7.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.16 {"installer":{"name":"uv","version":"0.9.16","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":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d07c50f6a7172a31d1bbd64dcd699ad6bf3f940cc6fd54e97e2caab3033468fc
|
|
| MD5 |
c73510de1dd4e6031c944d4a3c3d4111
|
|
| BLAKE2b-256 |
eab3a4d7b08dde6228647da63f602577e2d9ba06cd24b5344551b5385b1001d8
|