Back to Microsandbox

Execution

docs/sdk/python/execution.mdx

0.6.922.4 KB
Original Source

Run commands inside a running sandbox. See Commands for usage examples.

Sandbox

<span className="msb-recv">sandbox.</span><span className="msb-hn">exec()</span>

python
async def exec(
    cmd: str,
    args: list[str] | ExecOptions | None = None,
    *,
    cwd: str | None = None,
    user: str | None = None,
    env: Mapping[str, str] | None = None,
    timeout: float | None = None,
    stdin: Stdin | bytes | None = None,
    tty: bool = False,
    rlimits: list[Rlimit] | None = None,
) -> ExecOutput
<Accordion title="Example">
python
out = await sandbox.exec(
    "python3",
    ["script.py"],
    cwd="/app",
    env={"PYTHONPATH": "/app/lib"},
    timeout=30.0,
)
print(out.stdout_text)
print(out.exit_code)  # 0
</Accordion>

Run a command inside the sandbox and wait for it to complete, buffering all stdout and stderr into memory. The keyword-only options apply to this call alone and don't change the sandbox's defaults. For long-running processes or large output, use exec_stream() instead. Raises ExecTimeoutError if timeout elapses and ExecFailedError if the process can't be spawned.

<p className="msb-label">Parameters</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><code>cmd</code><span className="msb-type">str</span></div> <div className="msb-param-desc">Command to execute (e.g. <code>"python3"</code>, <code>"/usr/bin/node"</code>).</div> </div> <div className="msb-param"> <div className="msb-param-key"><code>args</code><span className="msb-type">list[str] | ExecOptions | None</span></div> <div className="msb-param-desc">Command arguments, or a typed options mapping that may include its own <code>args</code> list.</div> </div> <div className="msb-param"> <div className="msb-param-key"><code>cwd</code><span className="msb-type">str | None</span></div> <div className="msb-param-desc">Working directory for this command.</div> </div> <div className="msb-param"> <div className="msb-param-key"><code>user</code><span className="msb-type">str | None</span></div> <div className="msb-param-desc">Guest user to run as.</div> </div> <div className="msb-param"> <div className="msb-param-key"><code>env</code><span className="msb-type">Mapping[str, str] | None</span></div> <div className="msb-param-desc">Environment variables, merged on top of the sandbox defaults.</div> </div> <div className="msb-param"> <div className="msb-param-key"><code>timeout</code><span className="msb-type">float | None</span></div> <div className="msb-param-desc">Seconds before the process is killed.</div> </div> <div className="msb-param"> <div className="msb-param-key"><code>stdin</code><a className="msb-type" href="#stdin">Stdin | bytes | None</a></div> <div className="msb-param-desc">Stdin configuration. Raw <code>bytes</code> are sent inline; default is <code>/dev/null</code>.</div> </div> <div className="msb-param"> <div className="msb-param-key"><code>tty</code><span className="msb-type">bool</span></div> <div className="msb-param-desc">Allocate a pseudo-terminal, merging stdout and stderr.</div> </div> <div className="msb-param"> <div className="msb-param-key"><code>rlimits</code><a className="msb-type" href="#rlimit">list[Rlimit] | None</a></div> <div className="msb-param-desc">POSIX resource limits applied to the process.</div> </div> </div> <p className="msb-label">Returns</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><a className="msb-type" href="#execoutput">ExecOutput</a></div> <div className="msb-param-desc">Collected stdout, stderr, and exit status.</div> </div> </div>

<span className="msb-recv">sandbox.</span><span className="msb-hn">shell()</span>

python
async def shell(
    script: str,
    *,
    cwd: str | None = None,
    user: str | None = None,
    env: Mapping[str, str] | None = None,
    timeout: float | None = None,
    stdin: Stdin | bytes | None = None,
    tty: bool = False,
    rlimits: list[Rlimit] | None = None,
) -> ExecOutput
<Accordion title="Example">
python
out = await sandbox.shell("ls -la /app && echo done")
print(out.stdout_text)
</Accordion>

