voidrun 0.0.5__tar.gz → 0.0.7__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. voidrun-0.0.7/PKG-INFO +522 -0
  2. voidrun-0.0.7/README.md +498 -0
  3. {voidrun-0.0.5 → voidrun-0.0.7}/pyproject.toml +2 -1
  4. voidrun-0.0.7/scripts/run_all_examples.sh +46 -0
  5. voidrun-0.0.7/voidrun/__init__.py +29 -0
  6. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/create_sandbox_request.py +4 -4
  7. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/image.py +8 -4
  8. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/sandbox.py +13 -7
  9. voidrun-0.0.7/voidrun/client.py +399 -0
  10. voidrun-0.0.7/voidrun/constants.py +29 -0
  11. voidrun-0.0.7/voidrun/interpreter.py +176 -0
  12. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/sandbox.py +112 -38
  13. voidrun-0.0.5/PKG-INFO +0 -899
  14. voidrun-0.0.5/README.md +0 -875
  15. voidrun-0.0.5/voidrun/__init__.py +0 -4
  16. voidrun-0.0.5/voidrun/client.py +0 -140
  17. voidrun-0.0.5/voidrun/interpreter.py +0 -99
  18. {voidrun-0.0.5 → voidrun-0.0.7}/.gitignore +0 -0
  19. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/__init__.py +0 -0
  20. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/api/__init__.py +0 -0
  21. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/api/execution_api.py +0 -0
  22. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/api/file_system_api.py +0 -0
  23. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/api/images_api.py +0 -0
  24. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/api/organizations_api.py +0 -0
  25. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/api/sandboxes_api.py +0 -0
  26. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/api/system_api.py +0 -0
  27. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/api/users_api.py +0 -0
  28. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/api_client.py +0 -0
  29. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/api_response.py +0 -0
  30. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/configuration.py +0 -0
  31. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/exceptions.py +0 -0
  32. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/__init__.py +0 -0
  33. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/activate_api_key_request.py +0 -0
  34. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/api_key_response.py +0 -0
  35. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/api_response_sandbox.py +0 -0
  36. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/api_response_sandboxes_list.py +0 -0
  37. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/api_response_sandboxes_list_meta.py +0 -0
  38. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/command_kill_response.py +0 -0
  39. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/command_list_response.py +0 -0
  40. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/command_run_response.py +0 -0
  41. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/command_wait_response.py +0 -0
  42. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/compress_request.py +0 -0
  43. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/create_file_request.py +0 -0
  44. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/create_image_request.py +0 -0
  45. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/create_pty_session200_response.py +0 -0
  46. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/create_pty_session200_response_all_of_data.py +0 -0
  47. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/create_pty_session_request.py +0 -0
  48. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/create_sandbox201_response.py +0 -0
  49. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/disk_usage.py +0 -0
  50. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/error_response.py +0 -0
  51. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/exec_request.py +0 -0
  52. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/exec_response.py +0 -0
  53. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/exec_response_data.py +0 -0
  54. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/execute_in_session_request.py +0 -0
  55. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/extract_request.py +0 -0
  56. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/file_event.py +0 -0
  57. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/file_info.py +0 -0
  58. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/file_stats.py +0 -0
  59. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/generate_api_key_request.py +0 -0
  60. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/generated_api_key_response.py +0 -0
  61. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/get_current_user200_response.py +0 -0
  62. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/get_current_user200_response_orgs_inner.py +0 -0
  63. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/get_org_users200_response.py +0 -0
  64. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/get_org_users200_response_all_of_data_inner.py +0 -0
  65. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/get_pty_buffer200_response.py +0 -0
  66. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/get_pty_buffer200_response_all_of_data.py +0 -0
  67. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/get_version200_response.py +0 -0
  68. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/kill_background_process_request.py +0 -0
  69. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/list_files200_response.py +0 -0
  70. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/list_files200_response_data.py +0 -0
  71. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/list_pty_sessions200_response.py +0 -0
  72. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/list_pty_sessions200_response_all_of_data.py +0 -0
  73. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/organization.py +0 -0
  74. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/process_info.py +0 -0
  75. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/pty_session_info.py +0 -0
  76. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/resize_terminal_request.py +0 -0
  77. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/run_background_command_request.py +0 -0
  78. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/session_exec_request.py +0 -0
  79. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/session_exec_response.py +0 -0
  80. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/session_exec_stream_request.py +0 -0
  81. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/start_watch200_response.py +0 -0
  82. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/start_watch200_response_data.py +0 -0
  83. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/start_watch_request.py +0 -0
  84. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/models/success_response.py +0 -0
  85. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/py.typed +0 -0
  86. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/api_client/rest.py +0 -0
  87. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/commands.py +0 -0
  88. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/fs.py +0 -0
  89. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/pty.py +0 -0
  90. {voidrun-0.0.5 → voidrun-0.0.7}/voidrun/response.py +0 -0
