cased-sandboxes


Namecased-sandboxes JSON
Version 0.2.3 PyPI version JSON
download
home_pageNone
SummaryUniversal library for AI code execution sandboxes
upload_time2025-10-07 11:03:19
maintainerNone
docs_urlNone
authorNone
requires_python>=3.11
licenseNone
keywords ai cloudflare code-execution daytona e2b modal sandbox vercel
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # sandboxes

Universal library for AI code execution sandboxes.

[![Python Version](https://img.shields.io/badge/python-3.11%2B-blue)](https://www.python.org/downloads/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

## Overview

`sandboxes` provides a unified interface for sandboxed code execution across multiple providers:

- **Current providers**: E2B, Modal, Daytona
- **Experimental**: Cloudflare (requires self-hosted Worker deployment)

Write your code once and switch between providers with a single line change, or let the library automatically select a provider.
Includes a Python API plus full-featured CLI for use from any runtime.

## Installation

Add to your project:

```bash
uv add cased-sandboxes
```

or install with your preferred Python package manager and use the CLI
for any language, e.g.,:

```bash
uv pip install cased-sandboxes
```

## Quick Start

### One-line Execution + Auto-select Provider

```python
import asyncio
from sandboxes import run

async def main():
    # Creates a temporary sandbox, runs the command, then destroys the sandbox
    result = await run("echo 'Hello from sandbox!'")
    print(result.stdout)

    # Behind the scenes, run() does this:
    # 1. Auto-detects available providers (e.g., E2B, Modal, Daytona)
    # 2. Creates a new sandbox with the first available provider
    # 3. Executes your command in that isolated environment
    # 4. Returns the result
    # 5. Automatically destroys the sandbox

asyncio.run(main())
```

### Multiple Commands

```python
import asyncio
from sandboxes import run_many

async def main():
    # Execute multiple commands in one sandbox
    results = await run_many([
        "pip install requests",
        "python -c 'import requests; print(requests.__version__)'"
    ])
    for result in results:
        print(result.stdout)

asyncio.run(main())
```

### Persistent Sandbox Sessions

```python
import asyncio
from sandboxes import Sandbox

async def main():
    async with Sandbox.create() as sandbox:
        # Install dependencies
        await sandbox.execute("pip install numpy pandas")

        # Run your code
        result = await sandbox.execute("python analyze.py")
        print(result.stdout)

        await sandbox.upload("data.csv", "/tmp/data.csv")
        await sandbox.download("/tmp/results.csv", "results.csv")
    # Automatically cleaned up on exit

asyncio.run(main())
```

### Smart Sandbox Reuse

Use `get_or_create` with labels (which can include pre-set unique ids) to re-use particular sandboxes. Useful for agent sessions over time.

```python
import asyncio
from sandboxes import Sandbox

async def main():
    # First call creates a new sandbox
    sandbox1 = await Sandbox.get_or_create(
        labels={"project": "ml-training", "gpu": "true"}
    )

    # Later calls reuse the same sandbox
    sandbox2 = await Sandbox.get_or_create(
        labels={"project": "ml-training", "gpu": "true"}
    )

    assert sandbox1.id == sandbox2.id  # Same sandbox

asyncio.run(main())
```

### Provider Selection with Automatic Failover

```python
import asyncio
from sandboxes import Sandbox, run

async def main():
    # Control where your code runs
    sandbox = await Sandbox.create(
        provider="e2b",  # Try E2B first
        fallback=["modal", "cloudflare", "daytona"],  # Automatic failover
    )

    # The library automatically tries the next provider if one fails
    print(f"Using: {sandbox._provider_name}")

    # Or specify directly with run()
    result = await run("bash my-script.sh", provider="modal")

asyncio.run(main())
```

### Custom Images and Templates

```python
import asyncio
from sandboxes import Sandbox, SandboxConfig
from sandboxes.providers import ModalProvider, E2BProvider, DaytonaProvider

async def main():
    # High-level API - works with any provider
    sandbox = await Sandbox.create(image="python:3.12-slim")

    # Or with specific providers
    daytona_provider = DaytonaProvider()
    config = SandboxConfig(image="daytonaio/ai-test:0.2.3")
    sandbox = await daytona_provider.create_sandbox(config)

asyncio.run(main())

# Via CLI
# sandboxes run "python --version" --image python:3.12-slim
```

## API Reference

### Core Classes

- **`Sandbox`**: High-level interface with automatic provider management
- **`SandboxConfig`**: Configuration for sandbox creation (labels, timeout, image)
- **`ExecutionResult`**: Standardized result object (stdout, stderr, exit_code)
- **`Manager`**: Multi-provider orchestration with failover
- **`SandboxProvider`**: Abstract base class for provider implementations

### Key Methods

```python
# High-level functions
await run(command: str, provider: str = None) -> ExecutionResult
await run_many(commands: list[str], provider: str = None) -> list[ExecutionResult]

# Sandbox methods
await Sandbox.create(provider=None, fallback=None, labels=None, image=None) -> Sandbox
await Sandbox.get_or_create(labels: dict) -> Sandbox
await Sandbox.find(labels: dict) -> Sandbox | None
await sandbox.execute(command: str) -> ExecutionResult
await sandbox.execute_many(commands: list[str]) -> list[ExecutionResult]
await sandbox.stream(command: str) -> AsyncIterator[str]
await sandbox.upload(local_path: str, remote_path: str)
await sandbox.download(remote_path: str, local_path: str)
await sandbox.destroy()
```

## Command Line Interface

`sandboxes` includes a powerful CLI for running code in **any language** from your terminal. Execute TypeScript, Go, Rust, Python, or any other language in isolated sandboxes.
You can call the CLI from any language, or write a wrapper for it.

### Quick Start

```bash
# Run TypeScript from a file
sandboxes run --file script.ts

# Run Go code from stdin
cat main.go | sandboxes run --lang go

# Direct command execution
sandboxes run "python3 -c 'print(sum(range(100)))'"

# Run with specific provider
sandboxes run "python3 --version" --provider e2b

# List all sandboxes
sandboxes list
```

### Commands

#### `run` - Execute Code

```bash
# 1. From file (auto-detects language)
sandboxes run --file script.py
sandboxes run --file main.go

# 2. From stdin/pipe
cat script.py | sandboxes run --lang python
echo 'console.log("Hello!")' | sandboxes run --lang node

# 3. Direct command
sandboxes run "python3 -c 'print(42)'"
```

**Options:**

```bash
# Specify provider
sandboxes run --file app.py -p e2b

# Environment variables
sandboxes run --file script.py -e API_KEY=secret -e DEBUG=1

# Labels for reuse
sandboxes run --file app.py -l project=myapp --reuse

# Keep sandbox (don't auto-destroy)
sandboxes run --file script.py --keep

# Timeout
sandboxes run --file script.sh -t 600
```

Supported languages with auto-detect: `python`, `node/javascript`, `typescript`, `go`, `rust`, `bash/sh`

#### `list` - List Sandboxes

View all active sandboxes:

```bash
# List all sandboxes
sandboxes list

# Filter by provider
sandboxes list -p e2b

# Filter by labels
sandboxes list -l env=prod

# JSON output
sandboxes list --json
```

#### `exec` - Execute in Existing Sandbox

```bash
sandboxes exec sb-abc123 "ls -la" -p modal
sandboxes exec sb-abc123 "python script.py" -p e2b -e DEBUG=1
```

#### `destroy` - Remove Sandbox

```bash
sandboxes destroy sb-abc123 -p e2b
```

#### `providers` - Check Providers

```bash
sandboxes providers
```

#### `test` - Test Provider Connectivity

```bash
sandboxes test          # Test all
sandboxes test -p e2b   # Test specific
```

### CLI Examples

#### Development Workflow

```bash
# Create development sandbox
sandboxes run "git clone https://github.com/user/repo.git /app" \
  -l project=myapp \
  -l env=dev \
  --keep

# List to get sandbox ID
sandboxes list -l project=myapp

# Run commands in the sandbox
sandboxes exec sb-abc123 "cd /app && npm install" -p e2b
sandboxes exec sb-abc123 "cd /app && npm test" -p e2b

# Cleanup when done
sandboxes destroy sb-abc123 -p e2b
```

#### Multi-Language Code Testing

```bash
# TypeScript
echo 'const x: number = 42; console.log(x)' > test.ts
sandboxes run --file test.ts

# Go with automatic dependency installation
sandboxes run --file main.go --deps

# Go from stdin
cat main.go | sandboxes run --lang go

# Python from remote URL
curl -s https://example.com/script.py | sandboxes run --lang python
```

**Auto-Dependency Installation (`golang` only for now):** Use `--deps` to automatically install dependencies from `go.mod` (located in the same directory as your code file). The CLI will upload `go.mod` and `go.sum` (if present) and run `go mod download` before executing your code.


## Provider Configuration

You'll need API keys from one of the supported providers.

### Automatic Configuration

The library automatically detects available providers from environment variables:

```bash
# Set any of these environment variables:
export E2B_API_KEY="..."
export MODAL_TOKEN_ID="..."  # Or use `modal token set`
export DAYTONA_API_KEY="..."
export CLOUDFLARE_SANDBOX_BASE_URL="https://your-worker.workers.dev"
export CLOUDFLARE_API_TOKEN="..."
```

Then just use:
```python
import asyncio
from sandboxes import Sandbox

async def main():
    sandbox = await Sandbox.create()  # Auto-selects first available provider

asyncio.run(main())
```

#### How Auto-Detection Works

When you call `Sandbox.create()` or `run()`, the library checks for providers in this priority order:

1. **Daytona** - Looks for `DAYTONA_API_KEY`
2. **E2B** - Looks for `E2B_API_KEY`
3. **Modal** - Looks for `~/.modal.toml` or `MODAL_TOKEN_ID`
4. **Cloudflare** *(experimental)* - Looks for `CLOUDFLARE_SANDBOX_BASE_URL` + `CLOUDFLARE_API_TOKEN`

**The first provider with valid credentials becomes the default.** Cloudflare requires deploying your own Worker.

#### Customizing the Default Provider

You can override the auto-detected default:

```python
from sandboxes import Sandbox

# Option 1: Set default provider explicitly
Sandbox.configure(default_provider="modal")

# Option 2: Specify provider per call
sandbox = await Sandbox.create(provider="e2b")

# Option 3: Use fallback chain
sandbox = await Sandbox.create(
    provider="daytona",
    fallback=["e2b", "modal"]
)

# Check which providers are available
Sandbox._ensure_manager()
print(f"Available: {list(Sandbox._manager.providers.keys())}")
print(f"Default: {Sandbox._manager.default_provider}")
```

### Manual Provider Configuration

For more control, you can configure providers manually:

```python
from sandboxes import Sandbox

# Configure providers programmatically
Sandbox.configure(
    e2b_api_key="your-key",
    cloudflare_config={
        "base_url": "https://your-worker.workers.dev",
        "api_token": "your-token",
    },
    default_provider="e2b"
)
```

### Direct Provider Usage (Low-Level API)

For advanced use cases, you can work with providers directly:

```python
from sandboxes.providers import (
    E2BProvider,
    ModalProvider,
    DaytonaProvider,
    CloudflareProvider,
)

# E2B - Uses E2B_API_KEY env var
provider = E2BProvider()

# Modal - Uses ~/.modal.toml for auth
provider = ModalProvider()

# Daytona - Uses DAYTONA_API_KEY env var
provider = DaytonaProvider()

# Cloudflare - Requires base_url and token
provider = CloudflareProvider(
    base_url="https://your-worker.workers.dev",
    api_token="your-token",
)
```

Each provider requires appropriate authentication:
- **E2B**: Set `E2B_API_KEY` environment variable
- **Modal**: Run `modal token set` to configure
- **Daytona**: Set `DAYTONA_API_KEY` environment variable
- **Cloudflare** *(experimental)*: Deploy the [Cloudflare sandbox Worker](https://github.com/cloudflare/sandbox-sdk) and set `CLOUDFLARE_SANDBOX_BASE_URL`, `CLOUDFLARE_API_TOKEN`, and (optionally) `CLOUDFLARE_ACCOUNT_ID`

> **Cloudflare setup tips (experimental)**
>
> ⚠️ **Note**: Cloudflare support is experimental and requires self-hosting a Worker.
>
> 1. Clone the Cloudflare `sandbox-sdk` repository and deploy the `examples/basic` Worker with `wrangler`.
> 2. Provision a Workers Paid plan and enable Containers + Docker Hub registry for your account.
> 3. Define a secret (e.g. `SANDBOX_API_TOKEN`) in Wrangler and reuse the same value for `CLOUDFLARE_API_TOKEN` locally.
> 4. Set `CLOUDFLARE_SANDBOX_BASE_URL` to the Worker URL (e.g. `https://cf-sandbox.your-subdomain.workers.dev`).

## Advanced Usage

### Multi-Provider Orchestration

```python
import asyncio
from sandboxes import Manager, SandboxConfig
from sandboxes.providers import E2BProvider, ModalProvider, DaytonaProvider, CloudflareProvider

async def main():
    # Initialize manager and register providers
    manager = Manager(default_provider="e2b")

    manager.register_provider("e2b", E2BProvider, {})
    manager.register_provider("modal", ModalProvider, {})
    manager.register_provider("daytona", DaytonaProvider, {})
    manager.register_provider(
        "cloudflare",
        CloudflareProvider,
        {"base_url": "https://your-worker.workers.dev", "api_token": "..."}
    )

    # Manager handles failover automatically
    sandbox = await manager.create_sandbox(
        SandboxConfig(labels={"task": "test"}),
        fallback_providers=["modal", "daytona"]  # Try these if primary fails
    )

asyncio.run(main())
```

### Sandbox Reuse (Provider-Level)

For advanced control, work directly with providers instead of the high-level `Sandbox` API:

```python
import asyncio
from sandboxes import SandboxConfig
from sandboxes.providers import E2BProvider

async def main():
    provider = E2BProvider()

    # Sandboxes can be reused based on labels
    config = SandboxConfig(
        labels={"project": "ml-training", "gpu": "true"}
    )

    # This will find existing sandbox or create new one
    sandbox = await provider.get_or_create_sandbox(config)

    # Later in another process...
    # This will find the same sandbox
    sandbox = await provider.find_sandbox({"project": "ml-training"})

asyncio.run(main())
```

### Streaming Execution

```python
import asyncio
from sandboxes.providers import E2BProvider

async def main():
    provider = E2BProvider()
    sandbox = await provider.create_sandbox()

    # Stream output as it's generated
    async for chunk in provider.stream_execution(
        sandbox.id,
        "for i in range(10): print(i); time.sleep(1)"
    ):
        print(chunk, end="")

asyncio.run(main())
```

### Connection Pooling

```python
import asyncio
from sandboxes import SandboxConfig
from sandboxes.pool import ConnectionPool
from sandboxes.providers import E2BProvider

async def main():
    # Create a connection pool for better performance
    pool = ConnectionPool(
        provider=E2BProvider(),
        max_connections=10,
        max_idle_time=300,
        ttl=3600
    )

    # Get or create connection
    conn = await pool.get_or_create(
        SandboxConfig(labels={"pool": "ml"})
    )

    # Return to pool when done
    await pool.release(conn)

asyncio.run(main())
```

## Architecture

### Core Components

- **`Sandbox`**: High-level interface with automatic provider management
- **`SandboxProvider`**: Abstract base class for all providers
- **`SandboxConfig`**: Configuration for sandbox creation
- **`ExecutionResult`**: Standardized execution results
- **`Manager`**: Multi-provider orchestration
- **`ConnectionPool`**: Connection pooling with TTL
- **`RetryPolicy`**: Configurable retry logic
- **`CircuitBreaker`**: Fault tolerance


## Environment Variables

```bash
# E2B
export E2B_API_KEY="e2b_..."

# Daytona
export DAYTONA_API_KEY="dtn_..."

# Modal (or use modal token set)
export MODAL_TOKEN_ID="..."
export MODAL_TOKEN_SECRET="..."

# Cloudflare
export CLOUDFLARE_SANDBOX_BASE_URL="https://your-worker.workers.dev"
export CLOUDFLARE_API_TOKEN="..."
export CLOUDFLARE_ACCOUNT_ID="..."  # Optional
```

## Multi-Language Support

While `sandboxes` is a Python library, it can execute code in **any language** available in the sandbox environment. The sandboxes run standard Linux containers, so you can execute TypeScript, Go, Rust, Java, or any other language.

### Running TypeScript

```python
import asyncio
from sandboxes import Sandbox

async def run_typescript():
    """Execute TypeScript code in a sandbox."""
    async with Sandbox.create() as sandbox:
        # TypeScript code
        ts_code = '''
const greeting: string = "Hello from TypeScript!";
const numbers: number[] = [1, 2, 3, 4, 5];
const sum: number = numbers.reduce((a, b) => a + b, 0);

console.log(greeting);
console.log(`Sum of numbers: ${sum}`);
console.log(`Type system ensures safety at compile time`);
'''

        # Run with ts-node (npx auto-installs)
        result = await sandbox.execute(
            f"echo '{ts_code}' > /tmp/app.ts && npx -y ts-node /tmp/app.ts"
        )

        print(result.stdout)
        # Output:
        # Hello from TypeScript!
        # Sum of numbers: 15
        # Type system ensures safety at compile time

asyncio.run(run_typescript())
```

### Running Go

```python
import asyncio
from sandboxes import Sandbox

async def run_go():
    """Execute Go code in a sandbox."""
    async with Sandbox.create() as sandbox:
        # Go code
        go_code = '''package main

import (
    "fmt"
    "math"
)

func main() {
    fmt.Println("Hello from Go!")

    // Calculate fibonacci
    n := 10
    fmt.Printf("Fibonacci(%d) = %d\\n", n, fibonacci(n))

    // Demonstrate type safety
    radius := 5.0
    area := math.Pi * radius * radius
    fmt.Printf("Circle area (r=%.1f): %.2f\\n", radius, area)
}

func fibonacci(n int) int {
    if n <= 1 {
        return n
    }
    return fibonacci(n-1) + fibonacci(n-2)
}
'''

        # Save and run Go code
        result = await sandbox.execute(f'''
cat > /tmp/main.go << 'EOF'
{go_code}
EOF
go run /tmp/main.go
''')

        print(result.stdout)
        # Output:
        # Hello from Go!
        # Fibonacci(10) = 55
        # Circle area (r=5.0): 78.54

asyncio.run(run_go())
```

## Common Use Cases

### AI Agent Code Execution

```python
import asyncio
from sandboxes import Sandbox

async def execute_agent_code(code: str, language: str = "python"):
    """Safely execute AI-generated code."""
    async with Sandbox.create() as sandbox:
        # Install any required packages first
        if "import" in code:
            # Extract and install imports (simplified)
            await sandbox.execute("pip install requests numpy")

        # Execute the code
        result = await sandbox.execute(f"{language} -c '{code}'")

        if result.exit_code != 0:
            return f"Error: {result.stderr}"
        return result.stdout

# Example usage
asyncio.run(execute_agent_code("print('Hello!')", "python"))
```

### Data Processing Pipeline

```python
import asyncio
from sandboxes import Sandbox

async def process_dataset(dataset_url: str):
    """Process data in isolated environment."""
    async with Sandbox.create(labels={"task": "data-pipeline"}) as sandbox:
        # Setup environment
        await sandbox.execute_many([
            "pip install pandas numpy scikit-learn",
            f"wget {dataset_url} -O data.csv"
        ])

        # Upload processing script
        await sandbox.upload("process.py", "/tmp/process.py")

        # Run processing with streaming output
        async for output in sandbox.stream("python /tmp/process.py"):
            print(output, end="")

        # Download results
        await sandbox.download("/tmp/results.csv", "results.csv")

# Example usage
asyncio.run(process_dataset("https://example.com/data.csv"))
```

### Code Testing and Validation

```python
import asyncio
from sandboxes import Sandbox

async def test_solution(code: str, test_cases: list):
    """Test code against multiple test cases."""
    results = []

    async with Sandbox.create() as sandbox:
        # Save the code
        await sandbox.upload("solution.py", "/tmp/solution.py")

        # Run each test case
        for i, test in enumerate(test_cases):
            result = await sandbox.execute(
                f"python /tmp/solution.py < {test['input']}"
            )
            results.append({
                "test": i + 1,
                "passed": result.stdout.strip() == test['expected'],
                "output": result.stdout.strip()
            })

    return results

# Example usage
asyncio.run(test_solution("print(sum(map(int, input().split())))", [
    {"input": "1 2 3", "expected": "6"}
]))
```

## Troubleshooting

### No Providers Available

```python
# If you see: "No provider specified and no default provider set"

# Solution 1: Set environment variables
export E2B_API_KEY="your-key"

# Solution 2: Configure manually
from sandboxes import Sandbox
Sandbox.configure(e2b_api_key="your-key")

# Solution 3: Use low-level API
from sandboxes.providers import E2BProvider
provider = E2BProvider(api_key="your-key")
```

### Provider Failures

```python
import asyncio
from sandboxes import Sandbox
from sandboxes.exceptions import ProviderError

async def main():
    # Enable automatic failover
    sandbox = await Sandbox.create(
        provider="e2b",
        fallback=["modal", "cloudflare", "daytona"]
    )

    # Or handle errors manually
    try:
        sandbox = await Sandbox.create(provider="e2b")
    except ProviderError:
        sandbox = await Sandbox.create(provider="modal")

asyncio.run(main())
```

### Debugging

```python
import asyncio
import logging
from sandboxes import Sandbox

async def main():
    # Enable debug logging
    logging.basicConfig(level=logging.DEBUG)

    # Check provider health
    Sandbox._ensure_manager()
    for name, provider in Sandbox._manager.providers.items():
        health = await provider.health_check()
        print(f"{name}: {'✅' if health else '❌'}")

asyncio.run(main())
```

## Security Disclosure

We take security seriously. If you discover a security vulnerability in this library or any of its dependencies, please report it responsibly.

**Responsible Disclosure:**
- Email security reports to: **ted@cased.com**
- Include a detailed description of the vulnerability
- Provide steps to reproduce if possible
- Allow reasonable time for a fix before public disclosure

We will acknowledge your report within 48 hours and work with you to address the issue.

## License

MIT License - see [LICENSE](LICENSE) file for details.
## Acknowledgments

Built by [Cased](https://cased.com)

Special thanks to the teams at E2B, Modal, Daytona, and Cloudflare for their excellent sandbox platforms.

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "cased-sandboxes",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.11",
    "maintainer_email": null,
    "keywords": "ai, cloudflare, code-execution, daytona, e2b, modal, sandbox, vercel",
    "author": null,
    "author_email": "Sandboxes Contributors <ted@cased.com>",
    "download_url": "https://files.pythonhosted.org/packages/50/2d/ab875465c75d8abe0949216c2fcd2d3736cff3eb4c219b25ff480a4434cb/cased_sandboxes-0.2.3.tar.gz",
    "platform": null,
    "description": "# sandboxes\n\nUniversal library for AI code execution sandboxes.\n\n[![Python Version](https://img.shields.io/badge/python-3.11%2B-blue)](https://www.python.org/downloads/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\n## Overview\n\n`sandboxes` provides a unified interface for sandboxed code execution across multiple providers:\n\n- **Current providers**: E2B, Modal, Daytona\n- **Experimental**: Cloudflare (requires self-hosted Worker deployment)\n\nWrite your code once and switch between providers with a single line change, or let the library automatically select a provider.\nIncludes a Python API plus full-featured CLI for use from any runtime.\n\n## Installation\n\nAdd to your project:\n\n```bash\nuv add cased-sandboxes\n```\n\nor install with your preferred Python package manager and use the CLI\nfor any language, e.g.,:\n\n```bash\nuv pip install cased-sandboxes\n```\n\n## Quick Start\n\n### One-line Execution + Auto-select Provider\n\n```python\nimport asyncio\nfrom sandboxes import run\n\nasync def main():\n    # Creates a temporary sandbox, runs the command, then destroys the sandbox\n    result = await run(\"echo 'Hello from sandbox!'\")\n    print(result.stdout)\n\n    # Behind the scenes, run() does this:\n    # 1. Auto-detects available providers (e.g., E2B, Modal, Daytona)\n    # 2. Creates a new sandbox with the first available provider\n    # 3. Executes your command in that isolated environment\n    # 4. Returns the result\n    # 5. Automatically destroys the sandbox\n\nasyncio.run(main())\n```\n\n### Multiple Commands\n\n```python\nimport asyncio\nfrom sandboxes import run_many\n\nasync def main():\n    # Execute multiple commands in one sandbox\n    results = await run_many([\n        \"pip install requests\",\n        \"python -c 'import requests; print(requests.__version__)'\"\n    ])\n    for result in results:\n        print(result.stdout)\n\nasyncio.run(main())\n```\n\n### Persistent Sandbox Sessions\n\n```python\nimport asyncio\nfrom sandboxes import Sandbox\n\nasync def main():\n    async with Sandbox.create() as sandbox:\n        # Install dependencies\n        await sandbox.execute(\"pip install numpy pandas\")\n\n        # Run your code\n        result = await sandbox.execute(\"python analyze.py\")\n        print(result.stdout)\n\n        await sandbox.upload(\"data.csv\", \"/tmp/data.csv\")\n        await sandbox.download(\"/tmp/results.csv\", \"results.csv\")\n    # Automatically cleaned up on exit\n\nasyncio.run(main())\n```\n\n### Smart Sandbox Reuse\n\nUse `get_or_create` with labels (which can include pre-set unique ids) to re-use particular sandboxes. Useful for agent sessions over time.\n\n```python\nimport asyncio\nfrom sandboxes import Sandbox\n\nasync def main():\n    # First call creates a new sandbox\n    sandbox1 = await Sandbox.get_or_create(\n        labels={\"project\": \"ml-training\", \"gpu\": \"true\"}\n    )\n\n    # Later calls reuse the same sandbox\n    sandbox2 = await Sandbox.get_or_create(\n        labels={\"project\": \"ml-training\", \"gpu\": \"true\"}\n    )\n\n    assert sandbox1.id == sandbox2.id  # Same sandbox\n\nasyncio.run(main())\n```\n\n### Provider Selection with Automatic Failover\n\n```python\nimport asyncio\nfrom sandboxes import Sandbox, run\n\nasync def main():\n    # Control where your code runs\n    sandbox = await Sandbox.create(\n        provider=\"e2b\",  # Try E2B first\n        fallback=[\"modal\", \"cloudflare\", \"daytona\"],  # Automatic failover\n    )\n\n    # The library automatically tries the next provider if one fails\n    print(f\"Using: {sandbox._provider_name}\")\n\n    # Or specify directly with run()\n    result = await run(\"bash my-script.sh\", provider=\"modal\")\n\nasyncio.run(main())\n```\n\n### Custom Images and Templates\n\n```python\nimport asyncio\nfrom sandboxes import Sandbox, SandboxConfig\nfrom sandboxes.providers import ModalProvider, E2BProvider, DaytonaProvider\n\nasync def main():\n    # High-level API - works with any provider\n    sandbox = await Sandbox.create(image=\"python:3.12-slim\")\n\n    # Or with specific providers\n    daytona_provider = DaytonaProvider()\n    config = SandboxConfig(image=\"daytonaio/ai-test:0.2.3\")\n    sandbox = await daytona_provider.create_sandbox(config)\n\nasyncio.run(main())\n\n# Via CLI\n# sandboxes run \"python --version\" --image python:3.12-slim\n```\n\n## API Reference\n\n### Core Classes\n\n- **`Sandbox`**: High-level interface with automatic provider management\n- **`SandboxConfig`**: Configuration for sandbox creation (labels, timeout, image)\n- **`ExecutionResult`**: Standardized result object (stdout, stderr, exit_code)\n- **`Manager`**: Multi-provider orchestration with failover\n- **`SandboxProvider`**: Abstract base class for provider implementations\n\n### Key Methods\n\n```python\n# High-level functions\nawait run(command: str, provider: str = None) -> ExecutionResult\nawait run_many(commands: list[str], provider: str = None) -> list[ExecutionResult]\n\n# Sandbox methods\nawait Sandbox.create(provider=None, fallback=None, labels=None, image=None) -> Sandbox\nawait Sandbox.get_or_create(labels: dict) -> Sandbox\nawait Sandbox.find(labels: dict) -> Sandbox | None\nawait sandbox.execute(command: str) -> ExecutionResult\nawait sandbox.execute_many(commands: list[str]) -> list[ExecutionResult]\nawait sandbox.stream(command: str) -> AsyncIterator[str]\nawait sandbox.upload(local_path: str, remote_path: str)\nawait sandbox.download(remote_path: str, local_path: str)\nawait sandbox.destroy()\n```\n\n## Command Line Interface\n\n`sandboxes` includes a powerful CLI for running code in **any language** from your terminal. Execute TypeScript, Go, Rust, Python, or any other language in isolated sandboxes.\nYou can call the CLI from any language, or write a wrapper for it.\n\n### Quick Start\n\n```bash\n# Run TypeScript from a file\nsandboxes run --file script.ts\n\n# Run Go code from stdin\ncat main.go | sandboxes run --lang go\n\n# Direct command execution\nsandboxes run \"python3 -c 'print(sum(range(100)))'\"\n\n# Run with specific provider\nsandboxes run \"python3 --version\" --provider e2b\n\n# List all sandboxes\nsandboxes list\n```\n\n### Commands\n\n#### `run` - Execute Code\n\n```bash\n# 1. From file (auto-detects language)\nsandboxes run --file script.py\nsandboxes run --file main.go\n\n# 2. From stdin/pipe\ncat script.py | sandboxes run --lang python\necho 'console.log(\"Hello!\")' | sandboxes run --lang node\n\n# 3. Direct command\nsandboxes run \"python3 -c 'print(42)'\"\n```\n\n**Options:**\n\n```bash\n# Specify provider\nsandboxes run --file app.py -p e2b\n\n# Environment variables\nsandboxes run --file script.py -e API_KEY=secret -e DEBUG=1\n\n# Labels for reuse\nsandboxes run --file app.py -l project=myapp --reuse\n\n# Keep sandbox (don't auto-destroy)\nsandboxes run --file script.py --keep\n\n# Timeout\nsandboxes run --file script.sh -t 600\n```\n\nSupported languages with auto-detect: `python`, `node/javascript`, `typescript`, `go`, `rust`, `bash/sh`\n\n#### `list` - List Sandboxes\n\nView all active sandboxes:\n\n```bash\n# List all sandboxes\nsandboxes list\n\n# Filter by provider\nsandboxes list -p e2b\n\n# Filter by labels\nsandboxes list -l env=prod\n\n# JSON output\nsandboxes list --json\n```\n\n#### `exec` - Execute in Existing Sandbox\n\n```bash\nsandboxes exec sb-abc123 \"ls -la\" -p modal\nsandboxes exec sb-abc123 \"python script.py\" -p e2b -e DEBUG=1\n```\n\n#### `destroy` - Remove Sandbox\n\n```bash\nsandboxes destroy sb-abc123 -p e2b\n```\n\n#### `providers` - Check Providers\n\n```bash\nsandboxes providers\n```\n\n#### `test` - Test Provider Connectivity\n\n```bash\nsandboxes test          # Test all\nsandboxes test -p e2b   # Test specific\n```\n\n### CLI Examples\n\n#### Development Workflow\n\n```bash\n# Create development sandbox\nsandboxes run \"git clone https://github.com/user/repo.git /app\" \\\n  -l project=myapp \\\n  -l env=dev \\\n  --keep\n\n# List to get sandbox ID\nsandboxes list -l project=myapp\n\n# Run commands in the sandbox\nsandboxes exec sb-abc123 \"cd /app && npm install\" -p e2b\nsandboxes exec sb-abc123 \"cd /app && npm test\" -p e2b\n\n# Cleanup when done\nsandboxes destroy sb-abc123 -p e2b\n```\n\n#### Multi-Language Code Testing\n\n```bash\n# TypeScript\necho 'const x: number = 42; console.log(x)' > test.ts\nsandboxes run --file test.ts\n\n# Go with automatic dependency installation\nsandboxes run --file main.go --deps\n\n# Go from stdin\ncat main.go | sandboxes run --lang go\n\n# Python from remote URL\ncurl -s https://example.com/script.py | sandboxes run --lang python\n```\n\n**Auto-Dependency Installation (`golang` only for now):** Use `--deps` to automatically install dependencies from `go.mod` (located in the same directory as your code file). The CLI will upload `go.mod` and `go.sum` (if present) and run `go mod download` before executing your code.\n\n\n## Provider Configuration\n\nYou'll need API keys from one of the supported providers.\n\n### Automatic Configuration\n\nThe library automatically detects available providers from environment variables:\n\n```bash\n# Set any of these environment variables:\nexport E2B_API_KEY=\"...\"\nexport MODAL_TOKEN_ID=\"...\"  # Or use `modal token set`\nexport DAYTONA_API_KEY=\"...\"\nexport CLOUDFLARE_SANDBOX_BASE_URL=\"https://your-worker.workers.dev\"\nexport CLOUDFLARE_API_TOKEN=\"...\"\n```\n\nThen just use:\n```python\nimport asyncio\nfrom sandboxes import Sandbox\n\nasync def main():\n    sandbox = await Sandbox.create()  # Auto-selects first available provider\n\nasyncio.run(main())\n```\n\n#### How Auto-Detection Works\n\nWhen you call `Sandbox.create()` or `run()`, the library checks for providers in this priority order:\n\n1. **Daytona** - Looks for `DAYTONA_API_KEY`\n2. **E2B** - Looks for `E2B_API_KEY`\n3. **Modal** - Looks for `~/.modal.toml` or `MODAL_TOKEN_ID`\n4. **Cloudflare** *(experimental)* - Looks for `CLOUDFLARE_SANDBOX_BASE_URL` + `CLOUDFLARE_API_TOKEN`\n\n**The first provider with valid credentials becomes the default.** Cloudflare requires deploying your own Worker.\n\n#### Customizing the Default Provider\n\nYou can override the auto-detected default:\n\n```python\nfrom sandboxes import Sandbox\n\n# Option 1: Set default provider explicitly\nSandbox.configure(default_provider=\"modal\")\n\n# Option 2: Specify provider per call\nsandbox = await Sandbox.create(provider=\"e2b\")\n\n# Option 3: Use fallback chain\nsandbox = await Sandbox.create(\n    provider=\"daytona\",\n    fallback=[\"e2b\", \"modal\"]\n)\n\n# Check which providers are available\nSandbox._ensure_manager()\nprint(f\"Available: {list(Sandbox._manager.providers.keys())}\")\nprint(f\"Default: {Sandbox._manager.default_provider}\")\n```\n\n### Manual Provider Configuration\n\nFor more control, you can configure providers manually:\n\n```python\nfrom sandboxes import Sandbox\n\n# Configure providers programmatically\nSandbox.configure(\n    e2b_api_key=\"your-key\",\n    cloudflare_config={\n        \"base_url\": \"https://your-worker.workers.dev\",\n        \"api_token\": \"your-token\",\n    },\n    default_provider=\"e2b\"\n)\n```\n\n### Direct Provider Usage (Low-Level API)\n\nFor advanced use cases, you can work with providers directly:\n\n```python\nfrom sandboxes.providers import (\n    E2BProvider,\n    ModalProvider,\n    DaytonaProvider,\n    CloudflareProvider,\n)\n\n# E2B - Uses E2B_API_KEY env var\nprovider = E2BProvider()\n\n# Modal - Uses ~/.modal.toml for auth\nprovider = ModalProvider()\n\n# Daytona - Uses DAYTONA_API_KEY env var\nprovider = DaytonaProvider()\n\n# Cloudflare - Requires base_url and token\nprovider = CloudflareProvider(\n    base_url=\"https://your-worker.workers.dev\",\n    api_token=\"your-token\",\n)\n```\n\nEach provider requires appropriate authentication:\n- **E2B**: Set `E2B_API_KEY` environment variable\n- **Modal**: Run `modal token set` to configure\n- **Daytona**: Set `DAYTONA_API_KEY` environment variable\n- **Cloudflare** *(experimental)*: Deploy the [Cloudflare sandbox Worker](https://github.com/cloudflare/sandbox-sdk) and set `CLOUDFLARE_SANDBOX_BASE_URL`, `CLOUDFLARE_API_TOKEN`, and (optionally) `CLOUDFLARE_ACCOUNT_ID`\n\n> **Cloudflare setup tips (experimental)**\n>\n> \u26a0\ufe0f **Note**: Cloudflare support is experimental and requires self-hosting a Worker.\n>\n> 1. Clone the Cloudflare `sandbox-sdk` repository and deploy the `examples/basic` Worker with `wrangler`.\n> 2. Provision a Workers Paid plan and enable Containers + Docker Hub registry for your account.\n> 3. Define a secret (e.g. `SANDBOX_API_TOKEN`) in Wrangler and reuse the same value for `CLOUDFLARE_API_TOKEN` locally.\n> 4. Set `CLOUDFLARE_SANDBOX_BASE_URL` to the Worker URL (e.g. `https://cf-sandbox.your-subdomain.workers.dev`).\n\n## Advanced Usage\n\n### Multi-Provider Orchestration\n\n```python\nimport asyncio\nfrom sandboxes import Manager, SandboxConfig\nfrom sandboxes.providers import E2BProvider, ModalProvider, DaytonaProvider, CloudflareProvider\n\nasync def main():\n    # Initialize manager and register providers\n    manager = Manager(default_provider=\"e2b\")\n\n    manager.register_provider(\"e2b\", E2BProvider, {})\n    manager.register_provider(\"modal\", ModalProvider, {})\n    manager.register_provider(\"daytona\", DaytonaProvider, {})\n    manager.register_provider(\n        \"cloudflare\",\n        CloudflareProvider,\n        {\"base_url\": \"https://your-worker.workers.dev\", \"api_token\": \"...\"}\n    )\n\n    # Manager handles failover automatically\n    sandbox = await manager.create_sandbox(\n        SandboxConfig(labels={\"task\": \"test\"}),\n        fallback_providers=[\"modal\", \"daytona\"]  # Try these if primary fails\n    )\n\nasyncio.run(main())\n```\n\n### Sandbox Reuse (Provider-Level)\n\nFor advanced control, work directly with providers instead of the high-level `Sandbox` API:\n\n```python\nimport asyncio\nfrom sandboxes import SandboxConfig\nfrom sandboxes.providers import E2BProvider\n\nasync def main():\n    provider = E2BProvider()\n\n    # Sandboxes can be reused based on labels\n    config = SandboxConfig(\n        labels={\"project\": \"ml-training\", \"gpu\": \"true\"}\n    )\n\n    # This will find existing sandbox or create new one\n    sandbox = await provider.get_or_create_sandbox(config)\n\n    # Later in another process...\n    # This will find the same sandbox\n    sandbox = await provider.find_sandbox({\"project\": \"ml-training\"})\n\nasyncio.run(main())\n```\n\n### Streaming Execution\n\n```python\nimport asyncio\nfrom sandboxes.providers import E2BProvider\n\nasync def main():\n    provider = E2BProvider()\n    sandbox = await provider.create_sandbox()\n\n    # Stream output as it's generated\n    async for chunk in provider.stream_execution(\n        sandbox.id,\n        \"for i in range(10): print(i); time.sleep(1)\"\n    ):\n        print(chunk, end=\"\")\n\nasyncio.run(main())\n```\n\n### Connection Pooling\n\n```python\nimport asyncio\nfrom sandboxes import SandboxConfig\nfrom sandboxes.pool import ConnectionPool\nfrom sandboxes.providers import E2BProvider\n\nasync def main():\n    # Create a connection pool for better performance\n    pool = ConnectionPool(\n        provider=E2BProvider(),\n        max_connections=10,\n        max_idle_time=300,\n        ttl=3600\n    )\n\n    # Get or create connection\n    conn = await pool.get_or_create(\n        SandboxConfig(labels={\"pool\": \"ml\"})\n    )\n\n    # Return to pool when done\n    await pool.release(conn)\n\nasyncio.run(main())\n```\n\n## Architecture\n\n### Core Components\n\n- **`Sandbox`**: High-level interface with automatic provider management\n- **`SandboxProvider`**: Abstract base class for all providers\n- **`SandboxConfig`**: Configuration for sandbox creation\n- **`ExecutionResult`**: Standardized execution results\n- **`Manager`**: Multi-provider orchestration\n- **`ConnectionPool`**: Connection pooling with TTL\n- **`RetryPolicy`**: Configurable retry logic\n- **`CircuitBreaker`**: Fault tolerance\n\n\n## Environment Variables\n\n```bash\n# E2B\nexport E2B_API_KEY=\"e2b_...\"\n\n# Daytona\nexport DAYTONA_API_KEY=\"dtn_...\"\n\n# Modal (or use modal token set)\nexport MODAL_TOKEN_ID=\"...\"\nexport MODAL_TOKEN_SECRET=\"...\"\n\n# Cloudflare\nexport CLOUDFLARE_SANDBOX_BASE_URL=\"https://your-worker.workers.dev\"\nexport CLOUDFLARE_API_TOKEN=\"...\"\nexport CLOUDFLARE_ACCOUNT_ID=\"...\"  # Optional\n```\n\n## Multi-Language Support\n\nWhile `sandboxes` is a Python library, it can execute code in **any language** available in the sandbox environment. The sandboxes run standard Linux containers, so you can execute TypeScript, Go, Rust, Java, or any other language.\n\n### Running TypeScript\n\n```python\nimport asyncio\nfrom sandboxes import Sandbox\n\nasync def run_typescript():\n    \"\"\"Execute TypeScript code in a sandbox.\"\"\"\n    async with Sandbox.create() as sandbox:\n        # TypeScript code\n        ts_code = '''\nconst greeting: string = \"Hello from TypeScript!\";\nconst numbers: number[] = [1, 2, 3, 4, 5];\nconst sum: number = numbers.reduce((a, b) => a + b, 0);\n\nconsole.log(greeting);\nconsole.log(`Sum of numbers: ${sum}`);\nconsole.log(`Type system ensures safety at compile time`);\n'''\n\n        # Run with ts-node (npx auto-installs)\n        result = await sandbox.execute(\n            f\"echo '{ts_code}' > /tmp/app.ts && npx -y ts-node /tmp/app.ts\"\n        )\n\n        print(result.stdout)\n        # Output:\n        # Hello from TypeScript!\n        # Sum of numbers: 15\n        # Type system ensures safety at compile time\n\nasyncio.run(run_typescript())\n```\n\n### Running Go\n\n```python\nimport asyncio\nfrom sandboxes import Sandbox\n\nasync def run_go():\n    \"\"\"Execute Go code in a sandbox.\"\"\"\n    async with Sandbox.create() as sandbox:\n        # Go code\n        go_code = '''package main\n\nimport (\n    \"fmt\"\n    \"math\"\n)\n\nfunc main() {\n    fmt.Println(\"Hello from Go!\")\n\n    // Calculate fibonacci\n    n := 10\n    fmt.Printf(\"Fibonacci(%d) = %d\\\\n\", n, fibonacci(n))\n\n    // Demonstrate type safety\n    radius := 5.0\n    area := math.Pi * radius * radius\n    fmt.Printf(\"Circle area (r=%.1f): %.2f\\\\n\", radius, area)\n}\n\nfunc fibonacci(n int) int {\n    if n <= 1 {\n        return n\n    }\n    return fibonacci(n-1) + fibonacci(n-2)\n}\n'''\n\n        # Save and run Go code\n        result = await sandbox.execute(f'''\ncat > /tmp/main.go << 'EOF'\n{go_code}\nEOF\ngo run /tmp/main.go\n''')\n\n        print(result.stdout)\n        # Output:\n        # Hello from Go!\n        # Fibonacci(10) = 55\n        # Circle area (r=5.0): 78.54\n\nasyncio.run(run_go())\n```\n\n## Common Use Cases\n\n### AI Agent Code Execution\n\n```python\nimport asyncio\nfrom sandboxes import Sandbox\n\nasync def execute_agent_code(code: str, language: str = \"python\"):\n    \"\"\"Safely execute AI-generated code.\"\"\"\n    async with Sandbox.create() as sandbox:\n        # Install any required packages first\n        if \"import\" in code:\n            # Extract and install imports (simplified)\n            await sandbox.execute(\"pip install requests numpy\")\n\n        # Execute the code\n        result = await sandbox.execute(f\"{language} -c '{code}'\")\n\n        if result.exit_code != 0:\n            return f\"Error: {result.stderr}\"\n        return result.stdout\n\n# Example usage\nasyncio.run(execute_agent_code(\"print('Hello!')\", \"python\"))\n```\n\n### Data Processing Pipeline\n\n```python\nimport asyncio\nfrom sandboxes import Sandbox\n\nasync def process_dataset(dataset_url: str):\n    \"\"\"Process data in isolated environment.\"\"\"\n    async with Sandbox.create(labels={\"task\": \"data-pipeline\"}) as sandbox:\n        # Setup environment\n        await sandbox.execute_many([\n            \"pip install pandas numpy scikit-learn\",\n            f\"wget {dataset_url} -O data.csv\"\n        ])\n\n        # Upload processing script\n        await sandbox.upload(\"process.py\", \"/tmp/process.py\")\n\n        # Run processing with streaming output\n        async for output in sandbox.stream(\"python /tmp/process.py\"):\n            print(output, end=\"\")\n\n        # Download results\n        await sandbox.download(\"/tmp/results.csv\", \"results.csv\")\n\n# Example usage\nasyncio.run(process_dataset(\"https://example.com/data.csv\"))\n```\n\n### Code Testing and Validation\n\n```python\nimport asyncio\nfrom sandboxes import Sandbox\n\nasync def test_solution(code: str, test_cases: list):\n    \"\"\"Test code against multiple test cases.\"\"\"\n    results = []\n\n    async with Sandbox.create() as sandbox:\n        # Save the code\n        await sandbox.upload(\"solution.py\", \"/tmp/solution.py\")\n\n        # Run each test case\n        for i, test in enumerate(test_cases):\n            result = await sandbox.execute(\n                f\"python /tmp/solution.py < {test['input']}\"\n            )\n            results.append({\n                \"test\": i + 1,\n                \"passed\": result.stdout.strip() == test['expected'],\n                \"output\": result.stdout.strip()\n            })\n\n    return results\n\n# Example usage\nasyncio.run(test_solution(\"print(sum(map(int, input().split())))\", [\n    {\"input\": \"1 2 3\", \"expected\": \"6\"}\n]))\n```\n\n## Troubleshooting\n\n### No Providers Available\n\n```python\n# If you see: \"No provider specified and no default provider set\"\n\n# Solution 1: Set environment variables\nexport E2B_API_KEY=\"your-key\"\n\n# Solution 2: Configure manually\nfrom sandboxes import Sandbox\nSandbox.configure(e2b_api_key=\"your-key\")\n\n# Solution 3: Use low-level API\nfrom sandboxes.providers import E2BProvider\nprovider = E2BProvider(api_key=\"your-key\")\n```\n\n### Provider Failures\n\n```python\nimport asyncio\nfrom sandboxes import Sandbox\nfrom sandboxes.exceptions import ProviderError\n\nasync def main():\n    # Enable automatic failover\n    sandbox = await Sandbox.create(\n        provider=\"e2b\",\n        fallback=[\"modal\", \"cloudflare\", \"daytona\"]\n    )\n\n    # Or handle errors manually\n    try:\n        sandbox = await Sandbox.create(provider=\"e2b\")\n    except ProviderError:\n        sandbox = await Sandbox.create(provider=\"modal\")\n\nasyncio.run(main())\n```\n\n### Debugging\n\n```python\nimport asyncio\nimport logging\nfrom sandboxes import Sandbox\n\nasync def main():\n    # Enable debug logging\n    logging.basicConfig(level=logging.DEBUG)\n\n    # Check provider health\n    Sandbox._ensure_manager()\n    for name, provider in Sandbox._manager.providers.items():\n        health = await provider.health_check()\n        print(f\"{name}: {'\u2705' if health else '\u274c'}\")\n\nasyncio.run(main())\n```\n\n## Security Disclosure\n\nWe take security seriously. If you discover a security vulnerability in this library or any of its dependencies, please report it responsibly.\n\n**Responsible Disclosure:**\n- Email security reports to: **ted@cased.com**\n- Include a detailed description of the vulnerability\n- Provide steps to reproduce if possible\n- Allow reasonable time for a fix before public disclosure\n\nWe will acknowledge your report within 48 hours and work with you to address the issue.\n\n## License\n\nMIT License - see [LICENSE](LICENSE) file for details.\n## Acknowledgments\n\nBuilt by [Cased](https://cased.com)\n\nSpecial thanks to the teams at E2B, Modal, Daytona, and Cloudflare for their excellent sandbox platforms.\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "Universal library for AI code execution sandboxes",
    "version": "0.2.3",
    "project_urls": null,
    "split_keywords": [
        "ai",
        " cloudflare",
        " code-execution",
        " daytona",
        " e2b",
        " modal",
        " sandbox",
        " vercel"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "3122ba3baa4c21862fa6eb3e24ae249fdfd8f1b4a20590d251c50d0148420d9d",
                "md5": "43f575c52c80518810cc3cc7783c0b73",
                "sha256": "56ee5dc7b0a9d52f8dcb2f683dc3ee4332b7c64eb30e9d11c3f171e61bc352a7"
            },
            "downloads": -1,
            "filename": "cased_sandboxes-0.2.3-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "43f575c52c80518810cc3cc7783c0b73",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.11",
            "size": 48935,
            "upload_time": "2025-10-07T11:03:18",
            "upload_time_iso_8601": "2025-10-07T11:03:18.888449Z",
            "url": "https://files.pythonhosted.org/packages/31/22/ba3baa4c21862fa6eb3e24ae249fdfd8f1b4a20590d251c50d0148420d9d/cased_sandboxes-0.2.3-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "502dab875465c75d8abe0949216c2fcd2d3736cff3eb4c219b25ff480a4434cb",
                "md5": "fbe21048a0a91605a5d2b923e1f67287",
                "sha256": "1362c6d5b37ca4078d4def0f5e501b400f804d17c29f65b9ddab150b53fb2414"
            },
            "downloads": -1,
            "filename": "cased_sandboxes-0.2.3.tar.gz",
            "has_sig": false,
            "md5_digest": "fbe21048a0a91605a5d2b923e1f67287",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.11",
            "size": 41473,
            "upload_time": "2025-10-07T11:03:19",
            "upload_time_iso_8601": "2025-10-07T11:03:19.899281Z",
            "url": "https://files.pythonhosted.org/packages/50/2d/ab875465c75d8abe0949216c2fcd2d3736cff3eb4c219b25ff480a4434cb/cased_sandboxes-0.2.3.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-10-07 11:03:19",
    "github": false,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "lcname": "cased-sandboxes"
}
        
Elapsed time: 1.18729s