Run a command through the sandbox's configured shell (defaults to /bin/sh). Shell syntax like pipes, redirects, and && chains works. Accepts the same keyword-only options as exec().

<p className="msb-label">Parameters</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><code>script</code><span className="msb-type">str</span></div> <div className="msb-param-desc">Shell command string (e.g. <code>"ls -la /app &amp;&amp; echo done"</code>).</div> </div> <div className="msb-param"> <div className="msb-param-key"><code>cwd, user, env, timeout, stdin, tty, rlimits</code></div> <div className="msb-param-desc">Same per-call options as <a className="msb-type" href="#sandbox-exec">exec()</a>.</div> </div> </div> <p className="msb-label">Returns</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><a className="msb-type" href="#execoutput">ExecOutput</a></div> <div className="msb-param-desc">Collected stdout, stderr, and exit status.</div> </div> </div> <p className="msb-member-group">Stream methods</p>

<span className="msb-recv">sandbox.</span><span className="msb-hn">exec_stream()</span>

python
async def exec_stream(
    cmd: str,
    args: list[str] | ExecOptions | None = None,
    *,
    cwd: str | None = None,
    user: str | None = None,
    env: Mapping[str, str] | None = None,
    timeout: float | None = None,
    stdin: Stdin | bytes | None = None,
    tty: bool = False,
    rlimits: list[Rlimit] | None = None,
) -> ExecHandle
<Accordion title="Example">
python
import sys

from microsandbox import ExecEventType

handle = await sandbox.exec_stream("tail", ["-f", "/var/log/app.log"])
async for event in handle:
    if event.event_type is ExecEventType.STDOUT:
        sys.stdout.buffer.write(event.data)
    elif event.event_type is ExecEventType.EXITED:
        break
</Accordion>

Run a command with streaming output. Returns an ExecHandle that emits stdout, stderr, and exit events as they happen rather than buffering everything. Takes the same per-call options as exec(). Pass stdin=Stdin.pipe() to write to the process while it runs via take_stdin(). For TTY sessions, call resize(rows, cols) when the terminal dimensions change.

<p className="msb-label">Parameters</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><code>cmd</code><span className="msb-type">str</span></div> <div className="msb-param-desc">Command to execute.</div> </div> <div className="msb-param"> <div className="msb-param-key"><code>args</code><span className="msb-type">list[str] | ExecOptions | None</span></div> <div className="msb-param-desc">Command arguments, or a typed options mapping.</div> </div> <div className="msb-param"> <div className="msb-param-key"><code>cwd, user, env, timeout, stdin, tty, rlimits</code></div> <div className="msb-param-desc">Same per-call options as <a className="msb-type" href="#sandbox-exec">exec()</a>.</div> </div> </div> <p className="msb-label">Returns</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><a className="msb-type" href="#exechandle">ExecHandle</a></div> <div className="msb-param-desc">Streaming handle for receiving events and controlling the process.</div> </div> </div>

<span className="msb-recv">sandbox.</span><span className="msb-hn">shell_stream()</span>

python
async def shell_stream(
    script: str,
    *,
    cwd: str | None = None,
    user: str | None = None,
    env: Mapping[str, str] | None = None,
    timeout: float | None = None,
    stdin: Stdin | bytes | None = None,
    tty: bool = False,
    rlimits: list[Rlimit] | None = None,
) -> ExecHandle
<Accordion title="Example">
python
import sys

from microsandbox import ExecEventType

handle = await sandbox.shell_stream("for i in 1 2 3; do echo $i; sleep 1; done")
async for event in handle:
    if event.event_type is ExecEventType.STDOUT:
        sys.stdout.buffer.write(event.data)
</Accordion>

Streaming variant of shell(): runs script through the configured shell but returns an ExecHandle instead of buffering output.

<p className="msb-label">Parameters</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><code>script</code><span className="msb-type">str</span></div> <div className="msb-param-desc">Shell command string.</div> </div> <div className="msb-param"> <div className="msb-param-key"><code>cwd, user, env, timeout, stdin, tty, rlimits</code></div> <div className="msb-param-desc">Same per-call options as <a className="msb-type" href="#sandbox-exec">exec()</a>.</div> </div> </div> <p className="msb-label">Returns</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><a className="msb-type" href="#exechandle">ExecHandle</a></div> <div className="msb-param-desc">Streaming handle.</div> </div> </div> <p className="msb-member-group">Attach methods</p>

