Skip to main content

Python sandbox powered by WebAssembly

Project description

PyEryx - Python Bindings for Eryx

Python bindings for the Eryx sandbox - execute Python code securely inside WebAssembly.

Installation

pip install pyeryx

Note: The package is installed as pyeryx but imported as eryx.

Or build from source using maturin:

cd crates/eryx-python
maturin develop

Quick Start

import eryx

# Create a sandbox with the embedded Python runtime
sandbox = eryx.Sandbox()

# Execute Python code in complete isolation
result = sandbox.execute('''
print("Hello from the sandbox!")
x = 2 + 2
print(f"2 + 2 = {x}")
''')

print(result.stdout)
# Output:
# Hello from the sandbox!
# 2 + 2 = 4

print(f"Execution took {result.duration_ms:.2f}ms")

Features

  • Complete Isolation: Sandboxed code cannot access files, network, or system resources
  • Resource Limits: Configure timeouts and memory limits
  • Fast Startup: Pre-initialized Python runtime embedded for ~1-5ms sandbox creation
  • Pre-initialization: Custom snapshots with packages for even faster specialized sandboxes
  • Package Support: Load Python packages (.whl, .tar.gz) including native extensions
  • Type Safe: Full type stubs for IDE support and static analysis

Python Version

The sandbox runs CPython 3.14 compiled to WebAssembly (WASI). This is the same Python build used by componentize-py from the Bytecode Alliance.

Note: Python 3.14 is currently in development. The sandbox tracks the latest WASI-compatible CPython build from the componentize-py project.

Performance

The pyeryx package ships with a pre-initialized Python runtime embedded in the binary. This means Python's interpreter initialization (~450ms) has already been done at build time, so creating a sandbox is very fast:

import eryx
import time

# First sandbox - fast! (~1-5ms)
start = time.perf_counter()
sandbox = eryx.Sandbox()
print(f"Sandbox created in {(time.perf_counter() - start) * 1000:.1f}ms")

# Execution is also fast
start = time.perf_counter()
result = sandbox.execute('print("Hello!")')
print(f"Execution took {(time.perf_counter() - start) * 1000:.1f}ms")

For repeated sandbox creation with custom packages, see SandboxFactory below.

API Reference

Sandbox

The main class for executing Python code in isolation.

sandbox = eryx.Sandbox(
    resource_limits=eryx.ResourceLimits(
        execution_timeout_ms=5000,      # 5 second timeout
        max_memory_bytes=100_000_000,   # 100MB memory limit
    )
)

result = sandbox.execute("print('Hello!')")

Loading Packages

To use custom packages, use SandboxFactory which bundles packages into a reusable runtime snapshot:

import eryx

# Create a factory with your packages (one-time, takes 3-5 seconds)
factory = eryx.SandboxFactory(
    packages=[
        "/path/to/jinja2-3.1.2-py3-none-any.whl",
        "/path/to/markupsafe-2.1.3-wasi.tar.gz",  # WASI-compiled native extension
    ],
    imports=["jinja2"],  # Optional: pre-import for faster first execution
)

# Create sandboxes with packages already loaded (~10-20ms each)
sandbox = factory.create_sandbox()
result = sandbox.execute('''
from jinja2 import Template
template = Template("Hello, {{ name }}!")
print(template.render(name="World"))
''')

For packages with native extensions (like markupsafe), you need WASI-compiled versions. These are automatically late-linked into the WebAssembly component.

ExecuteResult

Returned by sandbox.execute() with execution results:

  • stdout: str - Captured standard output
  • duration_ms: float - Execution time in milliseconds
  • callback_invocations: int - Number of callback invocations
  • peak_memory_bytes: Optional[int] - Peak memory usage (if available)

ResourceLimits

Configure execution constraints:

limits = eryx.ResourceLimits(
    execution_timeout_ms=30000,        # Max script runtime (default: 30s)
    callback_timeout_ms=10000,         # Max single callback time (default: 10s)
    max_memory_bytes=134217728,        # Max memory (default: 128MB)
    max_callback_invocations=1000,     # Max callbacks (default: 1000)
)

