scalebox-sdk 0.1.4__py3-none-any.whl → 0.1.25__py3-none-any.whl

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 (68) hide show
  1. scalebox/__init__.py +1 -1
  2. scalebox/api/__init__.py +128 -128
  3. scalebox/api/client/__init__.py +8 -8
  4. scalebox/api/client/api/sandboxes/get_sandboxes.py +5 -3
  5. scalebox/api/client/api/sandboxes/get_sandboxes_sandbox_id_metrics.py +2 -2
  6. scalebox/api/client/api/sandboxes/post_sandboxes.py +2 -2
  7. scalebox/api/client/client.py +288 -288
  8. scalebox/api/client/models/listed_sandbox.py +11 -9
  9. scalebox/api/client/models/new_sandbox.py +1 -1
  10. scalebox/api/client/models/sandbox.py +125 -125
  11. scalebox/api/client/models/sandbox_state.py +1 -0
  12. scalebox/api/client/types.py +46 -46
  13. scalebox/code_interpreter/code_interpreter_async.py +370 -369
  14. scalebox/code_interpreter/code_interpreter_sync.py +318 -317
  15. scalebox/connection_config.py +92 -92
  16. scalebox/csx_desktop/main.py +12 -12
  17. scalebox/generated/api_pb2_connect.py +17 -66
  18. scalebox/sandbox_async/commands/command.py +307 -307
  19. scalebox/sandbox_async/commands/command_handle.py +187 -187
  20. scalebox/sandbox_async/commands/pty.py +187 -187
  21. scalebox/sandbox_async/filesystem/filesystem.py +557 -557
  22. scalebox/sandbox_async/filesystem/watch_handle.py +61 -61
  23. scalebox/sandbox_async/main.py +647 -646
  24. scalebox/sandbox_async/sandbox_api.py +365 -365
  25. scalebox/sandbox_async/utils.py +7 -7
  26. scalebox/sandbox_sync/__init__.py +2 -2
  27. scalebox/sandbox_sync/commands/command.py +300 -300
  28. scalebox/sandbox_sync/commands/command_handle.py +150 -150
  29. scalebox/sandbox_sync/commands/pty.py +181 -181
  30. scalebox/sandbox_sync/filesystem/filesystem.py +543 -543
  31. scalebox/sandbox_sync/filesystem/watch_handle.py +66 -66
  32. scalebox/sandbox_sync/main.py +789 -790
  33. scalebox/sandbox_sync/sandbox_api.py +356 -356
  34. scalebox/test/CODE_INTERPRETER_TESTS_READY.md +256 -256
  35. scalebox/test/README.md +164 -164
  36. scalebox/test/aclient.py +72 -72
  37. scalebox/test/code_interpreter_centext.py +21 -21
  38. scalebox/test/code_interpreter_centext_sync.py +21 -21
  39. scalebox/test/code_interpreter_test.py +1 -1
  40. scalebox/test/code_interpreter_test_sync.py +1 -1
  41. scalebox/test/run_all_validation_tests.py +334 -334
  42. scalebox/test/test_basic.py +78 -78
  43. scalebox/test/test_code_interpreter_async_comprehensive.py +2653 -2653
  44. scalebox/test/{test_code_interpreter_e2bsync_comprehensive.py → test_code_interpreter_execcode.py} +328 -392
  45. scalebox/test/test_code_interpreter_sync_comprehensive.py +3416 -3412
  46. scalebox/test/test_csx_desktop_examples.py +130 -0
  47. scalebox/test/test_sandbox_async_comprehensive.py +736 -738
  48. scalebox/test/test_sandbox_stress_and_edge_cases.py +778 -778
  49. scalebox/test/test_sandbox_sync_comprehensive.py +779 -770
  50. scalebox/test/test_sandbox_usage_examples.py +987 -987
  51. scalebox/test/testacreate.py +24 -24
  52. scalebox/test/testagetinfo.py +18 -18
  53. scalebox/test/testcodeinterpreter_async.py +508 -508
  54. scalebox/test/testcodeinterpreter_sync.py +239 -239
  55. scalebox/test/testcomputeuse.py +2 -2
  56. scalebox/test/testnovnc.py +12 -12
  57. scalebox/test/testsandbox_api.py +15 -0
  58. scalebox/test/testsandbox_async.py +202 -118
  59. scalebox/test/testsandbox_sync.py +71 -38
  60. scalebox/version.py +2 -2
  61. {scalebox_sdk-0.1.4.dist-info → scalebox_sdk-0.1.25.dist-info}/METADATA +104 -103
  62. {scalebox_sdk-0.1.4.dist-info → scalebox_sdk-0.1.25.dist-info}/RECORD +66 -66
  63. scalebox/test/test_code_interpreter_e2basync_comprehensive.py +0 -2655
  64. scalebox/test/test_e2b_first.py +0 -11
  65. {scalebox_sdk-0.1.4.dist-info → scalebox_sdk-0.1.25.dist-info}/WHEEL +0 -0
  66. {scalebox_sdk-0.1.4.dist-info → scalebox_sdk-0.1.25.dist-info}/entry_points.txt +0 -0
  67. {scalebox_sdk-0.1.4.dist-info → scalebox_sdk-0.1.25.dist-info}/licenses/LICENSE +0 -0
  68. {scalebox_sdk-0.1.4.dist-info → scalebox_sdk-0.1.25.dist-info}/top_level.txt +0 -0
