Skip to main content

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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

boxer_sdk-0.1.0.tar.gz (7.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

boxer_sdk-0.1.0-py3-none-any.whl (7.1 kB view details)

Uploaded Python 3

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

Hashes for boxer_sdk-0.1.0.tar.gz
Algorithm Hash digest
SHA256 7da916720d77782e5955c2f1d31171d6dd1096c93a0baec0ecc1a7d6d69549f7
MD5 7f54537ed85e8071d910f33587dcb60e
BLAKE2b-256 51a00a81321f23c64704e54b6c722ac6bc36781fba20a99030877f256c94b9e1

See more details on using hashes here.

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

Hashes for boxer_sdk-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d07c50f6a7172a31d1bbd64dcd699ad6bf3f940cc6fd54e97e2caab3033468fc
MD5 c73510de1dd4e6031c944d4a3c3d4111
BLAKE2b-256 eab3a4d7b08dde6228647da63f602577e2d9ba06cd24b5344551b5385b1001d8

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page