Python Sync SDK (clients/python/sync/): - 712 lines core implementation with 13 public APIs - HMAC-SHA256 authentication with OpenSSL - 4-tier credential system (args > env > ~/.unsandbox > ./accounts.csv) - Language caching with 1-hour TTL - 64+ comprehensive unit tests - Full documentation (README, USAGE, IMPLEMENTATION) Python Async SDK (clients/python/async/): - 705 lines async implementation using aiohttp - Full async/await pattern support - Exponential backoff polling strategy - 200+ test cases with ~95% coverage - 7 working async examples - 5 documentation guides C SDK (clients/c/): - 823 lines C implementation - Header file with 15 public functions - OpenSSL HMAC-SHA256 + libcurl HTTP client - Language detection for 48 file extensions - 22/22 tests passing - Proper memory management Examples: - 14 Python examples (7 sync, 7 async) with docstrings - 4 C examples (hello_world, fibonacci, error_handling, credentials) - All examples ready for pipeline validation - Expected outputs documented for validation Pipeline Integration: - Updated .gitlab-ci.yml with gcc/musl-dev for C compilation - Enhanced validate-examples.sh with C compilation support - Updated detect-changes.sh to recognize python/c changes - Updated generate-matrix.sh with python/c in matrix - E2E tests updated with mock Python/C examples - All tests passing (30+ test cases) Documentation: - PYTHON_C_INTEGRATION_SUMMARY.md (452 lines) - Complete API references for both SDKs - Quick start guides - Pattern documentation - Error handling guides
8.4 KiB
8.4 KiB
Unsandbox Python SDK (Synchronous) - Usage Guide
Overview
The Unsandbox Python SDK provides a synchronous (blocking) interface for executing code on unsandbox.com. Unlike the async SDK, the sync SDK makes blocking calls and waits for code execution to complete.
Installation
From Source
cd clients/python/sync
pip install -e .
Development Setup
cd clients/python/sync
pip install -e ".[dev]"
Quick Examples
1. Basic Synchronous Execution
Execute code and wait for completion:
from un import execute_code
result = execute_code("python", "print('hello')")
print(result)
# {
# 'status': 'completed',
# 'stdout': 'hello\n',
# 'stderr': '',
# 'exit_code': 0,
# 'runtime_ms': 342
# }
2. Async Execution with Polling
Start execution and manually poll:
from un import execute_async, wait_for_job
# Start execution (returns immediately)
job_id = execute_async("python", "print('working...')")
print(f"Job started: {job_id}")
# Later, poll for completion
result = wait_for_job(job_id)
print(result)
3. Check Job Status
Get current status without waiting:
from un import get_job
job = get_job("job_123")
print(f"Status: {job['status']}")
if job['status'] == 'completed':
print(f"Output: {job['stdout']}")
4. Cancel a Job
Stop a running job:
from un import execute_async, cancel_job
job_id = execute_async("python", "import time; time.sleep(100)")
cancel_job(job_id)
5. List Active Jobs
Get all jobs for your account:
from un import list_jobs
jobs = list_jobs()
for job in jobs:
print(f"{job['job_id']}: {job['status']}")
6. Detect Language from Filename
Automatically determine language:
from un import detect_language, execute_code
# Detect language
lang = detect_language("script.py") # Returns "python"
# Use detected language
if lang:
result = execute_code(lang, "print('hello')")
7. Get Supported Languages
List all available languages:
from un import get_languages
languages = get_languages()
print(f"Supported languages: {', '.join(languages)}")
8. Snapshots (Save/Restore Sessions)
from un import session_snapshot, list_snapshots, restore_snapshot
# Create a snapshot
snapshot_id = session_snapshot(
"session_123",
name="checkpoint_before_experiment"
)
# List all snapshots
snapshots = list_snapshots()
for snap in snapshots:
print(f"{snap['id']}: {snap['name']}")
# Restore a snapshot
result = restore_snapshot(snapshot_id)
Authentication
1. Function Arguments (Highest Priority)
result = execute_code(
"python",
"print('hello')",
public_key="your_public_key",
secret_key="your_secret_key"
)
2. Environment Variables
export UNSANDBOX_PUBLIC_KEY="your_public_key"
export UNSANDBOX_SECRET_KEY="your_secret_key"
from un import execute_code
# No args needed - uses environment variables
result = execute_code("python", "print('hello')")
3. Configuration File
Create ~/.unsandbox/accounts.csv:
public_key_1,secret_key_1
public_key_2,secret_key_2
Then:
from un import execute_code
# Uses first account (line 0)
result = execute_code("python", "print('hello')")
# To use second account:
import os
os.environ["UNSANDBOX_ACCOUNT"] = "1"
result = execute_code("python", "print('hello')")
4. Local accounts.csv (Lowest Priority)
Create ./accounts.csv in your project directory:
public_key,secret_key
from un import execute_code
result = execute_code("python", "print('hello')")
Error Handling
from un import execute_code, CredentialsError
import requests
try:
result = execute_code("python", "print('hello')")
except CredentialsError:
print("No credentials found - check environment or config files")
except requests.Timeout:
print("Request timed out - API may be down")
except requests.RequestException as e:
print(f"Network error: {e}")
except Exception as e:
print(f"Unexpected error: {e}")
Checking Execution Results
All execution results have the same structure:
result = execute_code("python", "print('hello')")
# Common fields:
result['status'] # 'completed', 'running', 'pending', 'failed', 'timeout', 'cancelled'
result['stdout'] # Standard output as string
result['stderr'] # Standard error as string
result['exit_code'] # Process exit code (0 = success)
result['runtime_ms'] # Execution time in milliseconds
result['job_id'] # Unique job identifier
Advanced Usage
Executing Large Programs
with open("my_script.py", "r") as f:
code = f.read()
result = execute_code("python", code)
Language Detection for Multiple Files
from un import detect_language, execute_code
import os
for filename in os.listdir("scripts"):
lang = detect_language(filename)
if lang:
with open(f"scripts/{filename}") as f:
code = f.read()
result = execute_code(lang, code)
print(f"{filename}: {result['status']}")
Batch Execution
from un import execute_async, get_job
import time
# Start multiple jobs
job_ids = []
for code in [code1, code2, code3]:
job_id = execute_async("python", code)
job_ids.append(job_id)
# Poll until all complete
results = {}
while job_ids:
for job_id in list(job_ids):
job = get_job(job_id)
if job['status'] in ('completed', 'failed', 'timeout', 'cancelled'):
results[job_id] = job
job_ids.remove(job_id)
if job_ids:
time.sleep(1) # Wait before next poll
# Process results
for job_id, result in results.items():
print(f"{job_id}: {result['stdout']}")
Polling with Custom Timeout
from un import execute_async, get_job
import time
job_id = execute_async("python", "import time; time.sleep(5); print('done')")
# Poll with custom timeout
start = time.time()
timeout_sec = 30
while time.time() - start < timeout_sec:
job = get_job(job_id)
if job['status'] in ('completed', 'failed', 'timeout', 'cancelled'):
print(f"Done: {job['stdout']}")
break
time.sleep(1)
else:
print("Custom timeout reached")
Performance Tips
- Reuse credentials: Load credentials once, pass to multiple calls
- Use caching: Languages list is cached for 1 hour
- Batch operations: Start multiple jobs async, poll together
- Handle timeouts: Always catch
requests.Timeout
Debugging
Enable verbose output:
import logging
# Enable requests logging
logging.basicConfig(level=logging.DEBUG)
logging.getLogger("requests").setLevel(logging.DEBUG)
logging.getLogger("urllib3").setLevel(logging.DEBUG)
from un import execute_code
result = execute_code("python", "print('hello')")
Testing Your Setup
from un import get_languages, execute_code
# Test 1: Can we get credentials?
try:
languages = get_languages()
print(f"✓ Authentication works, {len(languages)} languages available")
except Exception as e:
print(f"✗ Authentication failed: {e}")
exit(1)
# Test 2: Can we execute code?
try:
result = execute_code("python", "print('test')")
if result['status'] == 'completed':
print(f"✓ Code execution works: {result['stdout'].strip()}")
else:
print(f"✗ Code execution failed: {result['status']}")
except Exception as e:
print(f"✗ Code execution error: {e}")
Troubleshooting
"No credentials found"
Ensure one of these is set:
- Function arguments:
execute_code(..., public_key="...", secret_key="...") - Environment:
export UNSANDBOX_PUBLIC_KEY=... UNSANDBOX_SECRET_KEY=... - Config:
~/.unsandbox/accounts.csvor./accounts.csv
"Connection timeout"
- Check internet connection
- Verify API is reachable:
curl https://api.unsandbox.com/cluster - Check for firewall/proxy issues
"Authentication failed (401)"
- Verify public/secret keys are correct
- Ensure you're using the right account if multiple configured
- Check that account has API access enabled
Slow execution
- First execution may be slow (container startup)
- Subsequent executions should be faster
- Use async execution for long-running jobs
- Check pool status: https://api.unsandbox.com/cluster