<span className="msb-recv">sandbox.</span><span className="msb-hn">attach()</span>

python
async def attach(
    cmd: str,
    args: list[str] | None = None,
    *,
    cwd: str | None = None,
    user: str | None = None,
    env: Mapping[str, str] | None = None,
    detach_keys: str | None = None,
) -> int
<Accordion title="Example">
python
code = await sandbox.attach("bash", cwd="/app", env={"EDITOR": "vim"})
</Accordion>

Bridge your terminal directly to a process inside the sandbox for a fully interactive PTY session. Press the configured detach key sequence (default Ctrl+]) to disconnect without stopping the process. Returns the process exit code.

<p className="msb-label">Parameters</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><code>cmd</code><span className="msb-type">str</span></div> <div className="msb-param-desc">Command to run.</div> </div> <div className="msb-param"> <div className="msb-param-key"><code>args</code><span className="msb-type">list[str] | None</span></div> <div className="msb-param-desc">Command arguments.</div> </div> <div className="msb-param"> <div className="msb-param-key"><code>cwd</code><span className="msb-type">str | None</span></div> <div className="msb-param-desc">Working directory.</div> </div> <div className="msb-param"> <div className="msb-param-key"><code>user</code><span className="msb-type">str | None</span></div> <div className="msb-param-desc">Guest user to run as.</div> </div> <div className="msb-param"> <div className="msb-param-key"><code>env</code><span className="msb-type">Mapping[str, str] | None</span></div> <div className="msb-param-desc">Environment variables for the session.</div> </div> <div className="msb-param"> <div className="msb-param-key"><code>detach_keys</code><span className="msb-type">str | None</span></div> <div className="msb-param-desc">Detach key sequence (e.g. <code>"ctrl-]"</code> or <code>"ctrl-p,ctrl-q"</code>).</div> </div> </div> <p className="msb-label">Returns</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><span className="msb-type">int</span></div> <div className="msb-param-desc">Exit code of the process.</div> </div> </div>

<span className="msb-recv">sandbox.</span><span className="msb-hn">attach_shell()</span>

python
async def attach_shell() -> int
<Accordion title="Example">
python
code = await sandbox.attach_shell()
</Accordion>

Bridge your terminal to the sandbox's default shell in a fully interactive PTY session. Returns the shell's exit code.

<p className="msb-label">Returns</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><span className="msb-type">int</span></div> <div className="msb-param-desc">Exit code of the shell process.</div> </div> </div>

ExecHandle

<p className="msb-backref">Returned by <a href="#sandbox-exec_stream">exec_stream()</a> · <a href="#sandbox-shell_stream">shell_stream()</a></p>

A handle to a running streaming execution and its events.

<span className="msb-recv">handle.</span><span className="msb-hn">id</span>

str

Correlation ID for this execution

<span className="msb-recv">handle.</span><span className="msb-hn">take_stdin()</span>

python
take_stdin()

Take the stdin writer. Returns None after the first call, or when stdin wasn't piped

<p className="msb-label">Returns</p>

ExecSink \| None

<span className="msb-recv">handle.</span><span className="msb-hn">recv()</span>

python
recv()

(async) Receive the next event. Returns None when the stream ends

<p className="msb-label">Returns</p>

ExecEvent \| None

<span className="msb-recv">handle.</span><span className="msb-hn">wait()</span>

python
wait()

(async) Wait for the process to exit. Returns (code, success)

<p className="msb-label">Returns</p>

tuple[int, bool]

<span className="msb-recv">handle.</span><span className="msb-hn">collect()</span>

python
collect()

(async) Drain remaining output and wait for exit

<p className="msb-label">Returns</p>

ExecOutput

<span className="msb-recv">handle.</span><span className="msb-hn">signal()</span>

