Metadata-Version: 2.4
Name: sandbox-as-a-service
Version: 0.2.0
Summary: Official Python client for the Sandbox as a Service API — create disposable cloud sandboxes, run commands and move files.
Author: Florian Standhartinger
License: MIT
Project-URL: Homepage, https://sandbox-as-a-service.com
Project-URL: Documentation, https://sandbox-as-a-service.com/docs/sdk
Project-URL: Source, https://sandbox-as-a-service.com/sdk/
Project-URL: API, https://sandbox-as-a-service.com/docs/api
Keywords: sandboxes,sandbox-as-a-service,code-execution,e2b,agents
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.8
Description-Content-Type: text/markdown

# Sandbox as a Service — Python SDK

Official, dependency-free Python client for the
[Sandbox as a Service](https://sandbox-as-a-service.com) REST API: create a
disposable cloud VM, run commands in it, move files, expose a port, and destroy
it. Built on the standard library, so there is nothing to install alongside it.

## Install

```sh
pip install sandbox-as-a-service
```

The client is on the Python Package Index:
<https://pypi.org/project/sandbox-as-a-service/>. It is built on the standard
library only, so pip pulls in nothing alongside it.

**Alternative / offline:** the archive is a standard PEP 517 source
distribution built and served by the site itself; pip needs no extra index:

```sh
pip install https://sandbox-as-a-service.com/sdk/sandbox-as-a-service-python.tar.gz
```

To install a pinned build instead, use
`https://sandbox-as-a-service.com/sdk/sandbox_as_a_service-0.2.0.tar.gz`.

## Quickstart

```python
import os
from sandbox_as_a_service import Client

client = Client(api_key=os.environ["AAS_API_KEY"])   # key starts with aas_sk_

sandbox = client.create_sandbox(size="small", timeout_minutes=10)
try:
    result = sandbox.exec("python3 -c 'print(6 * 7)'")
    print(result.stdout.strip())   # -> 42
    print(result.exit_code)        # -> 0
finally:
    sandbox.destroy()
```

Both objects are context managers, and the sandbox destroys itself on the way
out — a sandbox left running is a sandbox being billed for:

```python
with Client() as client:                       # reads AAS_API_KEY
    with client.create_sandbox(timeout_minutes=5) as sandbox:
        sandbox.write_file("job.py", "print(sum(range(10)))\n")
        print(sandbox.exec("python3 job.py").stdout.strip())   # -> 45
```

## What is covered

| Area | Methods |
| --- | --- |
| Lifecycle | `create_sandbox`, `get_sandbox`, `list_sandboxes`, `iter_sandboxes`, `Sandbox.extend`, `Sandbox.refresh`, `Sandbox.destroy` |
| Commands | `Sandbox.exec` (blocking or streaming via `on_stdout`/`on_stderr`), `Sandbox.get_execution` |
| Files | `Sandbox.write_file`, `read_file`, `list_files`, `delete_file` |
| Preview URLs | `Sandbox.expose_port`, `list_ports`, `close_port` |
| Account | `get_usage`, `get_account` |

## Streaming output

Pass `on_stdout` or `on_stderr` to `Sandbox.exec` and the call streams: the
callback fires per chunk as the sandbox produces output, and the return value
is the same `Execution` object a blocking call returns:

```python
import sys

result = sandbox.exec(
    "for i in 1 2 3; do echo tick $i; sleep 1; done",
    on_stdout=lambda chunk: print(chunk, end=""),
    on_stderr=lambda chunk: print(chunk, end="", file=sys.stderr),
)
# callbacks fire as output arrives; result is the usual Execution object
```

Dropping the connection mid-stream — the process exiting, Ctrl-C, an exception
raised inside a callback — closes the stream, which kills the remote command;
the platform records it as `status: "cancelled"`. A failure inside the sandbox
after streaming started surfaces through the same typed exceptions as any API
error. See <https://sandbox-as-a-service.com/docs/execution#streaming-output>
for the event contract, the heartbeat, and the storage-cap rule (output past
1 MiB per stream keeps arriving live but is not stored; `truncated` is set).

Errors map onto typed exceptions in `sandbox_as_a_service.errors` — for example
`AuthenticationError` (401), `PaymentRequiredError` (402), `NotFoundError` (404),
`ConflictError` (409) and `RateLimitError` (429). Every API error keeps the
platform's `request_id`, which is what support needs to trace a request:

```python
from sandbox_as_a_service import RateLimitError

try:
    client.create_sandbox()
except RateLimitError as err:
    print("retry in", err.retry_after, "seconds", err.request_id)
```

## Notes

- `create_sandbox` blocks until the machine is ready. The default client
  timeout is 600 seconds, which covers a cold boot with room to spare.
- `exec` takes its own `timeout_ms` (1 000–600 000); the HTTP timeout is raised
  to match so a command that hits its limit still returns a result.
- Retries of a create are safe when you pass the same `idempotency_key`; a key
  is generated per call when you do not.

API reference: <https://sandbox-as-a-service.com/docs/api> ·
SDK docs: <https://sandbox-as-a-service.com/docs/sdk>
