flyte.sandbox
Sandbox utilities for running isolated code inside Flyte tasks.
.. warning:: Experimental feature: alpha — APIs may change without notice.
flyte.sandbox provides two distinct sandboxing approaches:
1. Orchestration sandbox — powered by Monty
Runs pure Python orchestration logic (control flow, routing, aggregation)
with zero overhead. The Monty runtime enforces strong restrictions:
no imports, no IO, no network access, microsecond startup. Used via
@env.sandbox.orchestrator or flyte.sandbox.orchestrator_from_str().
Sandboxed orchestrators are:
- **Side-effect free**: No filesystem, network, or OS access
- **Microsecond startup**: No container spin-up — runs in the same process
- **Multiplexable**: Many orchestrators run safely on the same Python process
Example::
env = flyte.TaskEnvironment(name="my-env")
@env.sandbox.orchestrator
def route(x: int, y: int) -> int:
return add(x, y) # calls a worker task
pipeline = flyte.sandbox.orchestrator_from_str(
"add(x, y) * 2",
inputs={"x": int, "y": int},
output=int,
tasks=[add],
)
2. Code sandbox — arbitrary code in an isolated container
Runs arbitrary Python scripts or shell commands inside an ephemeral Docker
container. The image is built on demand from declared packages and
system_packages, executed once, then discarded. Network is blocked by
default (block_network=True), preventing outbound calls from untrusted
code. Used via flyte.sandbox.create().
Three execution modes are supported:
- Code mode — provide Python source that runs with automatic input/output wiring.
- Verbatim mode — run a script that manages its own I/O via /var/inputs and /var/outputs.
- Command mode — execute an arbitrary command or entrypoint.
Examples
--------
Code mode
~~~~~~~~~
Provide Python code that uses inputs as variables and assigns
outputs as Python values.
_stats_code = """
import numpy as np
nums = np.array([float(v) for v in values.split(",")])
mean = float(np.mean(nums))
std = float(np.std(nums))
window_end = dt + delta
"""
stats_sandbox = flyte.sandbox.create(
name="numpy-stats",
code=_stats_code,
inputs={
"values": str,
"dt": datetime.datetime,
"delta": datetime.timedelta,
},
outputs={
"mean": float,
"std": float,
"window_end": datetime.datetime,
},
packages=["numpy"],
)
mean, std, window_end = await stats_sandbox.run.aio(
values="1,2,3,4,5",
dt=datetime.datetime(2024, 1, 1),
delta=datetime.timedelta(days=1),
)
Verbatim mode
~~~~~~~~~~~~~
Run a script that explicitly reads inputs from /var/inputs and
writes outputs to /var/outputs.
_etl_script = """ import json, pathlib
payload = json.loads(
pathlib.Path("/var/inputs/payload").read_text()
)
total = sum(payload["values"])
pathlib.Path("/var/outputs/total").write_text(str(total))
"""
etl_sandbox = flyte.sandbox.create(
name="etl-script",
code=_etl_script,
inputs={"payload": File},
outputs={"total": int},
auto_io=False,
)
Command mode
~~~~~~~~~~~~
Execute an arbitrary command inside the sandbox environment.
sandbox = flyte.sandbox.create(
name="test-runner",
command=["/bin/bash", "-c", "pytest /var/inputs/tests.py -q"],
inputs={"tests.py": File},
outputs={"exit_code": str},
)
Notes
-----
• Inputs are materialized under /var/inputs.
• Outputs must be written to /var/outputs.
• In code mode, inputs are available as Python variables and
scalar outputs are captured automatically.
• Additional Python dependencies can be specified via the
`packages` argument.
Directory
Classes
| Class | Description |
|---|---|
CodeTaskTemplate |
A sandboxed task created from a code string rather than a decorated function. |
ImageConfig |
Configuration for Docker image building at runtime. |
SandboxedConfig |
Configuration for a sandboxed task executed via Monty. |
SandboxedTaskTemplate |
A task template that executes the function body in a Monty sandbox. |
Methods
| Method | Description |
|---|---|
create() |
Create a stateless Python code sandbox. |
orchestrate_local() |
One-shot local execution of a code string in the Monty sandbox. |
orchestrator_from_str() |
Create a reusable sandboxed task from a code string. |
Variables
| Property | Type | Description |
|---|---|---|
ORCHESTRATOR_SYNTAX_PROMPT |
str |
|
sandbox_environment |
TaskEnvironment |
Methods
create()
def create(
name: typing.Optional[str],
code: typing.Optional[str],
inputs: typing.Optional[dict[str, type]],
outputs: typing.Optional[dict[str, type]],
command: typing.Optional[list[str]],
arguments: typing.Optional[list[str]],
packages: typing.Optional[list[str]],
system_packages: typing.Optional[list[str]],
additional_commands: typing.Optional[list[str]],
resources: typing.Optional[flyte._resources.Resources],
image_config: typing.Optional[flyte.sandbox._code_sandbox.ImageConfig],
image_name: typing.Optional[str],
image: typing.Optional[str],
auto_io: bool,
retries: int,
timeout: typing.Optional[int],
env_vars: typing.Optional[dict[str, str]],
secrets: typing.Optional[list],
cache: str,
) -> flyte.sandbox._code_sandbox._SandboxCreate a stateless Python code sandbox.
The sandbox is stateless — each invocation runs in a fresh, ephemeral container. No filesystem state, environment variables or side effects carry over between runs.
Three modes, mutually exclusive:
- Auto-IO mode (
codeprovided,auto_io=True, default): write just the business logic. Flyte auto-generates an argparse preamble so declared inputs are available as local variables, and writes declared scalar outputs to/var/outputs/automatically. No boilerplate needed. - Verbatim mode (
codeprovided,auto_io=False): run an arbitrary Python script as-is. CLI args for declared inputs are still forwarded, but the script handles all I/O itself (reading from/var/inputs/, writing to/var/outputs/<name>manually). - Command mode (
commandprovided): run any shell command directly, e.g. a compiled binary or a shell pipeline.
Call .run() on the returned sandbox to build the image and execute.
Example — auto-IO mode (default, no boilerplate)::
sandbox = flyte.sandbox.create(
name="double",
code="result = x * 2",
inputs={"x": int},
outputs={"result": int},
)
result = await sandbox.run.aio(x=21) # returns 42
Example — verbatim mode (complete Python script, full control)::
sandbox = flyte.sandbox.create(
name="etl",
code="""
import json, pathlib
data = json.loads(pathlib.Path("/var/inputs/payload").read_text())
pathlib.Path("/var/outputs/total").write_text(str(sum(data["values"])))
""",
inputs={"payload": File},
outputs={"total": int},
auto_io=False,
)
Example — command mode::
sandbox = flyte.sandbox.create(
name="test-runner",
command=["/bin/bash", "-c", pytest_cmd],
arguments=["_", "/var/inputs/solution.py", "/var/inputs/tests.py"],
inputs={"solution.py": File, "tests.py": File},
outputs={"exit_code": str},
)
| Parameter | Type | Description |
|---|---|---|
name |
typing.Optional[str] |
Sandbox name. Derives task and image names. |
code |
typing.Optional[str] |
Python source to run (auto-IO or verbatim mode). Mutually exclusive with command. - Primitive: int, float, str, bool - Date/time: datetime.datetime, datetime.timedelta - IO handles: flyte.io.File (bind-mounted at /var/inputs/<name>; available as a path string in auto-IO mode) - Primitive: int, float, str, bool - Date/time: datetime.datetime (ISO-8601), datetime.timedelta - IO handles: flyte.io.File (user code must write the file to /var/outputs/<name>) |
inputs |
typing.Optional[dict[str, type]] |
|
outputs |
typing.Optional[dict[str, type]] |
|
command |
typing.Optional[list[str]] |
Entrypoint command (command mode). Mutually exclusive with code. |
arguments |
typing.Optional[list[str]] |
Arguments forwarded to command (command mode only). |
packages |
typing.Optional[list[str]] |
Python packages to install via pip. |
system_packages |
typing.Optional[list[str]] |
System packages to install via apt. |
additional_commands |
typing.Optional[list[str]] |
Extra Dockerfile RUN commands. |
resources |
typing.Optional[flyte._resources.Resources] |
CPU / memory resources for the container. |
image_config |
typing.Optional[flyte.sandbox._code_sandbox.ImageConfig] |
Registry and Python version settings. |
image_name |
typing.Optional[str] |
Explicit image name, overrides the auto-generated one. |
image |
typing.Optional[str] |
Pre-built image URI. Skips the build step if provided. |
auto_io |
bool |
When True (default), Flyte wraps code with an auto-generated argparse preamble and output-writing epilogue so declared inputs are available as local variables and scalar outputs are collected automatically — no boilerplate needed. When False, code is run verbatim and must handle all I/O itself. |
retries |
int |
Number of task retries on failure. |
timeout |
typing.Optional[int] |
Task timeout in seconds. |
env_vars |
typing.Optional[dict[str, str]] |
Environment variables available inside the container. |
secrets |
typing.Optional[list] |
|
cache |
str |
Cache behaviour — "auto", "override", or "disable". |
orchestrate_local()
def orchestrate_local(
source: str,
inputs: Dict[str, Any],
tasks: Optional[List[Any]],
timeout_ms: int,
) -> AnyOne-shot local execution of a code string in the Monty sandbox.
.. warning:: Experimental feature: alpha — APIs may change without notice.
Sends the code + inputs to Monty and returns the result directly,
without creating a TaskTemplate or going through the controller.
The last expression in source becomes the return value::
result = await sandbox.orchestrate_local(
"add(x, y) * 2",
inputs={"x": 1, "y": 2},
tasks=[add],
)
# → 6
Parameters
source:
Python code string to execute in the sandbox.
inputs:
Mapping of input names to their values.
tasks:
List of external functions (tasks, durable ops) available inside the
sandbox. Each item’s __name__ is used as the key.
timeout_ms:
Sandbox execution timeout in milliseconds.
| Parameter | Type | Description |
|---|---|---|
source |
str |
|
inputs |
Dict[str, Any] |
|
tasks |
Optional[List[Any]] |
|
timeout_ms |
int |
orchestrator_from_str()
def orchestrator_from_str(
source: str,
inputs: Dict[str, type],
output: type,
tasks: Optional[List[Any]],
name: str,
timeout_ms: int,
cache: CacheRequest,
retries: int,
image: Optional[Any],
) -> CodeTaskTemplateCreate a reusable sandboxed task from a code string.
.. warning:: Experimental feature: alpha — APIs may change without notice.
The returned CodeTaskTemplate can be passed to flyte.run()
just like a decorated task.
The last expression in source becomes the return value::
pipeline = sandbox.orchestrator_from_str(
"add(x, y) * 2",
inputs={"x": int, "y": int},
output=int,
tasks=[add],
)
result = flyte.run(pipeline, x=1, y=2) # → 6
Parameters
source:
Python code string to execute in the sandbox.
inputs:
Mapping of input names to their types.
output:
The return type (default NoneType).
tasks:
List of external functions (tasks, durable ops) available inside the
sandbox. Each item’s __name__ is used as the key.
name:
Task name (default "sandboxed-code").
timeout_ms:
Sandbox execution timeout in milliseconds.
cache:
Cache policy for the task.
retries:
Number of retries on failure.
image:
Docker image to use. If not provided, a default Debian image with
pydantic-monty is created automatically.
| Parameter | Type | Description |
|---|---|---|
source |
str |
|
inputs |
Dict[str, type] |
|
output |
type |
|
tasks |
Optional[List[Any]] |
|
name |
str |
|
timeout_ms |
int |
|
cache |
CacheRequest |
|
retries |
int |
|
image |
Optional[Any] |