python
signal(sig)

(async) Send a POSIX signal (numeric) to the process

<span className="msb-recv">handle.</span><span className="msb-hn">kill()</span>

python
kill()

(async) Send SIGKILL to the process

<span className="msb-recv">handle.</span><span className="msb-hn">resize()</span>

python
resize(rows, cols)

(async) Resize the PTY to the given uint16 dimensions

ExecSink

<p className="msb-backref">Returned by <a href="#exechandle">ExecHandle.take_stdin()</a></p>

Writer for sending data to a running process's stdin. Obtained from ExecHandle.take_stdin() when the execution was configured with stdin=Stdin.pipe().

<span className="msb-recv">sink.</span><span className="msb-hn">write()</span>

python
write(data)

(async) Write bytes to the process's stdin

<span className="msb-recv">sink.</span><span className="msb-hn">close()</span>

python
close()

(async) Close the sink. Sends EOF in non-TTY pipe mode; the guest PTY remains open in TTY mode

Stdin

<p className="msb-backref">Used by <a href="#sandbox-exec">exec()</a> · <a href="#sandbox-shell">shell()</a> · <a href="#sandbox-exec_stream">exec_stream()</a> · <a href="#sandbox-shell_stream">shell_stream()</a></p>

Factory for process stdin configuration.

<span className="msb-recv">Stdin.</span><span className="msb-hn">null()</span>

python
Stdin.null()

Connect stdin to /dev/null (default)

<span className="msb-recv">Stdin.</span><span className="msb-hn">pipe()</span>

python
Stdin.pipe()

Open a writable pipe. Write via take_stdin() on the handle

<span className="msb-recv">Stdin.</span><span className="msb-hn">bytes()</span>

python
Stdin.bytes(data)

Inline data sent before the process starts, then EOF

The factories set the corresponding StdinMode member.

Rlimit

<p className="msb-backref">Used by <a href="#sandbox-exec">exec()</a> · <a href="#sandbox-shell">shell()</a> · <a href="#sandbox-exec_stream">exec_stream()</a> · <a href="#sandbox-shell_stream">shell_stream()</a></p>

Frozen dataclass describing a POSIX resource limit. Construct one directly or via a factory, then pass a list as the rlimits argument.

<span className="msb-recv">rlimit.</span><span className="msb-hn">resource</span>

RlimitResource

Which resource is limited

<span className="msb-recv">rlimit.</span><span className="msb-hn">soft</span>

int

Soft limit

<span className="msb-recv">rlimit.</span><span className="msb-hn">hard</span>

int

Hard limit

<span className="msb-recv">Rlimit.</span><span className="msb-hn">nofile()</span>

python
Rlimit.nofile(limit)

Max open file descriptors

<span className="msb-recv">Rlimit.</span><span className="msb-hn">cpu()</span>

python
Rlimit.cpu(secs)

CPU time limit in seconds

<span className="msb-recv">Rlimit.</span><span className="msb-hn">as_()</span>

python
Rlimit.as_(\*, soft, hard)

Virtual memory size

<span className="msb-recv">Rlimit.</span><span className="msb-hn">nproc()</span>

python
Rlimit.nproc(limit)

Max number of processes

<span className="msb-recv">Rlimit.</span><span className="msb-hn">fsize()</span>

python
Rlimit.fsize(limit)

Max file size

<span className="msb-recv">Rlimit.</span><span className="msb-hn">memlock()</span>

python
Rlimit.memlock(limit)

Max locked memory

<span className="msb-recv">Rlimit.</span><span className="msb-hn">stack()</span>

python
Rlimit.stack(limit)

Max stack size

Types

ExecOptions

<p className="msb-backref">Accepted by <a href="#sandbox-exec">exec()</a> · <a href="#sandbox-exec_stream">exec_stream()</a></p>

Typed dictionary for passing arguments and per-call options together as the second positional argument. Use a Stdin object to select a mode or raw bytes for inline data.

