Official Python SDK for Rexec - Terminal as a Service
Project description
Rexec Python SDK
Official Python SDK for Rexec - Terminal as a Service.
Installation
pip install pipeops-rexec
Quick Start
import asyncio
from rexec import RexecClient
async def main():
async with RexecClient("https://your-instance.com", "your-token") as client:
# Create a container
container = await client.containers.create(
image="ubuntu:24.04",
name="my-sandbox"
)
print(f"Created container: {container.id}")
# Connect to terminal
async with client.terminal.connect(container.id) as term:
await term.write(b"echo 'Hello from Rexec!'\n")
# Read output
data = await term.read()
print(data.decode())
# Clean up
await client.containers.delete(container.id)
asyncio.run(main())
API Reference
RexecClient
from rexec import RexecClient
# Create client (use as context manager for automatic cleanup)
async with RexecClient(
base_url="https://your-instance.com",
token="your-api-token",
timeout=30.0, # optional
) as client:
...
# Or manage manually
client = RexecClient("https://your-instance.com", "your-token")
try:
...
finally:
await client.close()
Containers
# List all containers
containers = await client.containers.list()
for c in containers:
print(f"{c.name}: {c.status}")
# Get a specific container
container = await client.containers.get(container_id)
# Create a container
container = await client.containers.create(
image="ubuntu:24.04",
name="my-container",
environment={"MY_VAR": "value"},
labels={"project": "demo"}
)
# Start a container
await client.containers.start(container_id)
# Stop a container
await client.containers.stop(container_id)
# Delete a container
await client.containers.delete(container_id)
Files
# List files in a directory
files = await client.files.list(container_id, "/home")
for f in files:
prefix = "📁" if f.is_dir else "📄"
print(f"{prefix} {f.name}")
# Download a file
content = await client.files.download(container_id, "/etc/passwd")
print(content.decode())
# Upload a file
await client.files.upload(
container_id,
"/home/script.py",
b"print('hello world')"
)
# Create a directory
await client.files.mkdir(container_id, "/home/mydir")
# Delete a file
await client.files.delete(container_id, "/home/script.py")
Terminal
# Connect to terminal (recommended: use as context manager)
async with client.terminal.connect(
container_id,
cols=120,
rows=40,
timeout=30.0
) as term:
# Send commands
await term.write(b"ls -la\n")
# Read output
data = await term.read()
print(data.decode())
# Resize terminal
await term.resize(150, 50)
# Or iterate over output
async with client.terminal.connect(container_id) as term:
await term.write(b"echo hello && sleep 1 && echo world\n")
async for data in term:
print(data.decode(), end="")
Examples
Run a Script and Capture Output
async def run_script(client: RexecClient, container_id: str, script: str) -> str:
output = []
async with client.terminal.connect(container_id) as term:
await term.write(f"{script}\nexit\n".encode())
async for data in term:
output.append(data.decode())
return "".join(output)
# Usage
result = await run_script(client, container.id, "apt update && apt install -y curl")
print(result)
Batch Container Operations
async def create_batch(client: RexecClient, count: int) -> list[Container]:
import asyncio
tasks = [
client.containers.create(
image="ubuntu:24.04",
name=f"worker-{i}"
)
for i in range(count)
]
return await asyncio.gather(*tasks)
# Create 5 containers in parallel
containers = await create_batch(client, 5)
File Sync
import os
from pathlib import Path
async def sync_directory(
client: RexecClient,
container_id: str,
local_path: Path,
remote_path: str
):
"""Sync a local directory to a container."""
await client.files.mkdir(container_id, remote_path)
for item in local_path.iterdir():
remote_item = f"{remote_path}/{item.name}"
if item.is_file():
content = item.read_bytes()
await client.files.upload(container_id, remote_item, content)
print(f"Uploaded: {remote_item}")
elif item.is_dir():
await sync_directory(client, container_id, item, remote_item)
Error Handling
from rexec import RexecClient, RexecAPIError, RexecConnectionError
try:
container = await client.containers.get("invalid-id")
except RexecAPIError as e:
print(f"API Error {e.status_code}: {e.message}")
except RexecConnectionError as e:
print(f"Connection Error: {e}")
Type Hints
The SDK is fully typed for excellent IDE support:
from rexec import (
RexecClient,
Container,
CreateContainerRequest,
FileInfo,
Terminal,
)
container: Container = await client.containers.create(image="ubuntu:24.04")
files: list[FileInfo] = await client.files.list(container.id, "/")
Requirements
- Python 3.9+
httpxfor HTTP requestswebsocketsfor terminal connections
License
MIT License - see LICENSE for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
pipeops_rexec-1.0.1.tar.gz
(4.3 kB
view details)
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pipeops_rexec-1.0.1.tar.gz.
File metadata
- Download URL: pipeops_rexec-1.0.1.tar.gz
- Upload date:
- Size: 4.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f06531c8009d259ba36d3c06aa9891b20302bfa38c59505d6c950796b2ab1ecf
|
|
| MD5 |
f25ee1ced7b9fc17dba5bb5ca59d19ee
|
|
| BLAKE2b-256 |
933bcb04a4f258d4258c82a5d60b75a42c6b0eef3497e0d3c1e41d0f40f8bb5a
|
File details
Details for the file pipeops_rexec-1.0.1-py3-none-any.whl.
File metadata
- Download URL: pipeops_rexec-1.0.1-py3-none-any.whl
- Upload date:
- Size: 3.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f1f058ca0bb6ce415929df97804db8f471371acbea633877216eead0ee96f0bb
|
|
| MD5 |
da39d1a14e322c89cb9e6a96310a9fd8
|
|
| BLAKE2b-256 |
886d4da770f75d0db6cf96ec9f28049a9cfd9f1ef13fde23426d4499833f8163
|