Skip to content

Commit 173ff07

Browse files
committed
docs + examples
1 parent cff909f commit 173ff07

10 files changed

Lines changed: 2071 additions & 38 deletions

File tree

README-SDK.md

Lines changed: 599 additions & 25 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,23 @@ The full API of this library can be found in [api.md](api.md).
3030

3131
For a higher-level, Pythonic interface, check out the new [`RunloopSDK`](README-SDK.md) which layers an object-oriented API on top of the generated client (including synchronous and asynchronous variants).
3232

33+
```python
34+
from runloop_api_client import RunloopSDK
35+
36+
sdk = RunloopSDK() # Uses RUNLOOP_API_KEY environment variable by default
37+
38+
# Create a devbox and execute commands with a clean, object-oriented interface
39+
with sdk.devbox.create(name="my-devbox") as devbox:
40+
result = devbox.cmd.exec("echo 'Hello from Runloop!'")
41+
print(result.stdout())
42+
```
43+
44+
**See the [SDK documentation](README-SDK.md) for complete examples and API reference.**
45+
46+
### REST API Client
47+
48+
Alternatively, you can use the generated REST API client directly:
49+
3350
```python
3451
import os
3552
from runloop_api_client import Runloop

examples/async_devbox.py

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
#!/usr/bin/env -S uv run python
2+
"""
3+
Async Runloop SDK Example - Concurrent Devbox Operations
4+
5+
This example demonstrates the asynchronous capabilities of the Runloop SDK:
6+
- Creating and managing devboxes asynchronously
7+
- Concurrent command execution across multiple devboxes
8+
- Async file operations
9+
- Async command streaming
10+
"""
11+
12+
import asyncio
13+
import os
14+
from runloop_api_client import AsyncRunloopSDK
15+
16+
17+
async def demonstrate_basic_async():
18+
"""Demonstrate basic async devbox operations."""
19+
print("=== Basic Async Operations ===")
20+
21+
sdk = AsyncRunloopSDK()
22+
23+
# Create a devbox with async context manager
24+
async with sdk.devbox.create(name="async-example-devbox") as devbox:
25+
print(f"Created devbox: {devbox.id}")
26+
27+
# Execute command asynchronously
28+
result = await devbox.cmd.exec("echo 'Hello from async devbox!'")
29+
output = await result.stdout()
30+
print(f"Command output: {output.strip()}")
31+
32+
# File operations
33+
await devbox.file.write(
34+
path="/home/user/async_test.txt",
35+
contents="Hello from async operations!\n",
36+
)
37+
content = await devbox.file.read(path="/home/user/async_test.txt")
38+
print(f"File content: {content.strip()}")
39+
40+
print("Devbox automatically shutdown\n")
41+
42+
43+
async def demonstrate_concurrent_commands():
44+
"""Execute multiple commands concurrently on the same devbox."""
45+
print("=== Concurrent Command Execution ===")
46+
47+
sdk = AsyncRunloopSDK()
48+
49+
async with sdk.devbox.create(name="concurrent-commands-devbox") as devbox:
50+
print(f"Created devbox: {devbox.id}")
51+
52+
# Execute multiple commands concurrently
53+
async def run_command(cmd: str, label: str):
54+
print(f"Starting: {label}")
55+
result = await devbox.cmd.exec(cmd)
56+
output = await result.stdout()
57+
print(f"{label} completed: {output.strip()}")
58+
return output
59+
60+
# Run multiple commands in parallel
61+
results = await asyncio.gather(
62+
run_command("echo 'Task 1' && sleep 1", "Task 1"),
63+
run_command("echo 'Task 2' && sleep 1", "Task 2"),
64+
run_command("echo 'Task 3' && sleep 1", "Task 3"),
65+
)
66+
67+
print(f"All {len(results)} tasks completed\n")
68+
69+
70+
async def demonstrate_multiple_devboxes():
71+
"""Create and manage multiple devboxes concurrently."""
72+
print("=== Managing Multiple Devboxes ===")
73+
74+
sdk = AsyncRunloopSDK()
75+
76+
async def create_and_use_devbox(name: str, number: int):
77+
"""Create a devbox, run a command, and return the result."""
78+
async with sdk.devbox.create(name=name) as devbox:
79+
print(f"Devbox {number} ({devbox.id}): Created")
80+
81+
# Run a command
82+
result = await devbox.cmd.exec(f"echo 'Hello from devbox {number}'")
83+
output = await result.stdout()
84+
print(f"Devbox {number}: {output.strip()}")
85+
86+
return output
87+
88+
# Create and use multiple devboxes concurrently
89+
results = await asyncio.gather(
90+
create_and_use_devbox("multi-devbox-1", 1),
91+
create_and_use_devbox("multi-devbox-2", 2),
92+
create_and_use_devbox("multi-devbox-3", 3),
93+
)
94+
95+
print(f"All {len(results)} devboxes completed and shutdown\n")
96+
97+
98+
async def demonstrate_async_streaming():
99+
"""Demonstrate real-time command output streaming with async callbacks."""
100+
print("=== Async Command Streaming ===")
101+
102+
sdk = AsyncRunloopSDK()
103+
104+
async with sdk.devbox.create(name="streaming-devbox") as devbox:
105+
print(f"Created devbox: {devbox.id}")
106+
107+
# Async callback to capture output
108+
output_lines = []
109+
110+
async def capture_output(line: str):
111+
print(f"[STREAM] {line.strip()}")
112+
output_lines.append(line)
113+
114+
# Execute command with streaming output
115+
print("\nStreaming command output:")
116+
await devbox.cmd.exec(
117+
"for i in 1 2 3 4 5; do echo \"Line $i\"; sleep 0.2; done",
118+
stdout=capture_output,
119+
)
120+
121+
print(f"\nCaptured {len(output_lines)} lines of output\n")
122+
123+
124+
async def demonstrate_async_execution():
125+
"""Demonstrate async execution management."""
126+
print("=== Async Execution Management ===")
127+
128+
sdk = AsyncRunloopSDK()
129+
130+
async with sdk.devbox.create(name="async-exec-devbox") as devbox:
131+
print(f"Created devbox: {devbox.id}")
132+
133+
# Start an async execution
134+
execution = await devbox.cmd.exec_async(
135+
"echo 'Starting...'; sleep 2; echo 'Finished!'"
136+
)
137+
print(f"Started execution: {execution.execution_id}")
138+
139+
# Poll execution state
140+
state = await execution.get_state()
141+
print(f"Initial status: {state.status}")
142+
143+
# Wait for completion
144+
print("Waiting for completion...")
145+
result = await execution.result()
146+
print(f"Exit code: {result.exit_code}")
147+
output = await result.stdout()
148+
print(f"Output:\n{output}")
149+
150+
# Start another execution and kill it
151+
print("\nStarting long-running process...")
152+
long_execution = await devbox.cmd.exec_async("sleep 30")
153+
print(f"Execution ID: {long_execution.execution_id}")
154+
155+
# Wait a bit then kill it
156+
await asyncio.sleep(1)
157+
print("Killing execution...")
158+
await long_execution.kill()
159+
print("Execution killed\n")
160+
161+
162+
async def main():
163+
"""Run all async demonstrations."""
164+
print("Initialized Async Runloop SDK\n")
165+
166+
# Run demonstrations
167+
await demonstrate_basic_async()
168+
await demonstrate_concurrent_commands()
169+
await demonstrate_multiple_devboxes()
170+
await demonstrate_async_streaming()
171+
await demonstrate_async_execution()
172+
173+
print("All async demonstrations completed!")
174+
175+
176+
if __name__ == "__main__":
177+
# Ensure API key is set
178+
if not os.getenv("RUNLOOP_API_KEY"):
179+
print("Error: RUNLOOP_API_KEY environment variable is not set")
180+
print("Please set it to your Runloop API key:")
181+
print(" export RUNLOOP_API_KEY=your-api-key")
182+
exit(1)
183+
184+
try:
185+
asyncio.run(main())
186+
except Exception as e:
187+
print(f"\nError: {e}")
188+
raise
189+

examples/basic_devbox.py

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
#!/usr/bin/env -S uv run python
2+
"""
3+
Basic Runloop SDK Example - Devbox Operations
4+
5+
This example demonstrates the core functionality of the Runloop SDK:
6+
- Creating and managing devboxes
7+
- Executing commands synchronously and asynchronously
8+
- File operations (read, write, upload, download)
9+
- Devbox lifecycle management
10+
"""
11+
12+
import os
13+
from pathlib import Path
14+
from runloop_api_client import RunloopSDK
15+
16+
17+
def main():
18+
# Initialize the SDK (uses RUNLOOP_API_KEY environment variable by default)
19+
sdk = RunloopSDK()
20+
print("Initialized Runloop SDK")
21+
22+
# Create a devbox with automatic cleanup using context manager
23+
print("\n=== Creating Devbox ===")
24+
with sdk.devbox.create(name="basic-example-devbox") as devbox:
25+
print(f"Created devbox: {devbox.id}")
26+
27+
# Get devbox information
28+
info = devbox.get_info()
29+
print(f"Devbox status: {info.status}")
30+
print(f"Devbox name: {info.name}")
31+
32+
# Execute a simple command
33+
print("\n=== Executing Commands ===")
34+
result = devbox.cmd.exec("echo 'Hello from Runloop!'")
35+
print(f"Command output: {result.stdout().strip()}")
36+
print(f"Exit code: {result.exit_code}")
37+
print(f"Success: {result.success}")
38+
39+
# Execute a command that generates output
40+
result = devbox.cmd.exec("ls -la /home/user")
41+
print(f"\nDirectory listing:\n{result.stdout()}")
42+
43+
# Execute a command with error
44+
result = devbox.cmd.exec("ls /nonexistent")
45+
if result.failed:
46+
print(f"\nCommand failed with exit code {result.exit_code}")
47+
print(f"Error output: {result.stderr()}")
48+
49+
# File operations
50+
print("\n=== File Operations ===")
51+
52+
# Write a file
53+
file_path = "/home/user/test.txt"
54+
content = "Hello, Runloop!\nThis is a test file.\n"
55+
devbox.file.write(path=file_path, contents=content)
56+
print(f"Wrote file: {file_path}")
57+
58+
# Read the file back
59+
read_content = devbox.file.read(path=file_path)
60+
print(f"Read file content:\n{read_content}")
61+
62+
# Create a local file to upload
63+
local_file = Path("temp_upload.txt")
64+
local_file.write_text("This file will be uploaded to the devbox.\n")
65+
66+
try:
67+
# Upload a file
68+
upload_path = "/home/user/uploaded.txt"
69+
devbox.file.upload(path=upload_path, file=local_file)
70+
print(f"\nUploaded file to: {upload_path}")
71+
72+
# Verify the upload by reading the file
73+
uploaded_content = devbox.file.read(path=upload_path)
74+
print(f"Uploaded file content: {uploaded_content.strip()}")
75+
76+
# Download a file
77+
download_data = devbox.file.download(path=upload_path)
78+
local_download = Path("temp_download.txt")
79+
local_download.write_bytes(download_data)
80+
print(f"Downloaded file to: {local_download}")
81+
print(f"Downloaded content: {local_download.read_text().strip()}")
82+
finally:
83+
# Cleanup local files
84+
local_file.unlink(missing_ok=True)
85+
if Path("temp_download.txt").exists():
86+
Path("temp_download.txt").unlink()
87+
88+
# Asynchronous command execution
89+
print("\n=== Asynchronous Command Execution ===")
90+
91+
# Start a long-running command asynchronously
92+
execution = devbox.cmd.exec_async("sleep 3 && echo 'Done sleeping!'")
93+
print(f"Started async execution: {execution.execution_id}")
94+
95+
# Check the execution state
96+
state = execution.get_state()
97+
print(f"Execution status: {state.status}")
98+
99+
# Wait for completion and get the result
100+
print("Waiting for execution to complete...")
101+
result = execution.result()
102+
print(f"Execution completed with exit code: {result.exit_code}")
103+
print(f"Output: {result.stdout().strip()}")
104+
105+
# Keep devbox alive (extends timeout)
106+
print("\n=== Devbox Lifecycle ===")
107+
devbox.keep_alive()
108+
print("Extended devbox timeout")
109+
110+
print("\n=== Devbox Cleanup ===")
111+
print("Devbox automatically shutdown when exiting context manager")
112+
113+
114+
if __name__ == "__main__":
115+
# Ensure API key is set
116+
if not os.getenv("RUNLOOP_API_KEY"):
117+
print("Error: RUNLOOP_API_KEY environment variable is not set")
118+
print("Please set it to your Runloop API key:")
119+
print(" export RUNLOOP_API_KEY=your-api-key")
120+
exit(1)
121+
122+
try:
123+
main()
124+
except Exception as e:
125+
print(f"\nError: {e}")
126+
raise
127+

0 commit comments

Comments
 (0)