# Or create unlimited (use with caution!)
unlimited = eryx.ResourceLimits.unlimited()

SandboxFactory

For use cases with custom packages, SandboxFactory lets you create a reusable factory with your packages pre-loaded and pre-imported.

Note: For basic usage without packages, eryx.Sandbox() is already fast (~1-5ms) because the base runtime ships pre-initialized. Use SandboxFactory only when you need to bundle custom packages.

Use cases for SandboxFactory:

  • Load packages (jinja2, numpy, etc.) once and create many sandboxes from the factory
  • Pre-import modules to eliminate import overhead on first execution
  • Save/load factory state to disk for persistence across process restarts
import eryx

# One-time factory creation with packages (takes 3-5 seconds)
factory = eryx.SandboxFactory(
    packages=[
        "/path/to/jinja2-3.1.2-py3-none-any.whl",
        "/path/to/markupsafe-2.1.3-wasi.tar.gz",
    ],
    imports=["jinja2"],  # Pre-import modules
)

# Create sandboxes with packages already loaded (~10-20ms each)
sandbox = factory.create_sandbox()
result = sandbox.execute('''
from jinja2 import Template
print(Template("Hello {{ name }}").render(name="World"))
''')

# Create many sandboxes from the same factory
for i in range(100):
    sandbox = factory.create_sandbox()
    sandbox.execute(f"print('Sandbox {i}')")

Saving and Loading

Save factories to disk for instant startup across process restarts:

# Save the factory (includes pre-compiled WASM state + package state)
factory.save("/path/to/jinja2-factory.bin")

# Later, in another process - loads in ~10ms (vs 3-5s to recreate)
factory = eryx.SandboxFactory.load("/path/to/jinja2-factory.bin")
sandbox = factory.create_sandbox()

Properties and Methods

  • factory.size_bytes - Size of the pre-compiled factory in bytes
  • factory.create_sandbox(resource_limits=...) - Create a new sandbox
  • factory.save(path) - Save factory to a file
  • factory.to_bytes() - Get factory as bytes
  • SandboxFactory.load(path) - Load factory from a file

Exceptions

  • eryx.EryxError - Base exception for all Eryx errors
  • eryx.ExecutionError - Python code raised an exception
  • eryx.InitializationError - Sandbox failed to initialize
  • eryx.ResourceLimitError - Resource limit exceeded
  • eryx.TimeoutError - Execution timed out

Package Loading

Supported Formats

  • .whl - Standard Python wheels (zip archives)
  • .tar.gz / .tgz - Tarballs (used by wasi-wheels project)
  • Directories - Pre-extracted package directories

Native Extensions

Packages containing native Python extensions (.so files compiled for WASI) are automatically detected and late-linked into the WebAssembly component. This allows packages like numpy, markupsafe, and others to work in the sandbox.

Note: You need WASI-compiled versions of native extensions, not regular Linux/macOS/Windows binaries.

Error Handling

import eryx

sandbox = eryx.Sandbox()

try:
    result = sandbox.execute("raise ValueError('oops')")
except eryx.ExecutionError as e:
    print(f"Code failed: {e}")

try:
    sandbox = eryx.Sandbox(
        resource_limits=eryx.ResourceLimits(execution_timeout_ms=100)
    )
    result = sandbox.execute("while True: pass")
except eryx.TimeoutError as e:
    print(f"Timed out: {e}")

Development

Building

# Install maturin
pip install maturin

# Build and install in development mode
maturin develop

# Build release wheel
maturin build --release

Testing

pip install pytest
pytest

License