voidrun-0.0.7/PKG-INFO ADDED
@@ -0,0 +1,522 @@
1
+ Metadata-Version: 2.4
2
+ Name: voidrun
3
+ Version: 0.0.7
4
+ Summary: Python SDK for VoidRun AI Sandbox
5
+ Project-URL: Homepage, https://voidrun.io
6
+ Project-URL: Documentation, https://docs.voidrun.io
7
+ Project-URL: Repository, https://github.com/voidrun/py-sdk
8
+ Author-email: VoidRun Team <support@voidrun.io>
9
+ License-Expression: MIT
10
+ Classifier: Framework :: AsyncIO
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Programming Language :: Python :: 3
14
+ Requires-Python: >=3.9
15
+ Requires-Dist: certifi
16
+ Requires-Dist: httpx>=0.24.0
17
+ Requires-Dist: pydantic>=2.0.0
18
+ Requires-Dist: python-dateutil>=2.8.2
19
+ Requires-Dist: python-dotenv>=1.0.0
20
+ Requires-Dist: typing-extensions>=4.0.0
21
+ Requires-Dist: urllib3>=2.0.0
22
+ Requires-Dist: websockets>=11.0
23
+ Description-Content-Type: text/markdown
24
+
25
+ # VoidRun Python SDK
26
+
27
+ Python client for [VoidRun](https://voidrun.io) AI sandboxes: run commands, manage files, use pseudo-terminals, stream output, and execute multi-language code in isolated environments.
28
+
29
+ The high-level API is aligned with the official **TypeScript SDK** (`create_sandbox`, `list_sandboxes`, `remove_sandbox`, `Sandbox.run_code`, `CodeExecutionResult`, and shared defaults).
30
+
31
+ [![PyPI version](https://img.shields.io/pypi/v/voidrun)](https://pypi.org/project/voidrun/)
32
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
33
+
34
+ ## Table of contents
35
+
36
+ - [Features](#features)
37
+ - [Requirements](#requirements)
38
+ - [Installation](#installation)
39
+ - [Configuration](#configuration)
40
+ - [Quick start](#quick-start)
41
+ - [Parity with the TypeScript SDK](#parity-with-the-typescript-sdk)
42
+ - [Core concepts](#core-concepts)
43
+ - [Code execution and interpreter](#code-execution-and-interpreter)
44
+ - [Background commands](#background-commands)
45
+ - [File system](#file-system)
46
+ - [File watching (async)](#file-watching-async)
47
+ - [Pseudo-terminal (PTY)](#pseudo-terminal-pty)
48
+ - [API reference (summary)](#api-reference-summary)
49
+ - [Runnable examples](#runnable-examples)
50
+ - [Development and tests](#development-and-tests)
51
+ - [Building and publishing](#building-and-publishing)
52
+ - [Error handling](#error-handling)
53
+ - [Troubleshooting](#troubleshooting)
54
+ - [Contributing, license, support](#contributing-license-support)
55
+
56
+ ## Features
57
+
58
+ - **Sandbox lifecycle**: Create, list, fetch, start/stop/pause/resume, and remove sandboxes (sync and async).
59
+ - **Shell execution**: `exec` with optional `ExecRequest`; SSE streaming via `exec_stream`.
60
+ - **Code interpreter**: `run_code` / `interpreter.run` return a structured **`CodeExecutionResult`** (stdout, stderr, success, exit_code, results, logs).
61
+ - **Files**: Create, upload, download, list, move, copy, compress, extract, permissions, search, disk usage.
62
+ - **File watching**: WebSocket-backed directory watches (async).
63
+ - **PTY**: Ephemeral and persistent terminal sessions, resize, `run_command` with prompt detection.
64
+ - **Background commands**: Run, list, attach, wait, kill long-running processes.
65
+
66
+ ## Requirements
67
+
68
+ - Python **3.9+**
69
+ - Dependencies: see [`pyproject.toml`](pyproject.toml) (Pydantic v2, httpx, urllib3, websockets, python-dotenv, etc.).
70
+
71
+ ## Installation
72
+
73
+ ```bash
74
+ pip install voidrun
75
+ ```
76
+
77
+ With Poetry:
78
+
79
+ ```bash
80
+ poetry add voidrun
81
+ ```
82
+
83
+ **From this repository** (editable install for development):
84
+
85
+ ```bash
86
+ cd py-sdk
87
+ pip install -e .
88
+ ```
89
+
90
+ ## Configuration
91
+
92
+ `VoidRun` and `AsyncVoidRun` require an **API key**. The **API base URL** defaults to the hosted endpoint (**`DEFAULT_API_BASE_URL`**, aligned with the TypeScript SDK and OpenAPI **`servers`**). Set **`VR_API_URL`** or **`API_URL`**, or pass **`base_url=`**, only for **self-hosted** deployments.
93
+
94
+ ### Constructor
95
+
96
+ ```python
97
+ from voidrun import VoidRun
98
+
99
+ vr = VoidRun(
100
+ api_key="your-api-key", # optional if VR_API_KEY / API_KEY is set
101
+ )
102
+ ```
103
+
104
+ ### Environment variables
105
+
106
+ | Variable | Purpose |
107
+ |----------|---------|
108
+ | `VR_API_KEY` or `API_KEY` | API key (required unless passed to the constructor). |
109
+ | `VR_API_URL` or `API_URL` | *(Self-hosted only.)* Overrides the default API base URL. |
110
+
111
+ ### Defaults (aligned with TypeScript SDK)
112
+
113
+ Exported from `voidrun`:
114
+
115
+ | Constant | Value | Meaning |
116
+ |----------|-------|---------|
117
+ | `DEFAULT_API_BASE_URL` | `https://platform.void-run.com/api` | Default API host when `VR_API_URL` / `API_URL` are unset. |
118
+ | `DEFAULT_SANDBOX_IMAGE` | `"code"` | Default image id when creating a sandbox without `image=`. |
119
+ | `DEFAULT_SANDBOX_CPU` | `1` | Default CPU count. |
120
+ | `DEFAULT_SANDBOX_MEM` | `1024` | Default memory in MB. |
121
+
122
+ For **self-hosted** VoidRun, set **`VR_API_URL`** (or **`API_URL`**) to your instance’s API root (including `/api` if that is how your server is mounted).
123
+
124
+ ## Quick start
125
+
126
+ ### Synchronous (recommended shape)
127
+
128
+ ```python
129
+ from voidrun import VoidRun
130
+
131
+ vr = VoidRun() # uses VR_API_KEY; default base URL unless VR_API_URL / API_URL is set
132
+
133
+ sandbox = vr.create_sandbox(mem=1024, cpu=1)
134
+
135
+ result = sandbox.exec('echo "Hello from VoidRun"')
136
+ # Exec returns VoidRunResponse whose .data is ExecResponseData
137
+ print(result.data.stdout)
138
+
139
+ sandbox.remove()
140
+ ```
141
+
142
+ ### Async
143
+
144
+ ```python
145
+ import asyncio
146
+ from voidrun import AsyncVoidRun
147
+
148
+ async def main():
149
+ async with AsyncVoidRun() as vr:
150
+ sandbox = await vr.create_sandbox(mem=1024, cpu=1)
151
+ result = sandbox.exec('echo "Hello"')
152
+ print(result.data.stdout)
153
+ await sandbox.remove_async()
154
+
155
+ asyncio.run(main())
156
+ ```
157
+
158
+ ### Context managers (auto cleanup)
159
+
160
+ Sync: exiting the block calls `remove()`. Async: `__aexit__` calls `remove_async()`.
161
+
162
+ ```python
163
+ with vr.create_sandbox() as sandbox:
164
+ print(sandbox.id)
165
+ ```
166
+
167
+ ```python
168
+ async with await vr.create_sandbox() as sandbox:
169
+ print(sandbox.id)
170
+ ```
171
+
172
+ ## Parity with the TypeScript SDK
173
+
174
+ Use the same mental model as `@voidrun/sdk` (or the internal TS client):
175
+
176
+ | TypeScript (concept) | Python |
177
+ |----------------------|--------|
178
+ | `createSandbox` | `VoidRun.create_sandbox` / `await AsyncVoidRun.create_sandbox` |
179
+ | `getSandbox` | `get_sandbox` |
180
+ | `listSandboxes` | `list_sandboxes` → `ListSandboxesResult` |
181
+ | `removeSandbox` | `remove_sandbox` or `sandbox.remove()` |
182
+ | `sandbox.runCode` | `sandbox.run_code` |
183
+ | `CodeExecutionResult` | `CodeExecutionResult` (Pydantic model) |
184
+ | `CodeInterpreter` | `CodeInterpreter` (alias: `Interpreter` on `sandbox.interpreter`) |
185
+
186
+ **Listing sandboxes** returns a **`ListSandboxesResult`** with:
187
+
188
+ - `.sandboxes`: list of `Sandbox` instances
189
+ - `.meta`: `ListSandboxesMeta` (`total`, `page`, `limit`, `total_pages`)
190
+
191
+ ## Core concepts
192
+
193
+ ### `VoidRun` / `AsyncVoidRun`
194
+
195
+ **Recommended methods**
196
+
197
+ - `create_sandbox(...)` → `Sandbox`
198
+ - `get_sandbox(sandbox_id)` → `Sandbox`
199
+ - `list_sandboxes(page=..., limit=...)` → `ListSandboxesResult`
200
+ - `remove_sandbox(sandbox_id)` → `None`
201
+
202
+ `AsyncVoidRun` exposes the same names with `await` and provides `aclose()` (and `async with` support) to shut down the thread pool used for API calls.
203
+
204
+ **Keyword aliases**
205
+
206
+ Create options accept both snake_case and camelCase where noted in code (e.g. `env_vars` / `envVars`, `org_id` / `orgId`).
207
+
208
+ ### `Sandbox`
209
+
210
+ Notable attributes: `id`, `name`, `cpu`, `mem`, `org_id`, `status`, `env_vars`, `image`, `region`, `ref_id`, `auto_sleep`, `disk_mb`, `created_at`, `created_by`.
211
+
212
+ Sub-clients:
213
+
214
+ - `.fs`: file operations
215
+ - `.pty`: pseudo-terminal
216
+ - `.interpreter`: `CodeInterpreter`
217
+ - `.commands`: background processes
218
+
219
+ Lifecycle:
220
+
221
+ - `start`, `stop`, `pause`, `resume` (and `*_async` variants where applicable)
222
+ - `remove()` / `remove_async()`: delete sandbox on the API
223
+ - `delete()` / `delete_async()`: deprecated aliases for `remove`
224
+
225
+ `info()` returns `self` (same idea as TS `sandbox.info()`).
226
+
227
+ ## Code execution and interpreter
228
+
229
+ ### `sandbox.exec`
230
+
231
+ Accepts a command string, or keyword `command=`, or a full **`ExecRequest`**:
232
+
233
+ ```python
234
+ from voidrun.api_client.models.exec_request import ExecRequest
235
+
236
+ r = sandbox.exec("uname -a")
237
+ r = sandbox.exec(command="pwd", cwd="/tmp", timeout=60)
238
+ r = sandbox.exec(ExecRequest(command="ls", cwd="/"))
239
+ ```
240
+
241
+ Return type: **`VoidRunResponse[ExecResponseData]`**: the API’s outer **`ExecResponse`** envelope is unwrapped so **`r.data`** is **`ExecResponseData`** (stdout / stderr / exit_code):
242
+
243
+ ```python
244
+ print(r.data.stdout, r.data.stderr, r.data.exit_code)
245
+ ```
246
+
247
+ ### Streaming (`exec_stream`)
248
+
249
+ Provide callbacks for SSE events (`on_stdout`, `on_stderr`, `on_exit`, `on_error`).
250
+
251
+ ### Interpreter and `run_code`
252
+
253
+ `sandbox.interpreter` is a **`CodeInterpreter`**. Both `interpreter.run(...)` and **`sandbox.run_code(...)`** return **`CodeExecutionResult`** directly (no `.data` nesting):
254
+
255
+ ```python
256
+ result = sandbox.run_code("print(2 + 2)", language="python")
257
+ print(result.stdout.strip()) # "4"
258
+ print(result.success)
259
+
260
+ result = sandbox.interpreter.run("console.log(1+1)", language="javascript")
261
+ ```
262
+
263
+ **Supported languages** (typical): `python`, `javascript`, `typescript`, `node`, `bash`, `sh` (as supported by your VoidRun deployment).
264
+
265
+ ## Background commands
266
+
267
+ ```python
268
+ run_result = sandbox.commands.run(
269
+ "sleep 5 && echo done",
270
+ {"DEBUG": "true"},
271
+ "/tmp",
272
+ 0,
273
+ )
274
+ print(run_result.data.pid)
275
+
276
+ sandbox.commands.list()
277
+ sandbox.commands.connect(pid, on_stdout=..., on_stderr=..., on_exit=...)
278
+ sandbox.commands.wait(pid)
279
+ sandbox.commands.kill(pid)
280
+ ```
281
+
282
+ Response shapes follow the generated OpenAPI models; access fields via `.data` on `VoidRunResponse` where applicable.
283
+
284
+ ## File system
285
+
286
+ ```python
287
+ sandbox.fs.create_file("/tmp/hello.txt")
288
+ sandbox.fs.upload_file("/tmp/hello.txt", "Hello, World!")
289
+ sandbox.fs.upload_file_from_path("/tmp/remote.txt", "/local/file.txt")
290
+
291
+ data = sandbox.fs.download_file("/tmp/hello.txt")
292
+ sandbox.fs.delete_file("/tmp/hello.txt")
293
+
294
+ result = sandbox.fs.list_files("/tmp")
295
+ files = result.data
296
+
297
+ sandbox.fs.stat_file("/tmp/hello.txt")
298
+ sandbox.fs.create_directory("/tmp/mydir")
299
+ sandbox.fs.move_file("/tmp/a.txt", "/tmp/b.txt")
300
+ sandbox.fs.copy_file("/tmp/a.txt", "/tmp/copy.txt")
301
+ sandbox.fs.change_permissions("/tmp/a.txt", "755")
302
+
303
+ sandbox.fs.head_tail("/tmp/log.txt", head=True, lines=10)
304
+ sandbox.fs.search_files("/tmp", "*.txt")
305
+ sandbox.fs.disk_usage("/tmp")
306
+
307
+ archive = sandbox.fs.compress_file("/tmp", "tar.gz")
308
+ sandbox.fs.extract_archive("/tmp/archive.tar.gz", "/tmp/extracted")
309
+ ```
310
+
311
+ ## File watching (async)
312
+
313
+ ```python
314
+ import asyncio
315
+ from voidrun import AsyncVoidRun
316
+
317
+ async def watch_tmp():
318
+ async with AsyncVoidRun() as vr:
319
+ sandbox = await vr.create_sandbox()
320
+
321
+ watcher = await sandbox.fs.watch(
322
+ "/app",
323
+ recursive=True,
324
+ on_event=lambda evt: print(evt.get("path"), evt.get("type")),
325
+ on_error=lambda err: print("watch error:", err),
326
+ )
327
+
328
+ await asyncio.sleep(60)
329
+ watcher.close()
330
+ await sandbox.remove_async()
331
+
332
+ asyncio.run(watch_tmp())
333
+ ```
334
+
335
+ ## Pseudo-terminal (PTY)
336
+
337
+ ### Ephemeral session
338
+
339
+ ```python
340
+ import asyncio
341
+ from voidrun import AsyncVoidRun
342
+
343
+ async def ephemeral():
344
+ async with AsyncVoidRun() as vr:
345
+ sandbox = await vr.create_sandbox()
346
+ pty = await sandbox.pty.connect(
347
+ on_data=lambda data: print(data, end=""),
348
+ on_error=lambda err: print("PTY error:", err),
349
+ )
350
+ pty.send_input('echo "Hello"\n')
351
+ await asyncio.sleep(2)
352
+ await pty.close()
353
+ await sandbox.remove_async()
354
+
355
+ asyncio.run(ephemeral())
356
+ ```
357
+
358
+ ### Persistent session
359
+
360
+ ```python
361
+ async def persistent():
362
+ async with AsyncVoidRun() as vr:
363
+ sandbox = await vr.create_sandbox()
364
+ response = sandbox.pty.create_session()
365
+ session_id = response.data.data.session_id
366
+
367
+ pty = await sandbox.pty.connect(
368
+ session_id=session_id,
369
+ on_data=lambda data: print(data, end=""),
370
+ )
371
+ pty.send_input('echo "Hello"\n')
372
+ await pty.close()
373
+
374
+ reconnected = await sandbox.pty.connect(
375
+ session_id=session_id,
376
+ on_data=lambda data: print(data, end=""),
377
+ )
378
+ await reconnected.close()
379
+
380
+ sandbox.pty.delete_session(session_id)
381
+ await sandbox.remove_async()
382
+ ```
383
+
384
+ ### Helpers
385
+
386
+ ```python
387
+ # After connect(...)
388
+ output = await pty.run_command("ls -la", timeout=5000, prompt="# ")
389
+ await pty.resize(80, 24)
390
+
391
+ sandbox.pty.list()
392
+ sandbox.pty.delete_session(session_id)
393
+ ```
394
+
395
+ ## API reference (summary)
396
+
397
+ ### Exports (`from voidrun import ...`)
398
+
399
+ `VoidRun`, `AsyncVoidRun`, `Sandbox`, `CodeInterpreter`, `Interpreter` (alias), `CodeExecutionResult`, `ListSandboxesResult`, `ListSandboxesMeta`, `DEFAULT_SANDBOX_*`.
400
+
401
+ ### `CodeExecutionResult`
402
+
403
+ | Field | Type | Description |
404
+ |-------|------|-------------|
405
+ | `success` | `bool` | Derived from exit code. |
406
+ | `stdout` / `stderr` | `str` | Combined streams. |
407
+ | `exit_code` | `int \| None` | Process exit code. |
408
+ | `results` | `Any` | Parsed output when applicable. |
409
+ | `error` | `str \| None` | Error hint (often stderr). |
410
+ | `logs` | `dict` | e.g. `stdout` / `stderr` line lists. |
411
+
412
+ ### OpenAPI client
413
+
414
+ The package includes a generated **`voidrun.api_client`** module. Regenerate it when the VoidRun OpenAPI specification changes (same spec as other official clients). After regen, confirm **sandbox `status`** values still match the server (e.g. `running`, `stopped`, `paused`, `error`, `killed`, `deleted`, …).
415
+
416
+ ## Runnable examples
417
+
418
+ The [`examples/`](examples/) directory contains scripts for sync/async usage, exec, FS, lifecycle, PTY, background commands, and the code interpreter.
419
+
420
+ **Run all examples** (loads `py-sdk/.env` if present, sets `PYTHONPATH`):
421
+
422
+ ```bash
423
+ chmod +x scripts/run_all_examples.sh # once
424
+ ./scripts/run_all_examples.sh
425
+ ```
426
+
427
+ The script exits with status **1** if any example fails (useful for CI).
428
+
429
+ **Single example**
430
+
431
+ From the `py-sdk` directory (with `PYTHONPATH` including the repo root, same as the batch script):
432
+
433
+ ```bash
434
+ export VR_API_KEY="your-api-key"
435
+ export PYTHONPATH="$(pwd)"
436
+
437
+ python3 examples/sync_usage.py
438
+ python3 examples/async_usage.py
439
+ ```
440
+
441
+ Use an API key from the same VoidRun deployment as the API host (hosted default, or set **`VR_API_URL`** for self-hosted).
442
+
443
+ ## Development and tests
444
+
445
+ ```bash
446
+ cd py-sdk
447
+ pip install -e .
448
+ pip install pytest pytest-asyncio pytest-mock
449
+
450
+ pytest tests/
451
+ ```
452
+
453
+ Hatch shortcut:
454
+
455
+ ```bash
456
+ hatch run test
457
+ hatch run all-examples # runs scripts/run_all_examples.sh
458
+ ```
459
+
460
+ ## Building and publishing
461
+
462
+ ```bash
463
+ pip install build
464
+ python -m build
465
+ ```
466
+
467
+ Or with Poetry: `poetry build` / `poetry publish`. See [`pyproject.toml`](pyproject.toml) for package metadata.
468
+
469
+ ## Error handling
470
+
471
+ Failures raise exceptions from the OpenAPI client (for example **`ApiException`**) with HTTP status and body. Parse the error body for `error` and `details` fields returned by the VoidRun API.
472
+
473
+ ```python
474
+ from voidrun import VoidRun
475
+ from voidrun.api_client.rest import ApiException
476
+
477
+ vr = VoidRun()
478
+
479
+ try:
480
+ vr.get_sandbox("nonexistent-id")
481
+ except ApiException as e:
482
+ print(e.status, e.body)
483
+ ```
484
+
485
+ ## Troubleshooting
486
+
487
+ ### "API key is required …"
488
+
489
+ Set `VR_API_KEY` or pass `api_key=` to the constructor.
490
+
491
+ ### "Base URL is required …"
492
+
493
+ You cleared the base URL (for example empty **`VR_API_URL`**). Omit the variable to use the packaged default, or set **`VR_API_URL`** / **`API_URL`** (self-hosted) with the correct prefix (often `/api`).
494
+
495
+ ### Unauthorized / invalid API key
496
+
497
+ The key must match the VoidRun API you are calling (hosted default host or your self-hosted **`VR_API_URL`**). A local `.env` pointing at `localhost` with a cloud key (or vice versa) will return 401.
498
+
499
+ ### Sandbox creation failures
500
+
501
+ Respect minimum **CPU** and **memory** enforced by your org/plan. Defaults are 1 CPU and 1024 MB; increase if the API rejects smaller values.
502
+
503
+ ### PTY timeouts
504
+
505
+ Increase `timeout` in `run_command`, or allow more time before closing the session.
506
+
507
+ ### File not found
508
+
509
+ List parent directories with `sandbox.fs.list_files` and confirm paths inside the sandbox.
510
+
511
+ ## Contributing, license, support
512
+
513
+ Contributions are welcome; see the repository’s contributing guidelines if present.
514
+
515
+ - **License:** MIT: see the `LICENSE` file.
516
+ - **PyPI:** [voidrun](https://pypi.org/project/voidrun/)
517
+ - **Issues / discussions:** [GitHub](https://github.com/voidrun/py-sdk)
518
+ - **Contact:** support@voidrun.io (see [`pyproject.toml`](pyproject.toml) authors)
519
+
520
+ ---
521
+
522
+ Made with care by VoidRun.