KeyTypeDescription
argslist[str]Command arguments
cwdstrWorking directory
userstrGuest user
envMapping[str, str]Per-command environment variables
timeoutfloatTimeout in seconds
stdinStdin | bytesStdin configuration or inline bytes
stdin_databytesInline stdin bytes when stdin is omitted
ttyboolWhether to allocate a pseudo-terminal
rlimitslist[Rlimit]POSIX resource limits

ExecOutput

<p className="msb-backref">Returned by <a href="#sandbox-exec">exec()</a> · <a href="#sandbox-shell">shell()</a> · <a href="#exechandle">ExecHandle.collect()</a></p>

The result of a completed command execution: collected output plus exit status. All members are properties. In TTY mode, stdout_bytes contains the combined terminal output and stderr_bytes is empty because a PTY doesn't preserve separate stdout and stderr streams.

PropertyTypeDescription
exit_codeintProcess exit code
successboolTrue when exit_code == 0
stdout_textstrCollected stdout decoded as UTF-8. Raises on invalid encoding
stderr_textstrCollected stderr decoded as UTF-8. Raises on invalid encoding
stdout_bytesbytesRaw stdout bytes
stderr_bytesbytesRaw stderr bytes

ExecEvent

<p className="msb-backref">Emitted by <a href="#exechandle">ExecHandle</a></p>

Native event object emitted by recv() and by iterating an ExecHandle. Fields that don't apply to a given event are None.

PropertyTypeDescription
event_typeExecEventTypeExact event discriminator
pidint | NoneGuest PID, set on ExecEventType.STARTED
databytes | NoneOutput bytes on STDOUT / STDERR, or a UTF-8 failure message on FAILED / STDIN_ERROR
codeint | NoneExit code on EXITED, or errno when available on FAILED / STDIN_ERROR

ExecEventType

<p className="msb-backref">Returned by <a href="#execevent">ExecEvent.event_type</a></p>

String enum (enum.StrEnum) identifying a streaming execution event.

MemberValueDescription
ExecEventType.STARTED"started"Process started; pid is populated
ExecEventType.STDOUT"stdout"Standard-output bytes are available in data
ExecEventType.STDERR"stderr"Standard-error bytes are available in data
ExecEventType.EXITED"exited"Process exited; code is populated
ExecEventType.FAILED"failed"Process startup failed
ExecEventType.STDIN_ERROR"stdin_error"Writing process stdin failed

ExitStatus

<p className="msb-backref">Used by <a href="#exechandle">ExecHandle.wait()</a></p>

Frozen dataclass describing a process exit result. ExecHandle.wait() returns the same information as a (code, success) tuple.

FieldTypeDescription
codeintProcess exit code
successboolTrue when code == 0

StdinMode

<p className="msb-backref">Used internally by <a href="#stdin">Stdin</a></p>

String enum (enum.StrEnum) identifying how command stdin is connected.

MemberValueDescription
StdinMode.NULL"null"Connect stdin to /dev/null
StdinMode.PIPE"pipe"Expose a writable ExecSink
StdinMode.BYTES"bytes"Send inline bytes, then EOF

RlimitResource

<p className="msb-backref">Used by <a href="#rlimit">Rlimit.resource</a></p>

String enum (enum.StrEnum) naming a limitable POSIX resource.

MemberValueDescription
RlimitResource.CPU"cpu"CPU time
RlimitResource.FSIZE"fsize"File size
RlimitResource.DATA"data"Data segment size
RlimitResource.STACK"stack"Stack size
RlimitResource.CORE"core"Core file size
RlimitResource.RSS"rss"Resident set size
RlimitResource.NPROC"nproc"Number of processes
RlimitResource.NOFILE"nofile"Open file descriptors
RlimitResource.MEMLOCK"memlock"Locked memory
RlimitResource.AS"as"Virtual memory
RlimitResource.LOCKS"locks"File locks
RlimitResource.SIGPENDING"sigpending"Pending signals
RlimitResource.MSGQUEUE"msgqueue"Message queue size
RlimitResource.NICE"nice"Nice priority ceiling
RlimitResource.RTPRIO"rtprio"Real-time priority ceiling
RlimitResource.RTTIME"rttime"Real-time CPU time