MIT OR Apache-2.0

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pyeryx-0.2.0.tar.gz (12.1 MB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

pyeryx-0.2.0-cp312-abi3-win_amd64.whl (39.0 MB view details)

Uploaded CPython 3.12+Windows x86-64

pyeryx-0.2.0-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (40.0 MB view details)

Uploaded CPython 3.12+manylinux: glibc 2.17+ x86-64

pyeryx-0.2.0-cp312-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (39.3 MB view details)

Uploaded CPython 3.12+manylinux: glibc 2.17+ ARM64

pyeryx-0.2.0-cp312-abi3-macosx_11_0_arm64.whl (39.3 MB view details)

Uploaded CPython 3.12+macOS 11.0+ ARM64

pyeryx-0.2.0-cp312-abi3-macosx_10_12_x86_64.whl (39.3 MB view details)

Uploaded CPython 3.12+macOS 10.12+ x86-64

File details

Details for the file pyeryx-0.2.0.tar.gz.

File metadata

  • Download URL: pyeryx-0.2.0.tar.gz
  • Upload date:
  • Size: 12.1 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pyeryx-0.2.0.tar.gz
Algorithm Hash digest
SHA256 f4ec660a3fb06628c3bc317c088e5e0ab45fc4065c0b00969ea9ac1bb57fd989
MD5 0ccf4fcc741b3afaf77edce89bb131d0
BLAKE2b-256 debe8d39633bac331be7b9b36c883d12364f78647ac0c3495000cb77e90d7096

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyeryx-0.2.0.tar.gz:

Publisher: python-release.yml on eryx-org/eryx

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyeryx-0.2.0-cp312-abi3-win_amd64.whl.

File metadata

  • Download URL: pyeryx-0.2.0-cp312-abi3-win_amd64.whl
  • Upload date:
  • Size: 39.0 MB
  • Tags: CPython 3.12+, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pyeryx-0.2.0-cp312-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 0c3e98a857ccefe7e9b2c72511705ef9bb4d30d447fbe7d7f53e902bd5adc9b3
MD5 54a903383beace00d59ff3a2ff41bda5
BLAKE2b-256 c3568572995cb97289ef50b6f8d142555f19c34071c2fa1d25e6cd56a9339d6d

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyeryx-0.2.0-cp312-abi3-win_amd64.whl:

Publisher: python-release.yml on eryx-org/eryx

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyeryx-0.2.0-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pyeryx-0.2.0-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 e2449cabffc51bd34e4e07d3f257c143db68bc8d4c50aed499877375f64740c8
MD5 9ad86d68122f9ff48dab469cc69f8f61
BLAKE2b-256 1a601267d2a19e923b9ca4d19d93c3755e462bbebda52a425286ea41be3a6d6a

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyeryx-0.2.0-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: python-release.yml on eryx-org/eryx

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyeryx-0.2.0-cp312-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for pyeryx-0.2.0-cp312-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 6cbb414c9b28999d6468841bd992122d893937b4f3eb6ba878fc02586ddd26cc
MD5 34bd9ee6d40ee00cedc8e07888b15a9d
BLAKE2b-256 d6928a9c8f6297a9d2c963fd35f0140e1e9a0079d65e1512130d2737b9835715

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyeryx-0.2.0-cp312-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: python-release.yml on eryx-org/eryx

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyeryx-0.2.0-cp312-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for pyeryx-0.2.0-cp312-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 06b4fa80ffda6ed271c38987a6aa38f9a9ab7f277324e5eceda13c5e51ca2f3b
MD5 e4c004056b356994c238988f49fa87e3
BLAKE2b-256 a1a82dd4d7b2b7d07e145e8402c4a11b341e353910221e7bc4d7c9747421bd16

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyeryx-0.2.0-cp312-abi3-macosx_11_0_arm64.whl:

Publisher: python-release.yml on eryx-org/eryx

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyeryx-0.2.0-cp312-abi3-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for pyeryx-0.2.0-cp312-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 48add014a25e3f4854bc9b0c26998b5627da937b7055da21954a77dfa8032784
MD5 06203a7ab389860b179071ac0df8ced1
BLAKE2b-256 323d7b486269eedcddfe1a3777b6f70754292dbe91b792f28beec621c37216ad

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyeryx-0.2.0-cp312-abi3-macosx_10_12_x86_64.whl:

Publisher: python-release.yml on eryx-org/eryx

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page