Skip to content

Python SDK

The promigence package on PyPI, version 0.1.0b7, for Python 3.9 or newer. It has two parts: a Sandbox class for working in one sandbox, and the Promigence client for everything else the API does. Each has an async twin.

Terminal
pip install promigence
Language: bash

It brings one dependency with it, httpx. Using TypeScript instead? The TypeScript SDK has the same two parts.

TypeScript SDK

Sign in

The SDK finds your API key the way the CLI does, and the first match wins: the api_key= argument, then the PROMIGENCE_API_KEY environment variable, then the key promigence login saved on this machine.

Terminal
export PROMIGENCE_API_KEY=...      # or sign in once with: promigence login
Language: bash

Every run has a spend cap in US dollars: spend_cap=, else PROMIGENCE_SPEND_CAP, else your organization's default.

Start a sandbox, run a command

Sandbox.create() starts a sandbox from the built-in promigence/base snapshot. Pass a snapshot ID or alias, or a template's name, to start from another.

One sandbox, one command
Python
from promigence import Sandbox

with Sandbox.create(spend_cap=1) as sb:        # starts from promigence/base
    result = sb.commands.run("python3 -c 'print(6 * 7)'")
    print(result.stdout)                        # 42
    print(result.exit_code)                     # 0
# leaving the block ends the sandbox
Language: python

A command that exits non-zero raises CommandExitError; pass throw_on_exit=False to get its result instead. Each command takes a timeout_ms, and every duration in the SDK is in milliseconds.

To start from a container image, name it with a tag or a digest and pass allow_build=True. The first use builds a snapshot of the image, billed per second at its size's rate while it builds. Later sandboxes reuse it.

From an image
Python
sb = Sandbox.create(image="python:3.12", allow_build=True, spend_cap=1)
Language: python

Files

Write, read, list, remove
Python
sb.files.write("/work/notes.txt", "hello\n")
print(sb.files.read("/work/notes.txt"))          # hello
print([e.name for e in sb.files.list("/work")])
sb.files.remove("/work/notes.txt")
Language: python

files.read returns text. For binary files, pass format="bytes".

Pause and resume

Python
sb.pause()                  # not billed by the second while paused
sb.resume()                 # back where it was
sb.set_auto_pause(300)      # or let it pause itself after 5 idle minutes
Language: python

A paused sandbox keeps its files and is not billed by the second. Commands left running in the background end at the pause.

How long a paused sandbox is kept

Fork

Sandbox.fork(snapshot, count=N) starts N identical sandboxes from one snapshot and returns when all of them are ready. To fork a sandbox as it is now, save it as a snapshot first.

Five copies of a sandbox
Python
from promigence import Promigence, Sandbox

with Promigence() as client:
    saved = client.sandboxes.snapshot(sb.sandbox_id, alias="my-env")
    copies = Sandbox.fork(saved["snapshot_id"], count=5, spend_cap=2)
    for copy in copies:
        print(copy.commands.run("ls /work").stdout)
        copy.kill()
Language: python

End a sandbox

sb.kill() ends a sandbox and stops its bill, and returns False if it had already ended. Leaving a with block calls it for you. set_timeout(timeout_ms) changes how long a sandbox may run.

Errors

Everything the SDK raises on purpose is a PromigenceError. It carries a stable code, a message, a fix and a docs link to the code's row on the errors page, plus the HTTP status and request_id when the API answered, and the CLI's exit_code.

Its subclasses name the cases you are likely to catch: AuthError, NotFoundError, RateLimitError (with retry_after_ms), SpendCapError, PromigenceTimeoutError and InvalidArgumentError. EnvFailedError means the environment failed, which is ours and never counted against your code. CommandExitError is a command that failed, and CommandTimeoutError one that ran past its timeout_ms.

Your failure or ours
Python
from promigence import CommandExitError, PromigenceError, Sandbox

try:
    with Sandbox.create(spend_cap=1) as sb:
        sb.commands.run("cd /work && pytest -q")
except CommandExitError as e:
    print("the tests failed with exit code", e.exit_code)
except PromigenceError as e:
    print(e.code, e.fix, e.docs)
Language: python

Async

AsyncSandbox and AsyncPromigence have the methods of Sandbox and Promigence. Await them.

Python
import asyncio
from promigence import AsyncSandbox

async def main():
    async with await AsyncSandbox.create(spend_cap=1) as sb:
        result = await sb.commands.run("echo hi")
        print(result.stdout)

asyncio.run(main())
Language: python

The SDK calls the same routes as the CLI. The API reference lists every one, with its parameters and answers.

API reference

Get started

Leave your work email and we will get you started.

See our Privacy Policy for how we use your email.