Tutorial 8 · Python SDK¶
Goal: drive the whole session lifecycle from Python — create, exec, pause, resume — with typed errors instead of status-code parsing, and see the one-line migration path from E2B.
Prereq: the one-time setup key, and the SDK installed:
The client resolves its config from arguments or the environment — same variables the CLI uses, plus the key:
Hello world¶
from barista_sdk import Session
s = Session.open("hello") # get-or-create by name (platform default template)
print(s.exec(["echo", "hi"]).stdout) # hi — waits through boot for you
open is the DO-shaped door (bar-052): the name is the API — created if
missing, reused if it exists, and exec wakes it if it's parked. Pass
template="cc" (from tutorial 7) to pick the image;
Session.create(...) remains for explicit create-only semantics (it refuses
an existing name with 409 — never a silent overwrite).
The full lifecycle¶
from barista_sdk import NotFound, NotReady, Session
s = Session.create(
name="worker1",
template="cc", # or image= + digest=
metadata={"team": "ml", "task": "eval"}, # find it later: barista ls --meta team=ml
size="medium", # 2 vCPU / 2 GiB (small is the default)
idle_pause_s=300, # auto-pause after 5 idle minutes (0 = never)
)
code, out, err = s.exec(["uname", "-a"]) # ExecResult unpacks as a 3-tuple
s.pause() # freeze: memory kept, compute released
s.resume() # continue the same live process
s.exec(["date"]) # picks up where it left off
s.delete()
Two behaviors worth knowing:
- A paused session wakes on exec. The gateway resumes a paused session
when you exec into it, so after an auto-pause your next
s.exec(...)just works — added latency, not an error. - Readiness is absorbed (bar-052):
execwaits through a session's boot or wake by default (ready_timeout=60), so there is no retry loop to write. Only when the bound elapses do you seeNotReady(the gateway's retryable 409, carryingretry_after); passwait=Falseif you'd rather handle it immediately yourself:
try:
s.exec(["cat", "/tmp/ready"], wait=False) # one attempt, no absorbed wait
except NotReady as e:
print(f"still coming up — retry in {e.retry_after}s")
NotFound, AuthError, and APIError cover the rest — branch on types, not
status codes.

Coming from E2B¶
barista_sdk.e2b exposes E2B's Sandbox shape over sessions, so switching is
an import-line change for the supported subset — and commands.run does the
NotReady polling above for you:
from barista_sdk.e2b import Sandbox
sbx = Sandbox(template="cc") # or image= + digest=
result = sbx.commands.run("echo hi") # polls while the sandbox boots
print(result.stdout, result.exit_code) # hi 0
sbx.pause()
sbx = Sandbox.connect(sbx.sandbox_id) # resumes — memory preserved
sbx.kill()
The honest differences from real E2B (no persistent run_code kernel,
timeout= maps to pause-keeping-memory instead of a kill, in-place
set_timeout raises) live in the reference:
../sdk-python.md, and in the barista_sdk.e2b module
docstring's compatibility table.