@@ -1,356 +1,356 @@
1
- import datetime
2
- import urllib.parse
3
- from typing import Dict, List, Optional
4
-
5
- from packaging.version import Version
6
-
7
- from ..api import ApiClient, SandboxCreateResponse, handle_api_exception
8
- from ..api.client.api.sandboxes import (
9
- delete_sandboxes_sandbox_id,
10
- get_sandboxes,
11
- get_sandboxes_sandbox_id,
12
- get_sandboxes_sandbox_id_metrics,
13
- post_sandboxes,
14
- post_sandboxes_sandbox_id_timeout,
15
- )
16
- from ..api.client.models import Error, NewSandbox, PostSandboxesSandboxIDTimeoutBody
17
- from ..connection_config import ConnectionConfig, ProxyTypes
18
- from ..exceptions import SandboxException, TemplateException
19
- from ..sandbox.sandbox_api import (
20
- ListedSandbox,
21
- SandboxApiBase,
22
- SandboxInfo,
23
- SandboxMetrics,
24
- SandboxQuery,
25
- )
26
-
27
-
28
- class SandboxApi(SandboxApiBase):
29
- @classmethod
30
- def list(
31
- cls,
32
- api_key: Optional[str] = None,
33
- query: Optional[SandboxQuery] = None,
34
- domain: Optional[str] = None,
35
- debug: Optional[bool] = None,
36
- request_timeout: Optional[float] = None,
37
- headers: Optional[Dict[str, str]] = None,
38
- proxy: Optional[ProxyTypes] = None,
39
- ) -> List[ListedSandbox]:
40
- """
41
- List all running sandboxes.
42
-
43
- :param api_key: API key to use for authentication, defaults to `E2B_API_KEY` environment variable
44
- :param query: Filter the list of sandboxes, e.g. by metadata `SandboxQuery(metadata={"key": "value"})`, if there are multiple filters they are combined with AND.
45
- :param domain: Domain to use for the request, only relevant for self-hosted environments
46
- :param debug: Enable debug mode, all requested are then sent to localhost
47
- :param request_timeout: Timeout for the request in **seconds**
48
- :param headers: Additional headers to send with the request
49
- :param proxy: Proxy to use for the request
50
-
51
- :return: List of running sandboxes
52
- """
53
- config = ConnectionConfig(
54
- api_key=api_key,
55
- domain=domain,
56
- debug=debug,
57
- request_timeout=request_timeout,
58
- headers=headers,
59
- proxy=proxy,
60
- )
61
-
62
- # Convert filters to the format expected by the API
63
- metadata = None
64
- if query:
65
- if query.metadata:
66
- quoted_metadata = {
67
- urllib.parse.quote(k): urllib.parse.quote(v)
68
- for k, v in query.metadata.items()
69
- }
70
- metadata = urllib.parse.urlencode(quoted_metadata)
71
-
72
- with ApiClient(
73
- config,
74
- limits=SandboxApiBase._limits,
75
- ) as api_client:
76
- res = get_sandboxes.sync_detailed(client=api_client, metadata=metadata)
77
-
78
- if res.status_code >= 300:
79
- raise handle_api_exception(res)
80
-
81
- if res.parsed is None:
82
- return []
83
-
84
- return [
85
- ListedSandbox(
86
- sandbox_id=sandbox.sandbox_id,
87
- template_id=sandbox.template_id,
88
- name=sandbox.alias if isinstance(sandbox.alias, str) else None,
89
- metadata=(
90
- sandbox.metadata if isinstance(sandbox.metadata, dict) else {}
91
- ),
92
- state=sandbox.state,
93
- cpu_count=sandbox.cpu_count,
94
- memory_mb=sandbox.memory_mb,
95
- started_at=sandbox.started_at,
96
- end_at=sandbox.end_at,
97
- )
98
- for sandbox in res.parsed
99
- ]
100
-
101
- @classmethod
102
- def _cls_get_info(
103
- cls,
104
- sandbox_id: str,
105
- api_key: Optional[str] = None,
106
- domain: Optional[str] = None,
107
- debug: Optional[bool] = None,
108
- request_timeout: Optional[float] = None,
109
- headers: Optional[Dict[str, str]] = None,
110
- proxy: Optional[ProxyTypes] = None,
111
- ) -> SandboxInfo:
112
- """
113
- Get the sandbox info.
114
- :param sandbox_id: Sandbox ID
115
- :param api_key: API key to use for authentication, defaults to `E2B_API_KEY` environment variable
116
- :param domain: Domain to use for the request, defaults to `E2B_DOMAIN` environment variable
117
- :param debug: Debug mode, defaults to `E2B_DEBUG` environment variable
118
- :param request_timeout: Timeout for the request in **seconds**
119
- :param headers: Additional headers to send with the request
120
-
121
- :return: Sandbox info
122
- """
123
- config = ConnectionConfig(
124
- api_key=api_key,
125
- domain=domain,
126
- debug=debug,
127
- request_timeout=request_timeout,
128
- headers=headers,
129
- proxy=proxy,
130
- )
131
-
132
- with ApiClient(
133
- config,
134
- limits=SandboxApiBase._limits,
135
- ) as api_client:
136
- res = get_sandboxes_sandbox_id.sync_detailed(
137
- sandbox_id,
138
- client=api_client,
139
- )
140
-
141
- if res.status_code >= 300:
142
- raise handle_api_exception(res)
143
-
144
- if res.parsed is None:
145
- raise Exception("Body of the request is None")
146
-
147
- return SandboxInfo(
148
- sandbox_id=res.parsed.sandbox_id,
149
- sandbox_domain=res.parsed.domain,
150
- template_id=res.parsed.template_id,
151
- name=res.parsed.alias if isinstance(res.parsed.alias, str) else None,
152
- metadata=(
153
- res.parsed.metadata if isinstance(res.parsed.metadata, dict) else {}
154
- ),
155
- started_at=res.parsed.started_at,
156
- end_at=res.parsed.end_at,
157
- envd_version=res.parsed.envd_version,
158
- _envd_access_token=res.parsed.envd_access_token,
159
- )
160
-
161
- @classmethod
162
- def _cls_kill(
163
- cls,
164
- sandbox_id: str,
165
- api_key: Optional[str] = None,
166
- domain: Optional[str] = None,
167
- debug: Optional[bool] = None,
168
- request_timeout: Optional[float] = None,
169
- headers: Optional[Dict[str, str]] = None,
170
- proxy: Optional[ProxyTypes] = None,
171
- ) -> bool:
172
- config = ConnectionConfig(
173
- api_key=api_key,
174
- domain=domain,
175
- debug=debug,
176
- request_timeout=request_timeout,
177
- headers=headers,
178
- proxy=proxy,
179
- )
180
-
181
- if config.debug:
182
- # Skip killing the sandbox in debug mode
183
- return True
184
-
185
- with ApiClient(
186
- config,
187
- limits=SandboxApiBase._limits,
188
- ) as api_client:
189
- res = delete_sandboxes_sandbox_id.sync_detailed(
190
- sandbox_id,
191
- client=api_client,
192
- )
193
-
194
- if res.status_code == 404:
195
- return False
196
-
197
- if res.status_code >= 300:
198
- raise handle_api_exception(res)
199
-
200
- return True
201
-
202
- @classmethod
203
- def _cls_set_timeout(
204
- cls,
205
- sandbox_id: str,
206
- timeout: int,
207
- api_key: Optional[str] = None,
208
- domain: Optional[str] = None,
209
- debug: Optional[bool] = None,
210
- request_timeout: Optional[float] = None,
211
- headers: Optional[Dict[str, str]] = None,
212
- proxy: Optional[ProxyTypes] = None,
213
- ) -> None:
214
- config = ConnectionConfig(
215
- api_key=api_key,
216
- domain=domain,
217
- debug=debug,
218
- request_timeout=request_timeout,
219
- headers=headers,
220
- proxy=proxy,
221
- )
222
-
223
- if config.debug:
224
- # Skip setting timeout in debug mode
225
- return
226
-
227
- with ApiClient(
228
- config,
229
- limits=SandboxApiBase._limits,
230
- ) as api_client:
231
- res = post_sandboxes_sandbox_id_timeout.sync_detailed(
232
- sandbox_id,
233
- client=api_client,
234
- body=PostSandboxesSandboxIDTimeoutBody(timeout=timeout),
235
- )
236
-
237
- if res.status_code >= 300:
238
- raise handle_api_exception(res)
239
-
240
- @classmethod
241
- def _create_sandbox(
242
- cls,
243
- template: str,
244
- timeout: int,
245
- metadata: Optional[Dict[str, str]] = None,
246
- env_vars: Optional[Dict[str, str]] = None,
247
- secure: Optional[bool] = None,
248
- api_key: Optional[str] = None,
249
- domain: Optional[str] = None,
250
- debug: Optional[bool] = None,
251
- request_timeout: Optional[float] = None,
252
- headers: Optional[Dict[str, str]] = None,
253
- proxy: Optional[ProxyTypes] = None,
254
- allow_internet_access: Optional[bool] = True,
255
- ) -> SandboxCreateResponse:
256
- config = ConnectionConfig(
257
- api_key=api_key,
258
- domain=domain,
259
- debug=debug,
260
- request_timeout=request_timeout,
261
- headers=headers,
262
- proxy=proxy,
263
- )
264
-
265
- with ApiClient(config, limits=SandboxApiBase._limits) as api_client:
266
- res = post_sandboxes.sync_detailed(
267
- body=NewSandbox(
268
- template_id=template,
269
- metadata=metadata or {},
270
- timeout=timeout,
271
- env_vars=env_vars or {},
272
- secure=secure or False,
273
- allow_internet_access=allow_internet_access,
274
- ),
275
- client=api_client,
276
- )
277
-
278
- if res.status_code >= 300:
279
- raise handle_api_exception(res)
280
-
281
- if res.parsed is None:
282
- raise Exception("Body of the request is None")
283
-
284
- # if Version(res.parsed.envd_version) < Version("0.1.0"):
285
- # SandboxApi._cls_kill(res.parsed.sandbox_id)
286
- # raise TemplateException(
287
- # "You need to update the template to use the new SDK. "
288
- # "You can do this by running `e2b template build` in the directory with the template."
289
- # )
290
-
291
- return SandboxCreateResponse(
292
- sandbox_id=res.parsed.sandbox_id,
293
- sandbox_domain=res.parsed.domain,
294
- envd_version=res.parsed.envd_version,
295
- envd_access_token=res.parsed.envd_access_token,
296
- )
297
-
298
- @classmethod
299
- def _cls_get_metrics(
300
- cls,
301
- sandbox_id: str,
302
- start: Optional[datetime.datetime] = None,
303
- end: Optional[datetime.datetime] = None,
304
- api_key: Optional[str] = None,
305
- domain: Optional[str] = None,
306
- debug: Optional[bool] = None,
307
- request_timeout: Optional[float] = None,
308
- headers: Optional[Dict[str, str]] = None,
309
- proxy: Optional[ProxyTypes] = None,
310
- ) -> List[SandboxMetrics]:
311
- config = ConnectionConfig(
312
- api_key=api_key,
313
- domain=domain,
314
- debug=debug,
315
- request_timeout=request_timeout,
316
- headers=headers,
317
- proxy=proxy,
318
- )
319
-
320
- if config.debug:
321
- # Skip getting the metrics in debug mode
322
- return []
323
-
324
- with ApiClient(
325
- config,
326
- limits=cls._limits,
327
- ) as api_client:
328
- res = get_sandboxes_sandbox_id_metrics.sync_detailed(
329
- sandbox_id,
330
- start=int(start.timestamp() * 1000) if start else None,
331
- end=int(end.timestamp() * 1000) if end else None,
332
- client=api_client,
333
- )
334
-
335
- if res.status_code >= 300:
336
- raise handle_api_exception(res)
337
-
338
- if res.parsed is None:
339
- return []
340
-
341
- if isinstance(res.parsed, Error):
342
- raise SandboxException(f"{res.parsed.message}: Request failed")
343
-
344
- # Convert to typed SandboxMetrics objects
345
- return [
346
- SandboxMetrics(
347
- cpu_count=metric.cpu_count,
348
- cpu_used_pct=metric.cpu_used_pct,
349
- disk_total=metric.disk_total,
350
- disk_used=metric.disk_used,
351
- mem_total=metric.mem_total,
352
- mem_used=metric.mem_used,
353
- timestamp=metric.timestamp,
354
- )
355
- for metric in res.parsed
356
- ]
1
+ import datetime
2
+ import urllib.parse
3
+ from typing import Dict, List, Optional
4
+
5
+ from packaging.version import Version
6
+
7
+ from ..api import ApiClient, SandboxCreateResponse, handle_api_exception
8
+ from ..api.client.api.sandboxes import (
9
+ delete_sandboxes_sandbox_id,
10
+ get_sandboxes,
11
+ get_sandboxes_sandbox_id,
12
+ get_sandboxes_sandbox_id_metrics,
13
+ post_sandboxes,
14
+ post_sandboxes_sandbox_id_timeout,
15
+ )
16
+ from ..api.client.models import Error, NewSandbox, PostSandboxesSandboxIDTimeoutBody
17
+ from ..connection_config import ConnectionConfig, ProxyTypes
18
+ from ..exceptions import SandboxException, TemplateException
19
+ from ..sandbox.sandbox_api import (
20
+ ListedSandbox,
21
+ SandboxApiBase,
22
+ SandboxInfo,
23
+ SandboxMetrics,
24
+ SandboxQuery,
25
+ )
26
+
27
+
28
+ class SandboxApi(SandboxApiBase):
29
+ @classmethod
30
+ def list(
31
+ cls,
32
+ api_key: Optional[str] = None,
33
+ query: Optional[SandboxQuery] = None,
34
+ domain: Optional[str] = None,
35
+ debug: Optional[bool] = None,
36
+ request_timeout: Optional[float] = None,
37
+ headers: Optional[Dict[str, str]] = None,
38
+ proxy: Optional[ProxyTypes] = None,
39
+ ) -> List[ListedSandbox]:
40
+ """
41
+ List all running sandboxes.
42
+
43
+ :param api_key: API key to use for authentication, defaults to `SBX_API_KEY` environment variable
44
+ :param query: Filter the list of sandboxes, e.g. by metadata `SandboxQuery(metadata={"key": "value"})`, if there are multiple filters they are combined with AND.
45
+ :param domain: Domain to use for the request, only relevant for self-hosted environments
46
+ :param debug: Enable debug mode, all requested are then sent to localhost
47
+ :param request_timeout: Timeout for the request in **seconds**
48
+ :param headers: Additional headers to send with the request
49
+ :param proxy: Proxy to use for the request
50
+
51
+ :return: List of running sandboxes
52
+ """
53
+ config = ConnectionConfig(
54
+ api_key=api_key,
55
+ domain=domain,
56
+ debug=debug,
57
+ request_timeout=request_timeout,
58
+ headers=headers,
59
+ proxy=proxy,
60
+ )
61
+
62
+ # Convert filters to the format expected by the API
63
+ metadata = None
64
+ if query:
65
+ if query.metadata:
66
+ quoted_metadata = {
67
+ urllib.parse.quote(k): urllib.parse.quote(v)
68
+ for k, v in query.metadata.items()
69
+ }
70
+ metadata = urllib.parse.urlencode(quoted_metadata)
71
+
72
+ with ApiClient(
73
+ config,
74
+ limits=SandboxApiBase._limits,
75
+ ) as api_client:
76
+ res = get_sandboxes.sync_detailed(client=api_client, metadata=metadata)
77
+
78
+ if res.status_code >= 300:
79
+ raise handle_api_exception(res)
80
+
81
+ if res.parsed is None:
82
+ return []
83
+
84
+ return [
85
+ ListedSandbox(
86
+ sandbox_id=sandbox.sandbox_id,
87
+ template_id=sandbox.template_id,
88
+ name=sandbox.alias if isinstance(sandbox.alias, str) else None,
89
+ metadata=(
90
+ sandbox.metadata if isinstance(sandbox.metadata, dict) else {}
91
+ ),
92
+ state=sandbox.state,
93
+ cpu_count=sandbox.cpu_count,
94
+ memory_mb=sandbox.memory_mb,
95
+ started_at=sandbox.started_at,
96
+ end_at=sandbox.end_at,
97
+ )
98
+ for sandbox in res.parsed
99
+ ]
100
+
101
+ @classmethod
102
+ def _cls_get_info(
103
+ cls,
104
+ sandbox_id: str,
105
+ api_key: Optional[str] = None,
106
+ domain: Optional[str] = None,
107
+ debug: Optional[bool] = None,
108
+ request_timeout: Optional[float] = None,
109
+ headers: Optional[Dict[str, str]] = None,
110
+ proxy: Optional[ProxyTypes] = None,
111
+ ) -> SandboxInfo:
112
+ """
113
+ Get the sandbox info.
114
+ :param sandbox_id: Sandbox ID
115
+ :param api_key: API key to use for authentication, defaults to `SBX_API_KEY` environment variable
116
+ :param domain: Domain to use for the request, defaults to `SBX_DOMAIN` environment variable
117
+ :param debug: Debug mode, defaults to `SBX_DEBUG` environment variable
118
+ :param request_timeout: Timeout for the request in **seconds**
119
+ :param headers: Additional headers to send with the request
120
+
121
+ :return: Sandbox info
122
+ """
123
+ config = ConnectionConfig(
124
+ api_key=api_key,
125
+ domain=domain,
126
+ debug=debug,
127
+ request_timeout=request_timeout,
128
+ headers=headers,
129
+ proxy=proxy,
130
+ )
131
+
132
+ with ApiClient(
133
+ config,
134
+ limits=SandboxApiBase._limits,
135
+ ) as api_client:
136
+ res = get_sandboxes_sandbox_id.sync_detailed(
137
+ sandbox_id,
138
+ client=api_client,
139
+ )
140
+
141
+ if res.status_code >= 300:
142
+ raise handle_api_exception(res)
143
+
144
+ if res.parsed is None:
145
+ raise Exception("Body of the request is None")
146
+
147
+ return SandboxInfo(
148
+ sandbox_id=res.parsed.sandbox_id,
149
+ sandbox_domain=res.parsed.domain,
150
+ template_id=res.parsed.template_id,
151
+ name=res.parsed.alias if isinstance(res.parsed.alias, str) else None,
152
+ metadata=(
153
+ res.parsed.metadata if isinstance(res.parsed.metadata, dict) else {}
154
+ ),
155
+ started_at=res.parsed.started_at,
156
+ end_at=res.parsed.end_at,
157
+ envd_version=res.parsed.envd_version,
158
+ _envd_access_token=res.parsed.envd_access_token,
159
+ )
160
+
161
+ @classmethod
162
+ def _cls_kill(
163
+ cls,
164
+ sandbox_id: str,
165
+ api_key: Optional[str] = None,
166
+ domain: Optional[str] = None,
167
+ debug: Optional[bool] = None,
168
+ request_timeout: Optional[float] = None,
169
+ headers: Optional[Dict[str, str]] = None,
170
+ proxy: Optional[ProxyTypes] = None,
171
+ ) -> bool:
172
+ config = ConnectionConfig(
173
+ api_key=api_key,
174
+ domain=domain,
175
+ debug=debug,
176
+ request_timeout=request_timeout,
177
+ headers=headers,
178
+ proxy=proxy,
179
+ )
180
+
181
+ if config.debug:
182
+ # Skip killing the sandbox in debug mode
183
+ return True
184
+
185
+ with ApiClient(
186
+ config,
187
+ limits=SandboxApiBase._limits,
188
+ ) as api_client:
189
+ res = delete_sandboxes_sandbox_id.sync_detailed(
190
+ sandbox_id,
191
+ client=api_client,
192
+ )
193
+
194
+ if res.status_code == 404:
195
+ return False
196
+
197
+ if res.status_code >= 300:
198
+ raise handle_api_exception(res)
199
+
200
+ return True
201
+
202
+ @classmethod
203
+ def _cls_set_timeout(
204
+ cls,
205
+ sandbox_id: str,
206
+ timeout: int,
207
+ api_key: Optional[str] = None,
208
+ domain: Optional[str] = None,
209
+ debug: Optional[bool] = None,
210
+ request_timeout: Optional[float] = None,
211
+ headers: Optional[Dict[str, str]] = None,
212
+ proxy: Optional[ProxyTypes] = None,
213
+ ) -> None:
214
+ config = ConnectionConfig(
215
+ api_key=api_key,
216
+ domain=domain,
217
+ debug=debug,
218
+ request_timeout=request_timeout,
219
+ headers=headers,
220
+ proxy=proxy,
221
+ )
222
+
223
+ if config.debug:
224
+ # Skip setting timeout in debug mode
225
+ return
226
+
227
+ with ApiClient(
228
+ config,
229
+ limits=SandboxApiBase._limits,
230
+ ) as api_client:
231
+ res = post_sandboxes_sandbox_id_timeout.sync_detailed(
232
+ sandbox_id,
233
+ client=api_client,
234
+ body=PostSandboxesSandboxIDTimeoutBody(timeout=timeout),
235
+ )
236
+
237
+ if res.status_code >= 300:
238
+ raise handle_api_exception(res)
239
+
240
+ @classmethod
241
+ def _create_sandbox(
242
+ cls,
243
+ template: str,
244
+ timeout: int,
245
+ metadata: Optional[Dict[str, str]] = None,
246
+ env_vars: Optional[Dict[str, str]] = None,
247
+ secure: Optional[bool] = None,
248
+ api_key: Optional[str] = None,
249
+ domain: Optional[str] = None,
250
+ debug: Optional[bool] = None,
251
+ request_timeout: Optional[float] = None,
252
+ headers: Optional[Dict[str, str]] = None,
253
+ proxy: Optional[ProxyTypes] = None,
254
+ allow_internet_access: Optional[bool] = True,
255
+ ) -> SandboxCreateResponse:
256
+ config = ConnectionConfig(
257
+ api_key=api_key,
258
+ domain=domain,
259
+ debug=debug,
260
+ request_timeout=request_timeout,
261
+ headers=headers,
262
+ proxy=proxy,
263
+ )
264
+
265
+ with ApiClient(config, limits=SandboxApiBase._limits) as api_client:
266
+ res = post_sandboxes.sync_detailed(
267
+ body=NewSandbox(
268
+ template_id=template,
269
+ metadata=metadata or {},
270
+ timeout=timeout,
271
+ env_vars=env_vars or {},
272
+ secure=secure or False,
273
+ allow_internet_access=allow_internet_access,
274
+ ),
275
+ client=api_client,
276
+ )
277
+
278
+ if res.status_code >= 300:
279
+ raise handle_api_exception(res)
280
+
281
+ if res.parsed is None:
282
+ raise Exception("Body of the request is None")
283
+
284
+ # if Version(res.parsed.envd_version) < Version("0.1.0"):
285
+ # SandboxApi._cls_kill(res.parsed.sandbox_id)
286
+ # raise TemplateException(
287
+ # "You need to update the template to use the new SDK. "
288
+ # "You can do this by running `scalebox template build` in the directory with the template."
289
+ # )
290
+
291
+ return SandboxCreateResponse(
292
+ sandbox_id=res.parsed.sandbox_id,
293
+ sandbox_domain=res.parsed.domain,
294
+ envd_version=res.parsed.envd_version,
295
+ envd_access_token=res.parsed.envd_access_token,
296
+ )
297
+
298
+ @classmethod
299
+ def _cls_get_metrics(
300
+ cls,
301
+ sandbox_id: str,
302
+ start: Optional[datetime.datetime] = None,
303
+ end: Optional[datetime.datetime] = None,
304
+ api_key: Optional[str] = None,
305
+ domain: Optional[str] = None,
306
+ debug: Optional[bool] = None,
307
+ request_timeout: Optional[float] = None,
308
+ headers: Optional[Dict[str, str]] = None,
309
+ proxy: Optional[ProxyTypes] = None,
310
+ ) -> List[SandboxMetrics]:
311
+ config = ConnectionConfig(
312
+ api_key=api_key,
313
+ domain=domain,
314
+ debug=debug,
315
+ request_timeout=request_timeout,
316
+ headers=headers,
317
+ proxy=proxy,
318
+ )
319
+
320
+ if config.debug:
321
+ # Skip getting the metrics in debug mode
322
+ return []
323
+
324
+ with ApiClient(
325
+ config,
326
+ limits=cls._limits,
327
+ ) as api_client:
328
+ res = get_sandboxes_sandbox_id_metrics.sync_detailed(
329
+ sandbox_id,
330
+ start=int(start.timestamp() * 1000) if start else None,
331
+ end=int(end.timestamp() * 1000) if end else None,
332
+ client=api_client,
333
+ )
334
+
335
+ if res.status_code >= 300:
336
+ raise handle_api_exception(res)
337
+
338
+ if res.parsed is None:
339
+ return []
340
+
341
+ if isinstance(res.parsed, Error):
342
+ raise SandboxException(f"{res.parsed.message}: Request failed")
343
+
344
+ # Convert to typed SandboxMetrics objects
345
+ return [
346
+ SandboxMetrics(
347
+ cpu_count=metric.cpu_count,
348
+ cpu_used_pct=metric.cpu_used_pct,
349
+ disk_total=metric.disk_total,
350
+ disk_used=metric.disk_used,
351
+ mem_total=metric.mem_total,
352
+ mem_used=metric.mem_used,
353
+ timestamp=metric.timestamp,
354
+ )
355
+ for metric in res.parsed
356
+ ]