Official Python client for Runbox - a fast, secure API for running code in isolated containers.
pip install runbox-pyfrom runbox_py import Client
# Create a client
client = Client(
url="http://localhost:8080",
api_key="your-api-key"
)
# Step 1: Set up a container and get environment info
setup = client.setup(
identifier="my-session",
language="python"
)
print(setup.container_id) # => "runbox-my-session-python"
print(setup.environment_snapshot.runtime_version) # => "3.11.6"
print(setup.environment_snapshot.packages["requests"]) # => "2.31.0"
# Step 2: Run code in the container
result = client.run(
container_id=setup.container_id,
files=[{"path": "main.py", "content": "print('Hello!')"}],
run_command="python main.py"
)
print(result.stdout) # => "Hello!\n"
print(result.success) # => Trueexport RUNBOX_URL=http://localhost:8080
export RUNBOX_API_KEY=your-api-keyfrom runbox_py import Client
# Will use environment variables
client = Client()client = Client(
url="http://localhost:8080",
api_key="your-api-key",
timeout=120 # HTTP timeout in seconds
)setup = client.setup(
identifier="session-123",
language="python",
env={"API_KEY": "secret"}, # Optional: environment variables
memory="512m", # Optional: memory limit
network_allow=["api.stripe.com"] # Optional: allowed network destinations
)
# Access environment information
print(setup.container_id) # => "runbox-session-123-python"
print(setup.cached) # => False (True if container was reused)
env = setup.environment_snapshot
print(env.os_name) # => "debian"
print(env.os_version) # => "12"
print(env.runtime_name) # => "python"
print(env.runtime_version) # => "3.11.6"
print(env.packages) # => {"pip": "23.0.1", "requests": "2.31.0", ...}result = client.run(
container_id="runbox-session-123-python",
files=[{"path": "main.py", "content": "print('Hello!')"}],
run_command="python main.py",
env={"DEBUG": "true"}, # Optional: runtime environment variables
timeout=30 # Optional: execution timeout in seconds
)
print(result.success) # => True
print(result.exit_code) # => 0
print(result.stdout) # => "Hello!\n"
print(result.stderr) # => ""
print(result.execution_time_ms) # => 42
print(result.timed_out) # => FalseInstall new dependencies before running code:
# Python example
result = client.run(
container_id=container_id,
files=[{"path": "main.py", "content": "import requests; print(requests.__version__)"}],
run_command="python main.py",
new_dependencies=["requests==2.31.0", "pytest"]
)
print(result.packages) # => {"pip": "23.0.1", "requests": "2.31.0", "pytest": "7.4.0", ...}
# Ruby example
result = client.run(
container_id=container_id,
files=[{"path": "main.rb", "content": "require 'rake'; puts Rake::VERSION"}],
run_command="ruby main.rb",
new_dependencies=["rake", "rspec"]
)
# Shell example (uses apk)
result = client.run(
container_id=container_id,
files=[{"path": "script.sh", "content": "#!/bin/sh\ncurl --version"}],
run_command="sh script.sh",
new_dependencies=["curl", "jq", "git"]
)Note: The packages field is only included in the result when new_dependencies are provided.
import asyncio
from runbox_py import AsyncClient
async def main():
async with AsyncClient(url="http://localhost:8080", api_key="your-api-key") as client:
# Setup container
setup = await client.setup(
identifier="session-123",
language="python"
)
# Run code
result = await client.run(
container_id=setup.container_id,
files=[{"path": "main.py", "content": "print('Hello!')"}],
run_command="python main.py"
)
print(result.stdout)
asyncio.run(main())deleted = client.delete_containers("session-123")
print(deleted) # => ["runbox-session-123-python"]health = client.health()
print(health.status) # => "healthy"
print(health.version) # => "1.0.0"Set up a container and get environment information.
Parameters:
identifier(str, required): Unique identifier for container reuselanguage(str, required): Programming language ("python","ruby","shell")env(dict, optional): Environment variables to settimeout(int, optional): Default timeout in secondsmemory(str, optional): Memory limit (e.g.,"256m","1g")network_allow(list[str], optional): Allowed network destinations
Returns: SetupResult with:
container_id: Container ID to use inrun()callscached: Whether container was reusedenvironment_snapshot: Environment information (OS, runtime, packages)
Run code in a container that was set up via setup().
Parameters:
container_id(str, required): Container ID fromsetup()responsefiles(list[dict], required): Files to write before runningrun_command(str, required): Command to runenv(dict, optional): Runtime environment variablestimeout(int, optional): Execution timeout in seconds
Returns: RunResult with:
success: Whether run succeeded (exit code 0)exit_code: Process exit codestdout: Standard outputstderr: Standard errorexecution_time_ms: Execution time in millisecondstimed_out: Whether run timed out
from runbox_py import (
Client,
AuthenticationError,
NotFoundError,
ValidationError,
RunError,
ConnectionError,
)
try:
setup = client.setup(identifier="test", language="python")
result = client.run(
container_id=setup.container_id,
files=[{"path": "main.py", "content": "print('hi')"}],
run_command="python main.py"
)
except AuthenticationError:
print("Invalid API key")
except NotFoundError:
print("Container not found (did you call setup first?)")
except ValidationError as e:
print(f"Invalid request: {e}")
except RunError as e:
print(f"Run failed: {e}")
except ConnectionError as e:
print(f"Could not connect: {e}")python3 -m venv venv
source venv/bin/activate
pip install -e ".[dev]"pytestIntegration tests require a running Runbox server:
# Start Runbox server (in another terminal)
cd ../runbox
docker-compose up
# Run integration tests
export RUNBOX_URL=http://localhost:8080
export RUNBOX_API_KEY=your-api-key
python examples/integration_test.pyruff check .
mypy src-
CI: Runs on every push and PR
- Tests on Python 3.9, 3.10, 3.11, 3.12
- Linting with Ruff
- Type checking with MyPy
- Integration tests against live Runbox server
-
CD: Publishes to PyPI on version tags
- Create a tag:
git tag v1.0.0 && git push --tags - Uses Trusted Publishing
- Create a tag:
MIT License - see LICENSE for details.