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,646 +1,647 @@
1
- import datetime
2
- import logging
3
- import time
4
- from typing import Dict, List, Optional, TypedDict, overload
5
-
6
- import aiohttp
7
- import httpx
8
- from aiohttp import TCPConnector
9
- from typing_extensions import Unpack
10
-
11
- from ..api.client.types import Unset
12
- from ..connection_config import ConnectionConfig, ProxyTypes
13
- from ..exceptions import SandboxException, request_timeout_error
14
- from ..generated.api import ENVD_API_HEALTH_ROUTE, ahandle_envd_api_exception
15
- from ..sandbox.main import SandboxSetup
16
- from ..sandbox.sandbox_api import SandboxMetrics
17
- from ..sandbox.utils import class_method_variant
18
- from ..sandbox_async.commands.command import Commands
19
- from ..sandbox_async.commands.pty import Pty
20
- from ..sandbox_async.filesystem.filesystem import Filesystem
21
- from ..sandbox_async.sandbox_api import SandboxApi, SandboxInfo
22
-
23
- logger = logging.getLogger(__name__)
24
-
25
-
26
- class AsyncTransportWithLogger(httpx.AsyncHTTPTransport):
27
- async def handle_async_request(self, request):
28
- url = f"{request.url.scheme}://{request.url.host}{request.url.path}"
29
- logger.info(f"Request: {request.method} {url}")
30
- response = await super().handle_async_request(request)
31
-
32
- # data = connect.GzipCompressor.decompress(response.read()).decode()
33
- logger.info(f"Response: {response.status_code} {url}")
34
-
35
- return response
36
-
37
-
38
- class AsyncSandboxOpts(TypedDict):
39
- sandbox_id: str
40
- sandbox_domain: Optional[str]
41
- envd_version: Optional[str]
42
- envd_access_token: Optional[str]
43
- connection_config: ConnectionConfig
44
-
45
-
46
- class AsyncSandbox(SandboxSetup, SandboxApi):
47
- """
48
- E2B cloud sandbox is a secure and isolated cloud environment.
49
-
50
- The sandbox allows you to:
51
- - Access Linux OS
52
- - Create, list, and delete files and directories
53
- - Run commands
54
- - Run isolated code
55
- - Access the internet
56
-
57
- Check docs [here](https://dev/docs).
58
-
59
- Use the `AsyncSandbox.create()` to create a new sandbox.
60
-
61
- Example:
62
- ```python
63
- from e2b import AsyncSandbox
64
-
65
- sandbox = await AsyncSandbox.create()
66
- ```
67
- """
68
-
69
- @property
70
- def files(self) -> Filesystem:
71
- """
72
- Module for interacting with the sandbox filesystem.
73
- """
74
- return self._filesystem
75
-
76
- @property
77
- def commands(self) -> Commands:
78
- """
79
- Module for running commands in the sandbox.
80
- """
81
- return self._commands
82
-
83
- @property
84
- def pty(self) -> Pty:
85
- """
86
- Module for interacting with the sandbox pseudo-terminal.
87
- """
88
- return self._pty
89
-
90
- @property
91
- def sandbox_id(self) -> str:
92
- """
93
- Unique identifier of the sandbox.
94
- """
95
- return self._sandbox_id
96
-
97
- @property
98
- def sandbox_domain(self) -> str:
99
- """
100
- Unique identifier of the sandbox.
101
- """
102
- return self._sandbox_domain
103
-
104
- @property
105
- def envd_api_url(self) -> str:
106
- return self._envd_api_url
107
-
108
- @property
109
- def _envd_access_token(self) -> str:
110
- """Private property to access the envd token"""
111
- return self.__envd_access_token
112
-
113
- @_envd_access_token.setter
114
- def _envd_access_token(self, value: str):
115
- """Private setter for envd token"""
116
- self.__envd_access_token = value
117
-
118
- @property
119
- def connection_config(self) -> ConnectionConfig:
120
- return self._connection_config
121
-
122
- def __init__(self, **opts: Unpack[AsyncSandboxOpts]):
123
- """
124
- Use `AsyncSandbox.create()` to create a new sandbox instead.
125
- """
126
- super().__init__()
127
-
128
- self._connection_config = opts["connection_config"]
129
-
130
- self._sandbox_id = opts["sandbox_id"]
131
- self._sandbox_domain = opts["sandbox_domain"] or self.connection_config.domain
132
- debug=self._connection_config.debug
133
- if debug:
134
- self._envd_api_url = f"http://{self.get_host(8888)}"
135
- else:
136
- self._envd_api_url = f"https://{self.get_host(self.envd_port)}"
137
- self._envd_version = opts["envd_version"]
138
- self._envd_access_token = opts["envd_access_token"]
139
- # connection_headers = {"Authorization": "Bearer root", }
140
-
141
- # self._envd_api_url =f"http://localhost:32119"
142
- self._envd_version =f"v1.0"
143
- # self._connection_config = ConnectionConfig(
144
- # headers=connection_headers,
145
- # )
146
-
147
- self._transport = AsyncTransportWithLogger(
148
- limits=self._limits, proxy=self._connection_config.proxy
149
- )
150
- self._envd_api = httpx.AsyncClient(
151
- base_url=self.envd_api_url,
152
- transport=self._transport,
153
- headers=self._connection_config.headers,
154
- )
155
- connector = TCPConnector(
156
- limit=100, # 最大连接数
157
- limit_per_host=20, # 每主机最大连接数
158
- keepalive_timeout=30, # 保持连接超时(秒)
159
- enable_cleanup_closed=True, # 清理已关闭的连接
160
- ssl=True # 是否使用 SSL
161
- )
162
- self._session = aiohttp.ClientSession(connector=connector,
163
- timeout=aiohttp.ClientTimeout(total=None))
164
- self._filesystem = Filesystem(
165
- self.envd_api_url,
166
- self._envd_version,
167
- self.connection_config,
168
- self._session,
169
- self._envd_api,
170
- )
171
- self._commands = Commands(
172
- self.envd_api_url,
173
- self.connection_config,
174
- self._session,
175
- )
176
- self._pty = Pty(
177
- self.envd_api_url,
178
- self.connection_config,
179
- self._session,
180
- )
181
-
182
- async def is_running(self, request_timeout: Optional[float] = None) -> bool:
183
- """
184
- Check if the sandbox is running.
185
-
186
- :param request_timeout: Timeout for the request in **seconds**
187
-
188
- :return: `True` if the sandbox is running, `False` otherwise
189
-
190
- Example
191
- ```python
192
- sandbox = await AsyncSandbox.create()
193
- await sandbox.is_running() # Returns True
194
-
195
- await sandbox.kill()
196
- await sandbox.is_running() # Returns False
197
- ```
198
- """
199
- try:
200
- r = await self._envd_api.get(
201
- ENVD_API_HEALTH_ROUTE,
202
- timeout=self.connection_config.get_request_timeout(request_timeout),
203
- )
204
-
205
- if r.status_code == 502:
206
- return False
207
-
208
- err = await ahandle_envd_api_exception(r)
209
-
210
- if err:
211
- raise err
212
-
213
- except httpx.TimeoutException:
214
- raise request_timeout_error()
215
-
216
- return True
217
-
218
- @classmethod
219
- async def create(
220
- cls,
221
- template: Optional[str] = None,
222
- timeout: Optional[int] = None,
223
- metadata: Optional[Dict[str, str]] = None,
224
- envs: Optional[Dict[str, str]] = None,
225
- api_key: Optional[str] = None,
226
- domain: Optional[str] = None,
227
- debug: Optional[bool] = None,
228
- request_timeout: Optional[float] = None,
229
- proxy: Optional[ProxyTypes] = None,
230
- secure: Optional[bool] = None,
231
- allow_internet_access: Optional[bool] = True,
232
- ):
233
- """
234
- Create a new sandbox.
235
-
236
- By default, the sandbox is created from the default `base` sandbox template.
237
-
238
- :param template: Sandbox template name or ID
239
- :param timeout: Timeout for the sandbox in **seconds**, default to 300 seconds. Maximum time a sandbox can be kept alive is 24 hours (86_400 seconds) for Pro users and 1 hour (3_600 seconds) for Hobby users.
240
- :param metadata: Custom metadata for the sandbox
241
- :param envs: Custom environment variables for the sandbox
242
- :param api_key: E2B API Key to use for authentication, defaults to `E2B_API_KEY` environment variable
243
- :param request_timeout: Timeout for the request in **seconds**
244
- :param proxy: Proxy to use for the request and for the **requests made to the returned sandbox**
245
- :param secure: Envd is secured with access token and cannot be used without it
246
- :param allow_internet_access: Allow sandbox to access the internet, defaults to `True`.
247
-
248
- :return: sandbox instance for the new sandbox
249
-
250
- Use this method instead of using the constructor to create a new sandbox.
251
- """
252
-
253
- connection_headers = {"Authorization": "Bearer root", }
254
- if debug:
255
- sandbox_id = "debug_sandbox_id"
256
- sandbox_domain = None
257
- envd_version = None
258
- envd_access_token = None
259
- else:
260
- response = await SandboxApi._create_sandbox(
261
- template=template or cls.default_template,
262
- api_key=api_key,
263
- timeout=timeout or cls.default_sandbox_timeout,
264
- metadata=metadata,
265
- domain=domain,
266
- debug=debug,
267
- request_timeout=request_timeout,
268
- env_vars=envs,
269
- secure=secure,
270
- proxy=proxy,
271
- allow_internet_access=allow_internet_access,
272
- )
273
-
274
- sandbox_id = response.sandbox_id
275
- sandbox_domain = response.sandbox_domain
276
- envd_version = response.envd_version
277
- envd_access_token = response.envd_access_token
278
-
279
- if envd_access_token is not None and not isinstance(
280
- envd_access_token, Unset
281
- ):
282
- connection_headers["X-Access-Token"] = envd_access_token
283
-
284
-
285
- connection_config = ConnectionConfig(
286
- api_key=api_key,
287
- domain=domain,
288
- debug=debug,
289
- request_timeout=request_timeout,
290
- headers=connection_headers,
291
- proxy=proxy,
292
- )
293
- print("connection_config"+str(connection_config.__dict__))
294
- sanbox = cls(
295
- sandbox_id=sandbox_id,
296
- sandbox_domain=sandbox_domain,
297
- envd_version=envd_version,
298
- envd_access_token=envd_access_token,
299
- connection_config=connection_config,
300
- )
301
- timeout = 5.0
302
- interval = 0.1
303
- elapsed = 0.0
304
-
305
- while elapsed <= timeout:
306
- try:
307
- isRunning = await sanbox.is_running(request_timeout=1)
308
- if isRunning:
309
- break
310
- except Exception:
311
- pass
312
- time.sleep(interval)
313
- elapsed += interval
314
- else:
315
- print("connect "+sandbox_domain+ENVD_API_HEALTH_ROUTE +" timeout 5s")
316
- return sanbox
317
-
318
- @classmethod
319
- async def connect(
320
- cls,
321
- sandbox_id: str,
322
- api_key: Optional[str] = None,
323
- domain: Optional[str] = None,
324
- debug: Optional[bool] = None,
325
- proxy: Optional[ProxyTypes] = None,
326
- ):
327
- """
328
- Connect to an existing sandbox.
329
- With sandbox ID you can connect to the same sandbox from different places or environments (serverless functions, etc).
330
-
331
- :param sandbox_id: Sandbox ID
332
- :param api_key: E2B API Key to use for authentication, defaults to `E2B_API_KEY` environment variable
333
- :param proxy: Proxy to use for the request and for the **requests made to the returned sandbox**
334
-
335
- :return: sandbox instance for the existing sandbox
336
-
337
- @example
338
- ```python
339
- sandbox = await AsyncSandbox.create()
340
- sandbox_id = sandbox.sandbox_id
341
-
342
- # Another code block
343
- same_sandbox = await AsyncSandbox.connect(sandbox_id)
344
- """
345
-
346
- connection_headers = {"Authorization": "Bearer root"}
347
-
348
- response = await SandboxApi._cls_get_info(
349
- sandbox_id,
350
- api_key=api_key,
351
- domain=domain,
352
- debug=debug,
353
- proxy=proxy,
354
- )
355
-
356
- if response._envd_access_token is not None and not isinstance(
357
- response._envd_access_token, Unset
358
- ):
359
- connection_headers["X-Access-Token"] = response._envd_access_token
360
-
361
- connection_config = ConnectionConfig(
362
- api_key=api_key,
363
- domain=domain,
364
- debug=debug,
365
- headers=connection_headers,
366
- proxy=proxy,
367
- )
368
-
369
- return cls(
370
- sandbox_id=sandbox_id,
371
- sandbox_domain=response.sandbox_domain,
372
- connection_config=connection_config,
373
- envd_version=response.envd_version,
374
- envd_access_token=response._envd_access_token,
375
- )
376
-
377
- async def __aenter__(self):
378
- if self._session.closed:
379
- connector = TCPConnector(
380
- limit=100, # 最大连接数
381
- limit_per_host=20, # 每主机最大连接数
382
- keepalive_timeout=30, # 保持连接超时(秒)
383
- enable_cleanup_closed=True, # 清理已关闭的连接
384
- ssl=False # 是否使用 SSL
385
- )
386
- self._session = aiohttp.ClientSession(connector=connector,
387
- timeout=aiohttp.ClientTimeout(total=None))
388
- return self
389
-
390
- async def __aexit__(self, exc_type, exc_value, traceback):
391
- await self.kill()
392
- await self._session.close()
393
-
394
- @overload
395
- async def kill(self, request_timeout: Optional[float] = None) -> bool:
396
- """
397
- Kill the sandbox.
398
-
399
- :param request_timeout: Timeout for the request in **seconds**
400
-
401
- :return: `True` if the sandbox was killed, `False` if the sandbox was not found
402
- """
403
- ...
404
-
405
- @overload
406
- @staticmethod
407
- async def kill(
408
- sandbox_id: str,
409
- api_key: Optional[str] = None,
410
- domain: Optional[str] = None,
411
- debug: Optional[bool] = None,
412
- request_timeout: Optional[float] = None,
413
- proxy: Optional[ProxyTypes] = None,
414
- ) -> bool:
415
- """
416
- Kill the sandbox specified by sandbox ID.
417
-
418
- :param sandbox_id: Sandbox ID
419
- :param api_key: E2B API Key to use for authentication, defaults to `E2B_API_KEY` environment variable
420
- :param request_timeout: Timeout for the request in **seconds**
421
- :param proxy: Proxy to use for the request
422
-
423
- :return: `True` if the sandbox was killed, `False` if the sandbox was not found
424
- """
425
- ...
426
-
427
- @class_method_variant("_cls_kill")
428
- async def kill(
429
- self,
430
- request_timeout: Optional[float] = None,
431
- ) -> bool: # type: ignore
432
- config_dict = self.connection_config.__dict__
433
- config_dict.pop("access_token", None)
434
- config_dict.pop("api_url", None)
435
-
436
- if request_timeout:
437
- config_dict["request_timeout"] = request_timeout
438
-
439
- await SandboxApi._cls_kill(
440
- sandbox_id=self.sandbox_id,
441
- **config_dict,
442
- )
443
-
444
- @overload
445
- async def set_timeout(
446
- self,
447
- timeout: int,
448
- request_timeout: Optional[float] = None,
449
- ) -> None:
450
- """
451
- Set the timeout of the sandbox.
452
- After the timeout expires the sandbox will be automatically killed.
453
- This method can extend or reduce the sandbox timeout set when creating the sandbox or from the last call to `.set_timeout`.
454
-
455
- Maximum time a sandbox can be kept alive is 24 hours (86_400 seconds) for Pro users and 1 hour (3_600 seconds) for Hobby users.
456
-
457
- :param timeout: Timeout for the sandbox in **seconds**
458
- :param request_timeout: Timeout for the request in **seconds**
459
- """
460
- ...
461
-
462
- @overload
463
- @staticmethod
464
- async def set_timeout(
465
- sandbox_id: str,
466
- timeout: int,
467
- api_key: Optional[str] = None,
468
- domain: Optional[str] = None,
469
- debug: Optional[bool] = None,
470
- request_timeout: Optional[float] = None,
471
- proxy: Optional[ProxyTypes] = None,
472
- ) -> None:
473
- """
474
- Set the timeout of the specified sandbox.
475
- After the timeout expires the sandbox will be automatically killed.
476
- This method can extend or reduce the sandbox timeout set when creating the sandbox or from the last call to `.set_timeout`.
477
-
478
- Maximum time a sandbox can be kept alive is 24 hours (86_400 seconds) for Pro users and 1 hour (3_600 seconds) for Hobby users.
479
-
480
- :param sandbox_id: Sandbox ID
481
- :param timeout: Timeout for the sandbox in **seconds**
482
- :param request_timeout: Timeout for the request in **seconds**
483
- :param proxy: Proxy to use for the request
484
- """
485
- ...
486
-
487
- @class_method_variant("_cls_set_timeout")
488
- async def set_timeout( # type: ignore
489
- self,
490
- timeout: int,
491
- request_timeout: Optional[float] = None,
492
- ) -> None:
493
- config_dict = self.connection_config.__dict__
494
- config_dict.pop("access_token", None)
495
- config_dict.pop("api_url", None)
496
-
497
- if request_timeout:
498
- config_dict["request_timeout"] = request_timeout
499
-
500
- await SandboxApi._cls_set_timeout(
501
- sandbox_id=self.sandbox_id,
502
- timeout=timeout,
503
- **config_dict,
504
- )
505
-
506
- @overload
507
- async def get_info(
508
- self,
509
- request_timeout: Optional[float] = None,
510
- ) -> SandboxInfo:
511
- """
512
- Get sandbox information like sandbox ID, template, metadata, started at/end at date.
513
- :param request_timeout: Timeout for the request in **seconds**
514
- :return: Sandbox info
515
- """
516
- ...
517
-
518
- @overload
519
- @staticmethod
520
- async def get_info(
521
- sandbox_id: str,
522
- api_key: Optional[str] = None,
523
- domain: Optional[str] = None,
524
- debug: Optional[bool] = None,
525
- request_timeout: Optional[float] = None,
526
- headers: Optional[Dict[str, str]] = None,
527
- proxy: Optional[ProxyTypes] = None,
528
- ) -> SandboxInfo:
529
- """
530
- Get sandbox information like sandbox ID, template, metadata, started at/end at date.
531
- :param sandbox_id: Sandbox ID
532
- :param api_key: E2B API Key to use for authentication, defaults to `E2B_API_KEY` environment variable
533
- :param domain: E2B domain to use for authentication, defaults to `E2B_DOMAIN` environment variable
534
- :param debug: Whether to use debug mode, defaults to `E2B_DEBUG` environment variable
535
- :param request_timeout: Timeout for the request in **seconds**
536
- :param headers: Custom headers to use for the request
537
- :param proxy: Proxy to use for the request
538
- :return: Sandbox info
539
- """
540
- ...
541
-
542
- @class_method_variant("_cls_get_info")
543
- async def get_info( # type: ignore
544
- self,
545
- request_timeout: Optional[float] = None,
546
- ) -> SandboxInfo:
547
- """
548
- Get sandbox information like sandbox ID, template, metadata, started at/end at date.
549
- :param request_timeout: Timeout for the request in **seconds**
550
- :return: Sandbox info
551
- """
552
-
553
- config_dict = self.connection_config.__dict__
554
- config_dict.pop("access_token", None)
555
- config_dict.pop("api_url", None)
556
-
557
- if request_timeout:
558
- config_dict["request_timeout"] = request_timeout
559
-
560
- return await SandboxApi._cls_get_info(
561
- sandbox_id=self.sandbox_id,
562
- **config_dict,
563
- )
564
-
565
- @overload
566
- async def get_metrics( # type: ignore
567
- self,
568
- start: Optional[datetime.datetime] = None,
569
- end: Optional[datetime.datetime] = None,
570
- request_timeout: Optional[float] = None,
571
- ) -> List[SandboxMetrics]:
572
- """
573
- Get the metrics of the current sandbox.
574
-
575
- :param start: Start time for the metrics, defaults to the start of the sandbox
576
- :param end: End time for the metrics, defaults to current time
577
- :param request_timeout: Timeout for the request in **seconds**
578
-
579
- :return: List of sandbox metrics containing CPU, memory and disk usage information
580
- """
581
- ...
582
-
583
- @overload
584
- @staticmethod
585
- async def get_metrics(
586
- sandbox_id: str,
587
- start: Optional[datetime.datetime] = None,
588
- end: Optional[datetime.datetime] = None,
589
- api_key: Optional[str] = None,
590
- domain: Optional[str] = None,
591
- debug: Optional[bool] = None,
592
- request_timeout: Optional[float] = None,
593
- ) -> List[SandboxMetrics]:
594
- """
595
- Get the metrics of the sandbox specified by sandbox ID.
596
-
597
- :param sandbox_id: Sandbox ID
598
- :param start: Start time for the metrics, defaults to the start of the sandbox
599
- :param end: End time for the metrics, defaults to current time
600
- :param api_key: E2B API Key to use for authentication, defaults to `E2B_API_KEY` environment variable
601
- :param request_timeout: Timeout for the request in **seconds**
602
-
603
- :return: List of sandbox metrics containing CPU, memory and disk usage information
604
- """
605
- ...
606
-
607
- @class_method_variant("_cls_get_metrics")
608
- async def get_metrics( # type: ignore
609
- self,
610
- start: Optional[datetime.datetime] = None,
611
- end: Optional[datetime.datetime] = None,
612
- request_timeout: Optional[float] = None,
613
- ) -> List[SandboxMetrics]:
614
- """
615
- Get the metrics of the current sandbox.
616
-
617
- :param start: Start time for the metrics, defaults to the start of the sandbox
618
- :param end: End time for the metrics, defaults to current time
619
- :param request_timeout: Timeout for the request in **seconds**
620
-
621
- :return: List of sandbox metrics containing CPU, memory and disk usage information
622
- """
623
- # if self._envd_version:
624
- # if Version(self._envd_version) < Version("0.1.5"):
625
- # raise SandboxException(
626
- # "Metrics are not supported in this version of the sandbox, please rebuild your template."
627
- # )
628
- #
629
- # if Version(self._envd_version) < Version("0.2.4"):
630
- # logger.warning(
631
- # "Disk metrics are not supported in this version of the sandbox, please rebuild the template to get disk metrics."
632
- # )
633
-
634
- config_dict = self.connection_config.__dict__
635
- print(str(config_dict))
636
- config_dict.pop("access_token", None)
637
- config_dict.pop("api_url", None)
638
- if request_timeout:
639
- config_dict["request_timeout"] = request_timeout
640
-
641
- return await self._cls_get_metrics(
642
- sandbox_id=self.sandbox_id,
643
- start=start,
644
- end=end,
645
- **config_dict,
646
- )
1
+ import datetime
2
+ import logging
3
+ import time
4
+ from typing import Dict, List, Optional, TypedDict, overload
5
+
6
+ import aiohttp
7
+ import httpx
8
+ from aiohttp import TCPConnector
9
+ from typing_extensions import Unpack
10
+
11
+ from ..api.client.types import Unset
12
+ from ..connection_config import ConnectionConfig, ProxyTypes
13
+ from ..exceptions import SandboxException, request_timeout_error
14
+ from ..generated.api import ENVD_API_HEALTH_ROUTE, ahandle_envd_api_exception
15
+ from ..sandbox.main import SandboxSetup
16
+ from ..sandbox.sandbox_api import SandboxMetrics
17
+ from ..sandbox.utils import class_method_variant
18
+ from ..sandbox_async.commands.command import Commands
19
+ from ..sandbox_async.commands.pty import Pty
20
+ from ..sandbox_async.filesystem.filesystem import Filesystem
21
+ from ..sandbox_async.sandbox_api import SandboxApi, SandboxInfo
22
+
23
+ logger = logging.getLogger(__name__)
24
+
25
+
26
+ class AsyncTransportWithLogger(httpx.AsyncHTTPTransport):
27
+ async def handle_async_request(self, request):
28
+ url = f"{request.url.scheme}://{request.url.host}{request.url.path}"
29
+ logger.info(f"Request: {request.method} {url}")
30
+ response = await super().handle_async_request(request)
31
+
32
+ # data = connect.GzipCompressor.decompress(response.read()).decode()
33
+ logger.info(f"Response: {response.status_code} {url}")
34
+
35
+ return response
36
+
37
+
38
+ class AsyncSandboxOpts(TypedDict):
39
+ sandbox_id: str
40
+ sandbox_domain: Optional[str]
41
+ envd_version: Optional[str]
42
+ envd_access_token: Optional[str]
43
+ connection_config: ConnectionConfig
44
+
45
+
46
+ class AsyncSandbox(SandboxSetup, SandboxApi):
47
+ """
48
+ Scalebox cloud sandbox is a secure and isolated cloud environment.
49
+
50
+ The sandbox allows you to:
51
+ - Access Linux OS
52
+ - Create, list, and delete files and directories
53
+ - Run commands
54
+ - Run isolated code
55
+ - Access the internet
56
+
57
+ Check docs [here](https://dev/docs).
58
+
59
+ Use the `AsyncSandbox.create()` to create a new sandbox.
60
+
61
+ Example:
62
+ ```python
63
+ from scalebox import AsyncSandbox
64
+
65
+ sandbox = await AsyncSandbox.create()
66
+ ```
67
+ """
68
+
69
+ @property
70
+ def files(self) -> Filesystem:
71
+ """
72
+ Module for interacting with the sandbox filesystem.
73
+ """
74
+ return self._filesystem
75
+
76
+ @property
77
+ def commands(self) -> Commands:
78
+ """
79
+ Module for running commands in the sandbox.
80
+ """
81
+ return self._commands
82
+
83
+ @property
84
+ def pty(self) -> Pty:
85
+ """
86
+ Module for interacting with the sandbox pseudo-terminal.
87
+ """
88
+ return self._pty
89
+
90
+ @property
91
+ def sandbox_id(self) -> str:
92
+ """
93
+ Unique identifier of the sandbox.
94
+ """
95
+ return self._sandbox_id
96
+
97
+ @property
98
+ def sandbox_domain(self) -> str:
99
+ """
100
+ Unique identifier of the sandbox.
101
+ """
102
+ return self._sandbox_domain
103
+
104
+ @property
105
+ def envd_api_url(self) -> str:
106
+ return self._envd_api_url
107
+
108
+ @property
109
+ def _envd_access_token(self) -> str:
110
+ """Private property to access the envd token"""
111
+ return self.__envd_access_token
112
+
113
+ @_envd_access_token.setter
114
+ def _envd_access_token(self, value: str):
115
+ """Private setter for envd token"""
116
+ self.__envd_access_token = value
117
+
118
+ @property
119
+ def connection_config(self) -> ConnectionConfig:
120
+ return self._connection_config
121
+
122
+ def __init__(self, **opts: Unpack[AsyncSandboxOpts]):
123
+ """
124
+ Use `AsyncSandbox.create()` to create a new sandbox instead.
125
+ """
126
+ super().__init__()
127
+
128
+ self._connection_config = opts["connection_config"]
129
+
130
+ self._sandbox_id = opts["sandbox_id"]
131
+ self._sandbox_domain = opts["sandbox_domain"] or self.connection_config.domain
132
+ debug=self._connection_config.debug
133
+ if debug:
134
+ self._envd_api_url = f"http://{self.get_host(8888)}"
135
+ else:
136
+ self._envd_api_url = f"https://{self.get_host(self.envd_port)}"
137
+ self._envd_version = opts["envd_version"]
138
+ self._envd_access_token = opts["envd_access_token"]
139
+ # connection_headers = {"Authorization": "Bearer root", }
140
+
141
+ # self._envd_api_url =f"http://localhost:32119"
142
+ self._envd_version =f"v1.0"
143
+ # self._connection_config = ConnectionConfig(
144
+ # headers=connection_headers,
145
+ # )
146
+
147
+ self._transport = AsyncTransportWithLogger(
148
+ limits=self._limits, proxy=self._connection_config.proxy
149
+ )
150
+ self._envd_api = httpx.AsyncClient(
151
+ base_url=self.envd_api_url,
152
+ transport=self._transport,
153
+ headers=self._connection_config.headers,
154
+ )
155
+ connector = TCPConnector(
156
+ limit=100, # 最大连接数
157
+ limit_per_host=20, # 每主机最大连接数
158
+ keepalive_timeout=30, # 保持连接超时(秒)
159
+ enable_cleanup_closed=True, # 清理已关闭的连接
160
+ ssl=True # 是否使用 SSL
161
+ )
162
+ self._session = aiohttp.ClientSession(connector=connector,
163
+ timeout=aiohttp.ClientTimeout(total=None))
164
+ self._filesystem = Filesystem(
165
+ self.envd_api_url,
166
+ self._envd_version,
167
+ self.connection_config,
168
+ self._session,
169
+ self._envd_api,
170
+ )
171
+ self._commands = Commands(
172
+ self.envd_api_url,
173
+ self.connection_config,
174
+ self._session,
175
+ )
176
+ self._pty = Pty(
177
+ self.envd_api_url,
178
+ self.connection_config,
179
+ self._session,
180
+ )
181
+
182
+ async def is_running(self, request_timeout: Optional[float] = None) -> bool:
183
+ """
184
+ Check if the sandbox is running.
185
+
186
+ :param request_timeout: Timeout for the request in **seconds**
187
+
188
+ :return: `True` if the sandbox is running, `False` otherwise
189
+
190
+ Example
191
+ ```python
192
+ sandbox = await AsyncSandbox.create()
193
+ await sandbox.is_running() # Returns True
194
+
195
+ await sandbox.kill()
196
+ await sandbox.is_running() # Returns False
197
+ ```
198
+ """
199
+ try:
200
+ r = await self._envd_api.get(
201
+ ENVD_API_HEALTH_ROUTE,
202
+ timeout=self.connection_config.get_request_timeout(request_timeout),
203
+ )
204
+
205
+ if r.status_code == 502:
206
+ return False
207
+
208
+ err = await ahandle_envd_api_exception(r)
209
+
210
+ if err:
211
+ raise err
212
+
213
+ except httpx.TimeoutException:
214
+ raise request_timeout_error()
215
+
216
+ return True
217
+
218
+ @classmethod
219
+ async def create(
220
+ cls,
221
+ template: Optional[str] = None,
222
+ timeout: Optional[int] = None,
223
+ metadata: Optional[Dict[str, str]] = None,
224
+ envs: Optional[Dict[str, str]] = None,
225
+ api_key: Optional[str] = None,
226
+ domain: Optional[str] = None,
227
+ debug: Optional[bool] = None,
228
+ request_timeout: Optional[float] = None,
229
+ proxy: Optional[ProxyTypes] = None,
230
+ secure: Optional[bool] = None,
231
+ allow_internet_access: Optional[bool] = True,
232
+ ):
233
+ """
234
+ Create a new sandbox.
235
+
236
+ By default, the sandbox is created from the default `base` sandbox template.
237
+
238
+ :param template: Sandbox template name or ID
239
+ :param timeout: Timeout for the sandbox in **seconds**, default to 300 seconds. Maximum time a sandbox can be kept alive is 24 hours (86_400 seconds) for Pro users and 1 hour (3_600 seconds) for Hobby users.
240
+ :param metadata: Custom metadata for the sandbox
241
+ :param envs: Custom environment variables for the sandbox
242
+ :param api_key: SBX API Key to use for authentication, defaults to `SBX_API_KEY` environment variable
243
+ :param request_timeout: Timeout for the request in **seconds**
244
+ :param proxy: Proxy to use for the request and for the **requests made to the returned sandbox**
245
+ :param secure: Envd is secured with access token and cannot be used without it
246
+ :param allow_internet_access: Allow sandbox to access the internet, defaults to `True`.
247
+
248
+ :return: sandbox instance for the new sandbox
249
+
250
+ Use this method instead of using the constructor to create a new sandbox.
251
+ """
252
+
253
+ connection_headers = {"Authorization": "Bearer root", }
254
+ if debug:
255
+ sandbox_id = "debug_sandbox_id"
256
+ sandbox_domain = None
257
+ envd_version = None
258
+ envd_access_token = None
259
+ else:
260
+ response = await SandboxApi._create_sandbox(
261
+ template=template or cls.default_template,
262
+ api_key=api_key,
263
+ timeout=timeout or cls.default_sandbox_timeout,
264
+ metadata=metadata,
265
+ domain=domain,
266
+ debug=debug,
267
+ request_timeout=request_timeout,
268
+ env_vars=envs,
269
+ secure=secure,
270
+ proxy=proxy,
271
+ allow_internet_access=allow_internet_access,
272
+ )
273
+
274
+ sandbox_id = response.sandbox_id
275
+ sandbox_domain = response.sandbox_domain
276
+ envd_version = response.envd_version
277
+ envd_access_token = response.envd_access_token
278
+
279
+ if envd_access_token is not None and not isinstance(
280
+ envd_access_token, Unset
281
+ ):
282
+ connection_headers["X-Access-Token"] = envd_access_token
283
+
284
+
285
+ connection_config = ConnectionConfig(
286
+ api_key=api_key,
287
+ domain=domain,
288
+ debug=debug,
289
+ request_timeout=request_timeout,
290
+ headers=connection_headers,
291
+ proxy=proxy,
292
+ )
293
+ print("connection_config"+str(connection_config.__dict__))
294
+ sanbox = cls(
295
+ sandbox_id=sandbox_id,
296
+ sandbox_domain=sandbox_domain,
297
+ envd_version=envd_version,
298
+ envd_access_token=envd_access_token,
299
+ connection_config=connection_config,
300
+ )
301
+ timeout = 10.0
302
+ interval = 0.3
303
+ elapsed = 0.0
304
+
305
+ while elapsed <= timeout:
306
+ try:
307
+ isRunning = await sanbox.is_running(request_timeout=1)
308
+ if isRunning:
309
+ break
310
+ except Exception:
311
+ pass
312
+ time.sleep(interval)
313
+ elapsed += interval
314
+ else:
315
+ print("connect "+sandbox_domain+ENVD_API_HEALTH_ROUTE +" timeout 5s")
316
+ return sanbox
317
+
318
+ @classmethod
319
+ async def connect(
320
+ cls,
321
+ sandbox_id: str,
322
+ api_key: Optional[str] = None,
323
+ domain: Optional[str] = None,
324
+ debug: Optional[bool] = None,
325
+ proxy: Optional[ProxyTypes] = None,
326
+ ):
327
+ """
328
+ Connect to an existing sandbox.
329
+ With sandbox ID you can connect to the same sandbox from different places or environments (serverless functions, etc).
330
+
331
+ :param sandbox_id: Sandbox ID
332
+ :param api_key: SBX API Key to use for authentication, defaults to `SBX_API_KEY` environment variable
333
+ :param proxy: Proxy to use for the request and for the **requests made to the returned sandbox**
334
+
335
+ :return: sandbox instance for the existing sandbox
336
+
337
+ @example
338
+ ```python
339
+ sandbox = await AsyncSandbox.create()
340
+ sandbox_id = sandbox.sandbox_id
341
+
342
+ # Another code block
343
+ same_sandbox = await AsyncSandbox.connect(sandbox_id)
344
+ """
345
+
346
+ connection_headers = {"Authorization": "Bearer root"}
347
+
348
+ response = await SandboxApi._cls_get_info(
349
+ sandbox_id,
350
+ api_key=api_key,
351
+ domain=domain,
352
+ debug=debug,
353
+ proxy=proxy,
354
+ )
355
+
356
+ if response._envd_access_token is not None and not isinstance(
357
+ response._envd_access_token, Unset
358
+ ):
359
+ connection_headers["X-Access-Token"] = response._envd_access_token
360
+ print("connection_headers:"+str(connection_headers))
361
+
362
+ connection_config = ConnectionConfig(
363
+ api_key=api_key,
364
+ domain=domain,
365
+ debug=debug,
366
+ headers=connection_headers,
367
+ proxy=proxy,
368
+ )
369
+
370
+ return cls(
371
+ sandbox_id=sandbox_id,
372
+ sandbox_domain=response.sandbox_domain,
373
+ connection_config=connection_config,
374
+ envd_version=response.envd_version,
375
+ envd_access_token=response._envd_access_token,
376
+ )
377
+
378
+ async def __aenter__(self):
379
+ if self._session.closed:
380
+ connector = TCPConnector(
381
+ limit=100, # 最大连接数
382
+ limit_per_host=20, # 每主机最大连接数
383
+ keepalive_timeout=30, # 保持连接超时(秒)
384
+ enable_cleanup_closed=True, # 清理已关闭的连接
385
+ ssl=False # 是否使用 SSL
386
+ )
387
+ self._session = aiohttp.ClientSession(connector=connector,
388
+ timeout=aiohttp.ClientTimeout(total=None))
389
+ return self
390
+
391
+ async def __aexit__(self, exc_type, exc_value, traceback):
392
+ await self.kill()
393
+ await self._session.close()
394
+
395
+ @overload
396
+ async def kill(self, request_timeout: Optional[float] = None) -> bool:
397
+ """
398
+ Kill the sandbox.
399
+
400
+ :param request_timeout: Timeout for the request in **seconds**
401
+
402
+ :return: `True` if the sandbox was killed, `False` if the sandbox was not found
403
+ """
404
+ ...
405
+
406
+ @overload
407
+ @staticmethod
408
+ async def kill(
409
+ sandbox_id: str,
410
+ api_key: Optional[str] = None,
411
+ domain: Optional[str] = None,
412
+ debug: Optional[bool] = None,
413
+ request_timeout: Optional[float] = None,
414
+ proxy: Optional[ProxyTypes] = None,
415
+ ) -> bool:
416
+ """
417
+ Kill the sandbox specified by sandbox ID.
418
+
419
+ :param sandbox_id: Sandbox ID
420
+ :param api_key: SBX API Key to use for authentication, defaults to `SBX_API_KEY` environment variable
421
+ :param request_timeout: Timeout for the request in **seconds**
422
+ :param proxy: Proxy to use for the request
423
+
424
+ :return: `True` if the sandbox was killed, `False` if the sandbox was not found
425
+ """
426
+ ...
427
+
428
+ @class_method_variant("_cls_kill")
429
+ async def kill(
430
+ self,
431
+ request_timeout: Optional[float] = None,
432
+ ) -> bool: # type: ignore
433
+ config_dict = self.connection_config.__dict__
434
+ config_dict.pop("access_token", None)
435
+ config_dict.pop("api_url", None)
436
+
437
+ if request_timeout:
438
+ config_dict["request_timeout"] = request_timeout
439
+
440
+ await SandboxApi._cls_kill(
441
+ sandbox_id=self.sandbox_id,
442
+ **config_dict,
443
+ )
444
+
445
+ @overload
446
+ async def set_timeout(
447
+ self,
448
+ timeout: int,
449
+ request_timeout: Optional[float] = None,
450
+ ) -> None:
451
+ """
452
+ Set the timeout of the sandbox.
453
+ After the timeout expires the sandbox will be automatically killed.
454
+ This method can extend or reduce the sandbox timeout set when creating the sandbox or from the last call to `.set_timeout`.
455
+
456
+ Maximum time a sandbox can be kept alive is 24 hours (86_400 seconds) for Pro users and 1 hour (3_600 seconds) for Hobby users.
457
+
458
+ :param timeout: Timeout for the sandbox in **seconds**
459
+ :param request_timeout: Timeout for the request in **seconds**
460
+ """
461
+ ...
462
+
463
+ @overload
464
+ @staticmethod
465
+ async def set_timeout(
466
+ sandbox_id: str,
467
+ timeout: int,
468
+ api_key: Optional[str] = None,
469
+ domain: Optional[str] = None,
470
+ debug: Optional[bool] = None,
471
+ request_timeout: Optional[float] = None,
472
+ proxy: Optional[ProxyTypes] = None,
473
+ ) -> None:
474
+ """
475
+ Set the timeout of the specified sandbox.
476
+ After the timeout expires the sandbox will be automatically killed.
477
+ This method can extend or reduce the sandbox timeout set when creating the sandbox or from the last call to `.set_timeout`.
478
+
479
+ Maximum time a sandbox can be kept alive is 24 hours (86_400 seconds) for Pro users and 1 hour (3_600 seconds) for Hobby users.
480
+
481
+ :param sandbox_id: Sandbox ID
482
+ :param timeout: Timeout for the sandbox in **seconds**
483
+ :param request_timeout: Timeout for the request in **seconds**
484
+ :param proxy: Proxy to use for the request
485
+ """
486
+ ...
487
+
488
+ @class_method_variant("_cls_set_timeout")
489
+ async def set_timeout( # type: ignore
490
+ self,
491
+ timeout: int,
492
+ request_timeout: Optional[float] = None,
493
+ ) -> None:
494
+ config_dict = self.connection_config.__dict__
495
+ config_dict.pop("access_token", None)
496
+ config_dict.pop("api_url", None)
497
+
498
+ if request_timeout:
499
+ config_dict["request_timeout"] = request_timeout
500
+
501
+ await SandboxApi._cls_set_timeout(
502
+ sandbox_id=self.sandbox_id,
503
+ timeout=timeout,
504
+ **config_dict,
505
+ )
506
+
507
+ @overload
508
+ async def get_info(
509
+ self,
510
+ request_timeout: Optional[float] = None,
511
+ ) -> SandboxInfo:
512
+ """
513
+ Get sandbox information like sandbox ID, template, metadata, started at/end at date.
514
+ :param request_timeout: Timeout for the request in **seconds**
515
+ :return: Sandbox info
516
+ """
517
+ ...
518
+
519
+ @overload
520
+ @staticmethod
521
+ async def get_info(
522
+ sandbox_id: str,
523
+ api_key: Optional[str] = None,
524
+ domain: Optional[str] = None,
525
+ debug: Optional[bool] = None,
526
+ request_timeout: Optional[float] = None,
527
+ headers: Optional[Dict[str, str]] = None,
528
+ proxy: Optional[ProxyTypes] = None,
529
+ ) -> SandboxInfo:
530
+ """
531
+ Get sandbox information like sandbox ID, template, metadata, started at/end at date.
532
+ :param sandbox_id: Sandbox ID
533
+ :param api_key: SBX API Key to use for authentication, defaults to `SBX_API_KEY` environment variable
534
+ :param domain: SBX domain to use for authentication, defaults to `SBX_DOMAIN` environment variable
535
+ :param debug: Whether to use debug mode, defaults to `SBX_DEBUG` environment variable
536
+ :param request_timeout: Timeout for the request in **seconds**
537
+ :param headers: Custom headers to use for the request
538
+ :param proxy: Proxy to use for the request
539
+ :return: Sandbox info
540
+ """
541
+ ...
542
+
543
+ @class_method_variant("_cls_get_info")
544
+ async def get_info( # type: ignore
545
+ self,
546
+ request_timeout: Optional[float] = None,
547
+ ) -> SandboxInfo:
548
+ """
549
+ Get sandbox information like sandbox ID, template, metadata, started at/end at date.
550
+ :param request_timeout: Timeout for the request in **seconds**
551
+ :return: Sandbox info
552
+ """
553
+
554
+ config_dict = self.connection_config.__dict__
555
+ config_dict.pop("access_token", None)
556
+ config_dict.pop("api_url", None)
557
+
558
+ if request_timeout:
559
+ config_dict["request_timeout"] = request_timeout
560
+
561
+ return await SandboxApi._cls_get_info(
562
+ sandbox_id=self.sandbox_id,
563
+ **config_dict,
564
+ )
565
+
566
+ @overload
567
+ async def get_metrics( # type: ignore
568
+ self,
569
+ start: Optional[datetime.datetime] = None,
570
+ end: Optional[datetime.datetime] = None,
571
+ request_timeout: Optional[float] = None,
572
+ ) -> List[SandboxMetrics]:
573
+ """
574
+ Get the metrics of the current sandbox.
575
+
576
+ :param start: Start time for the metrics, defaults to the start of the sandbox
577
+ :param end: End time for the metrics, defaults to current time
578
+ :param request_timeout: Timeout for the request in **seconds**
579
+
580
+ :return: List of sandbox metrics containing CPU, memory and disk usage information
581
+ """
582
+ ...
583
+
584
+ @overload
585
+ @staticmethod
586
+ async def get_metrics(
587
+ sandbox_id: str,
588
+ start: Optional[datetime.datetime] = None,
589
+ end: Optional[datetime.datetime] = None,
590
+ api_key: Optional[str] = None,
591
+ domain: Optional[str] = None,
592
+ debug: Optional[bool] = None,
593
+ request_timeout: Optional[float] = None,
594
+ ) -> List[SandboxMetrics]:
595
+ """
596
+ Get the metrics of the sandbox specified by sandbox ID.
597
+
598
+ :param sandbox_id: Sandbox ID
599
+ :param start: Start time for the metrics, defaults to the start of the sandbox
600
+ :param end: End time for the metrics, defaults to current time
601
+ :param api_key: SBX API Key to use for authentication, defaults to `SBX_API_KEY` environment variable
602
+ :param request_timeout: Timeout for the request in **seconds**
603
+
604
+ :return: List of sandbox metrics containing CPU, memory and disk usage information
605
+ """
606
+ ...
607
+
608
+ @class_method_variant("_cls_get_metrics")
609
+ async def get_metrics( # type: ignore
610
+ self,
611
+ start: Optional[datetime.datetime] = None,
612
+ end: Optional[datetime.datetime] = None,
613
+ request_timeout: Optional[float] = None,
614
+ ) -> List[SandboxMetrics]:
615
+ """
616
+ Get the metrics of the current sandbox.
617
+
618
+ :param start: Start time for the metrics, defaults to the start of the sandbox
619
+ :param end: End time for the metrics, defaults to current time
620
+ :param request_timeout: Timeout for the request in **seconds**
621
+
622
+ :return: List of sandbox metrics containing CPU, memory and disk usage information
623
+ """
624
+ # if self._envd_version:
625
+ # if Version(self._envd_version) < Version("0.1.5"):
626
+ # raise SandboxException(
627
+ # "Metrics are not supported in this version of the sandbox, please rebuild your template."
628
+ # )
629
+ #
630
+ # if Version(self._envd_version) < Version("0.2.4"):
631
+ # logger.warning(
632
+ # "Disk metrics are not supported in this version of the sandbox, please rebuild the template to get disk metrics."
633
+ # )
634
+
635
+ config_dict = self.connection_config.__dict__
636
+ print(str(config_dict))
637
+ config_dict.pop("access_token", None)
638
+ config_dict.pop("api_url", None)
639
+ if request_timeout:
640
+ config_dict["request_timeout"] = request_timeout
641
+
642
+ return await self._cls_get_metrics(
643
+ sandbox_id=self.sandbox_id,
644
+ start=start,
645
+ end=end,
646
+ **config_dict,
647
+ )