scalebox-sdk 0.1.20__py3-none-any.whl → 0.1.21__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.
@@ -1,790 +1,789 @@
1
- import datetime
2
- import logging
3
- import socket
4
- import time
5
- from typing import Dict, List, Optional, TypedDict, overload
6
-
7
- import httpx
8
- import urllib3
9
- from httpx import Timeout
10
- from packaging.version import Version
11
- from urllib3 import Retry
12
-
13
- from ..api.client.types import Unset
14
- from ..connection_config import ConnectionConfig, ProxyTypes
15
- from ..exceptions import SandboxException, request_timeout_error
16
- from ..generated.api import ENVD_API_HEALTH_ROUTE, handle_envd_api_exception
17
- from ..sandbox.main import SandboxSetup
18
- from ..sandbox.sandbox_api import SandboxMetrics
19
- from ..sandbox.utils import class_method_variant
20
- from ..sandbox_sync.commands.command import Commands
21
- from ..sandbox_sync.commands.pty import Pty
22
- from ..sandbox_sync.filesystem.filesystem import Filesystem
23
- from ..sandbox_sync.sandbox_api import SandboxApi, SandboxInfo
24
-
25
- logger = logging.getLogger(__name__)
26
-
27
-
28
- class TransportWithLogger(httpx.HTTPTransport):
29
- def handle_request(self, request):
30
- url = f"{request.url.scheme}://{request.url.host}{request.url.path}"
31
- logger.info(f"Request: {request.method} {url}")
32
- response = super().handle_request(request)
33
-
34
- # data = connect.GzipCompressor.decompress(response.read()).decode()
35
- logger.info(f"Response: {response.status_code} {url}")
36
-
37
- return response
38
-
39
- class SandboxOpts(TypedDict):
40
- sandbox_id: str
41
- sandbox_domain: Optional[str]
42
- envd_version: Optional[str]
43
- envd_access_token: Optional[str]
44
- connection_config: ConnectionConfig
45
-
46
- class Sandbox(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 `Sandbox()` to create a new sandbox.
60
-
61
- Example:
62
- ```python
63
- from e2b import Sandbox
64
-
65
- sandbox = Sandbox()
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
- Domain where the sandbox is hosted.
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: Optional[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__(
123
- # self,
124
- # template: Optional[str] = None,
125
- # timeout: Optional[int] = None,
126
- # metadata: Optional[Dict[str, str]] = None,
127
- # envs: Optional[Dict[str, str]] = None,
128
- # secure: Optional[bool] = None,
129
- # api_key: Optional[str] = None,
130
- # domain: Optional[str] = None,
131
- # debug: Optional[bool] = None,
132
- # sandbox_id: Optional[str] = None,
133
- # request_timeout: Optional[float] = None,
134
- # proxy: Optional[ProxyTypes] = None,
135
- # allow_internet_access: Optional[bool] = True,
136
- # ):
137
- def __init__(self, **opts):
138
- """
139
- Create a new sandbox.
140
-
141
- By default, the sandbox is created from the default `base` sandbox template.
142
-
143
- :param template: Sandbox template name or ID
144
- :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
145
- :param metadata: Custom metadata for the sandbox
146
- :param envs: Custom environment variables for the sandbox
147
- :param api_key: E2B API Key to use for authentication, defaults to `E2B_API_KEY` environment variable
148
- :param request_timeout: Timeout for the request in **seconds**
149
- :param proxy: Proxy to use for the request and for the **requests made to the returned sandbox**
150
- :param allow_internet_access: Allow sandbox to access the internet, defaults to `True`
151
-
152
- :return: sandbox instance for the new sandbox
153
- """
154
- super().__init__()
155
- self._connection_config = opts["connection_config"]
156
-
157
- self._sandbox_id = opts["sandbox_id"]
158
- self._sandbox_domain = opts["sandbox_domain"] or self.connection_config.domain
159
- debug = self._connection_config.debug
160
- # connection_headers = {"Authorization": "Bearer root", }
161
-
162
- # if debug:
163
- # self._sandbox_id = "debug_sandbox_id"
164
- # self._sandbox_domain = None
165
- # self._envd_version = None
166
- # self._envd_access_token = None
167
- # elif sandbox_id is not None:
168
- # response = SandboxApi._cls_get_info(
169
- # sandbox_id,
170
- # api_key=api_key,
171
- # domain=domain,
172
- # debug=debug,
173
- # request_timeout=request_timeout,
174
- # proxy=proxy,
175
- # )
176
- #
177
- # self._sandbox_id = sandbox_id
178
- # self._sandbox_domain = response.sandbox_domain
179
- # self._envd_version = response.envd_version
180
- # self._envd_access_token = response._envd_access_token
181
- #
182
- # if response._envd_access_token is not None and not isinstance(
183
- # response._envd_access_token, Unset
184
- # ):
185
- # connection_headers["X-Access-Token"] = response._envd_access_token
186
- # else:
187
- # template = template or self.default_template
188
- # timeout = timeout or self.default_sandbox_timeout
189
- # response = SandboxApi._create_sandbox(
190
- # template=template,
191
- # api_key=api_key,
192
- # timeout=timeout,
193
- # metadata=metadata,
194
- # env_vars=envs,
195
- # domain=domain,
196
- # debug=debug,
197
- # request_timeout=request_timeout,
198
- # secure=secure or False,
199
- # proxy=proxy,
200
- # allow_internet_access=allow_internet_access,
201
- # )
202
- #
203
- # self._sandbox_id = response.sandbox_id
204
- # self._sandbox_domain = response.sandbox_domain
205
- # self._envd_version = response.envd_version
206
- #
207
- # if response.envd_access_token is not None and not isinstance(
208
- # response.envd_access_token, Unset
209
- # ):
210
- # self._envd_access_token = response.envd_access_token
211
- # connection_headers["X-Access-Token"] = response.envd_access_token
212
- # else:
213
- # self._envd_access_token = None
214
- # self._transport = TransportWithLogger(limits=self._limits, proxy=proxy)
215
- # self._connection_config = ConnectionConfig(
216
- # api_key=api_key,
217
- # domain=domain,
218
- # debug=debug,
219
- # request_timeout=request_timeout,
220
- # headers=connection_headers,
221
- # proxy=proxy,
222
- # )
223
-
224
- self._sandbox_domain = self._sandbox_domain or self._connection_config.domain
225
- # self._envd_api_url = f"{'http' if self.connection_config.debug else 'https'}://{self.get_host(self.envd_port)}"
226
- if debug:
227
- self._envd_api_url = f"http://{self.get_host(8888)}"
228
- # elif self._sandbox_id is not None:
229
- # response = SandboxApi._cls_get_info(
230
- # self._sandbox_id,
231
- # api_key=self._api_key(),
232
- # domain=self._sandbox_domain,
233
- # debug=debug,
234
- # request_timeout=self.request_timeout,
235
- # proxy=self.proxy,
236
- # )
237
- #
238
- # self._sandbox_id = self._sandbox_id
239
- # self._sandbox_domain = response.sandbox_domain
240
- # self._envd_version = response.envd_version
241
- # self._envd_access_token = response._envd_access_token
242
- #
243
- # if response._envd_access_token is not None and not isinstance(
244
- # response._envd_access_token, Unset
245
- # ):
246
- # self._connection_config["X-Access-Token"] = response._envd_access_token
247
- # self._envd_api_url = f"http://{self.get_host(self.envd_port)}"
248
- else:
249
- self._envd_api_url = f"https://{self.get_host(self.envd_port)}"
250
- self._transport = TransportWithLogger(limits=self._limits, proxy=self._connection_config.proxy)
251
- # self._envd_api_url = f"http://localhost:8088"
252
- # self._envd_api_url = f"http://{self.get_host(self.envd_port)}"
253
- # self._envd_api_url = f"http://localhost:31000"
254
- self._envd_api = httpx.Client(
255
- base_url=self._envd_api_url,
256
- transport=self._transport,
257
- headers=self.connection_config.headers,
258
- )
259
-
260
- self._envd_version=f"v1.0"
261
- # 准备连接池参数
262
- connection_pool_kw = {
263
- # 连接池大小
264
- "maxsize": 100,
265
- "block": False,
266
- # 超时设置
267
- "timeout": self._connection_config.request_timeout,
268
- # 重试策略
269
- "retries": Retry(
270
- total=3,
271
- backoff_factor=0.1,
272
- status_forcelist=[500, 502, 503, 504]
273
- ),
274
- # SSL 设置
275
- # "cert_reqs": 'CERT_NONE',
276
- "ca_certs": None,
277
- # 套接字选项
278
- "socket_options": [
279
- (socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1),
280
- (socket.IPPROTO_TCP, socket.TCP_NODELAY, 1),
281
- ],
282
- }
283
-
284
- # 如果有代理配置,添加到连接池参数
285
- if hasattr(self._connection_config, 'proxy') and self._connection_config.proxy:
286
- connection_pool_kw["proxy_url"] = self._connection_config.proxy
287
-
288
- # 创建 urllib3.PoolManager 连接池
289
- self._urllib3_pool = urllib3.PoolManager(
290
- num_pools=10, # 池的数量
291
- headers=self._connection_config.headers, # 默认头部
292
- **connection_pool_kw # 连接池参数
293
- )
294
-
295
- self._filesystem = Filesystem(
296
- self.envd_api_url,
297
- self._envd_version,
298
- self.connection_config,
299
- self._urllib3_pool,
300
- self._envd_api,
301
- )
302
- self._commands = Commands(
303
- self.envd_api_url,
304
- self.connection_config,
305
- self._urllib3_pool,
306
- )
307
- self._pty = Pty(
308
- self.envd_api_url,
309
- self.connection_config,
310
- self._urllib3_pool,
311
- )
312
-
313
- @classmethod
314
- def create(
315
- cls,
316
- template: Optional[str] = None,
317
- timeout: Optional[int] = None,
318
- metadata: Optional[Dict[str, str]] = None,
319
- envs: Optional[Dict[str, str]] = None,
320
- api_key: Optional[str] = None,
321
- domain: Optional[str] = None,
322
- debug: Optional[bool] = None,
323
- sandbox_id: Optional[str] = None,
324
- request_timeout: Optional[float] = None,
325
- proxy: Optional[ProxyTypes] = None,
326
- secure: Optional[bool] = None,
327
- allow_internet_access: Optional[bool] = True,
328
- ):
329
- """
330
- Create a new sandbox.
331
-
332
- By default, the sandbox is created from the default `base` sandbox template.
333
-
334
- :param template: Sandbox template name or ID
335
- :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.
336
- :param metadata: Custom metadata for the sandbox
337
- :param envs: Custom environment variables for the sandbox
338
- :param api_key: scalebox API Key to use for authentication, defaults to `CSX_API_KEY` environment variable
339
- :param request_timeout: Timeout for the request in **seconds**
340
- :param proxy: Proxy to use for the request and for the **requests made to the returned sandbox**
341
- :param secure: Envd is secured with access token and cannot be used without it
342
- :param allow_internet_access: Allow sandbox to access the internet, defaults to `True`.
343
-
344
- :return: sandbox instance for the new sandbox
345
-
346
- Use this method instead of using the constructor to create a new sandbox.
347
- """
348
- if sandbox_id and (metadata is not None or template is not None):
349
- raise SandboxException(
350
- "Cannot set metadata or timeout when connecting to an existing sandbox. "
351
- "Use Sandbox.connect method instead.",
352
- )
353
- connection_headers = {"Authorization": "Bearer root", }
354
- if debug:
355
- sandbox_id = "debug_sandbox_id"
356
- sandbox_domain = None
357
- envd_version = None
358
- envd_access_token = None
359
- elif sandbox_id is not None:
360
- response = SandboxApi._cls_get_info(
361
- sandbox_id,
362
- api_key=api_key,
363
- domain=domain,
364
- debug=debug,
365
- request_timeout=request_timeout,
366
- proxy=proxy,
367
- )
368
-
369
- sandbox_domain = response.sandbox_domain
370
- envd_version = response.envd_version
371
- envd_access_token = response._envd_access_token
372
-
373
- if response._envd_access_token is not None and not isinstance(
374
- response._envd_access_token, Unset
375
- ):
376
- connection_headers["X-Access-Token"] = response._envd_access_token
377
- else:
378
- response = SandboxApi._create_sandbox(
379
- template=template or cls.default_template,
380
- api_key=api_key,
381
- timeout=timeout or cls.default_sandbox_timeout,
382
- metadata=metadata,
383
- domain=domain,
384
- debug=debug,
385
- request_timeout=request_timeout,
386
- env_vars=envs,
387
- secure=secure,
388
- proxy=proxy,
389
- allow_internet_access=allow_internet_access,
390
- )
391
-
392
- sandbox_id = response.sandbox_id
393
- sandbox_domain = response.sandbox_domain
394
- envd_version = response.envd_version
395
- envd_access_token = response.envd_access_token
396
-
397
- if envd_access_token is not None and not isinstance(
398
- envd_access_token, Unset
399
- ):
400
- connection_headers["X-Access-Token"] = envd_access_token
401
-
402
- connection_config = ConnectionConfig(
403
- api_key=api_key,
404
- domain=domain,
405
- debug=debug,
406
- request_timeout=request_timeout,
407
- headers=connection_headers,
408
- proxy=proxy,
409
- )
410
- print("connection_config" + str(connection_config.__dict__))
411
- sanbox= cls(
412
- sandbox_id=sandbox_id,
413
- sandbox_domain=sandbox_domain,
414
- envd_version=envd_version,
415
- envd_access_token=envd_access_token,
416
- connection_config=connection_config,
417
- )
418
-
419
- timeout = 5.0
420
- interval = 0.3
421
- elapsed = 0.0
422
- while elapsed <= timeout:
423
- try:
424
- isRunning = sanbox.is_running(request_timeout=1)
425
- if isRunning:
426
- break
427
- except Exception:
428
- pass
429
- time.sleep(interval)
430
- elapsed += interval
431
- else:
432
- print("connect "+sandbox_domain+ENVD_API_HEALTH_ROUTE +" timeout 5s")
433
- return sanbox
434
-
435
- def is_running(self, request_timeout: Optional[float] = None) -> bool:
436
- """
437
- Check if the sandbox is running.
438
-
439
- :param request_timeout: Timeout for the request in **seconds**
440
-
441
- :return: `True` if the sandbox is running, `False` otherwise
442
-
443
- Example
444
- ```python
445
- sandbox = Sandbox()
446
- sandbox.is_running() # Returns True
447
-
448
- sandbox.kill()
449
- sandbox.is_running() # Returns False
450
- ```
451
- """
452
- try:
453
- r = self._envd_api.get(
454
- ENVD_API_HEALTH_ROUTE,
455
- timeout=self.connection_config.get_request_timeout(request_timeout),
456
- )
457
- print(r)
458
- if r.status_code == 502:
459
- return False
460
-
461
- err = handle_envd_api_exception(r)
462
-
463
- if err:
464
- raise err
465
-
466
- except httpx.TimeoutException:
467
- raise request_timeout_error()
468
-
469
- return True
470
-
471
- @classmethod
472
- def connect(
473
- cls,
474
- sandbox_id: str,
475
- api_key: Optional[str] = None,
476
- domain: Optional[str] = None,
477
- debug: Optional[bool] = None,
478
- proxy: Optional[ProxyTypes] = None,
479
- ):
480
- """
481
- Connects to an existing Sandbox.
482
- With sandbox ID you can connect to the same sandbox from different places or environments (serverless functions, etc).
483
-
484
- :param sandbox_id: Sandbox ID
485
- :param api_key: E2B API Key to use for authentication, defaults to `E2B_API_KEY` environment variable
486
- :param proxy: Proxy to use for the request and for the **requests made to the returned sandbox**
487
-
488
- :return: sandbox instance for the existing sandbox
489
-
490
- @example
491
- ```python
492
- sandbox = Sandbox()
493
- sandbox_id = sandbox.sandbox_id
494
-
495
- # Another code block
496
- same_sandbox = Sandbox.connect(sandbox_id)
497
- ```
498
- """
499
- connection_headers = {"Authorization": "Bearer root"}
500
-
501
- response = SandboxApi._cls_get_info(
502
- sandbox_id,
503
- api_key=api_key,
504
- domain=domain,
505
- debug=debug,
506
- proxy=proxy,
507
- )
508
-
509
- if response._envd_access_token is not None and not isinstance(
510
- response._envd_access_token, Unset
511
- ):
512
- connection_headers["X-Access-Token"] = response._envd_access_token
513
-
514
- connection_config = ConnectionConfig(
515
- api_key=api_key,
516
- domain=domain,
517
- debug=debug,
518
- headers=connection_headers,
519
- proxy=proxy,
520
- )
521
-
522
- return cls(
523
- sandbox_id=sandbox_id,
524
- sandbox_domain=response.sandbox_domain,
525
- envd_version=response.envd_version,
526
- envd_access_token=response._envd_access_token,
527
- connection_config=connection_config,
528
- )
529
-
530
- def __enter__(self):
531
- return self
532
-
533
- def __exit__(self, exc_type, exc_value, traceback):
534
- self.kill()
535
-
536
- @overload
537
- def kill(self, request_timeout: Optional[float] = None) -> bool:
538
- """
539
- Kill the sandbox.
540
-
541
- :param request_timeout: Timeout for the request in **seconds**
542
-
543
- :return: `True` if the sandbox was killed, `False` if the sandbox was not found
544
- """
545
- ...
546
-
547
- @overload
548
- @staticmethod
549
- def kill(
550
- sandbox_id: str,
551
- api_key: Optional[str] = None,
552
- domain: Optional[str] = None,
553
- debug: Optional[bool] = None,
554
- request_timeout: Optional[float] = None,
555
- proxy: Optional[ProxyTypes] = None,
556
- ) -> bool:
557
- """
558
- Kill the sandbox specified by sandbox ID.
559
-
560
- :param sandbox_id: Sandbox ID
561
- :param api_key: E2B API Key to use for authentication, defaults to `E2B_API_KEY` environment variable
562
- :param request_timeout: Timeout for the request in **seconds**
563
- :param proxy: Proxy to use for the request
564
-
565
- :return: `True` if the sandbox was killed, `False` if the sandbox was not found
566
- """
567
- ...
568
-
569
- @class_method_variant("_cls_kill")
570
- def kill(self, request_timeout: Optional[float] = None) -> bool: # type: ignore
571
- """
572
- Kill the sandbox.
573
-
574
- :param request_timeout: Timeout for the request
575
- :return: `True` if the sandbox was killed, `False` if the sandbox was not found
576
- """
577
- config_dict = self.connection_config.__dict__
578
- config_dict.pop("access_token", None)
579
- config_dict.pop("api_url", None)
580
-
581
- if request_timeout:
582
- config_dict["request_timeout"] = request_timeout
583
-
584
- SandboxApi._cls_kill(
585
- sandbox_id=self.sandbox_id,
586
- **config_dict,
587
- )
588
-
589
- @overload
590
- def set_timeout(
591
- self,
592
- timeout: int,
593
- request_timeout: Optional[float] = None,
594
- ) -> None:
595
- """
596
- Set the timeout of the sandbox.
597
- After the timeout expires the sandbox will be automatically killed.
598
- This method can extend or reduce the sandbox timeout set when creating the sandbox or from the last call to `.set_timeout`.
599
-
600
- 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.
601
-
602
- :param timeout: Timeout for the sandbox in **seconds**
603
- :param request_timeout: Timeout for the request in **seconds**
604
- """
605
- ...
606
-
607
- @overload
608
- @staticmethod
609
- def set_timeout(
610
- sandbox_id: str,
611
- timeout: int,
612
- api_key: Optional[str] = None,
613
- domain: Optional[str] = None,
614
- debug: Optional[bool] = None,
615
- request_timeout: Optional[float] = None,
616
- proxy: Optional[ProxyTypes] = None,
617
- ) -> None:
618
- """
619
- Set the timeout of the sandbox specified by sandbox ID.
620
- After the timeout expires the sandbox will be automatically killed.
621
- This method can extend or reduce the sandbox timeout set when creating the sandbox or from the last call to `.set_timeout`.
622
-
623
- 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.
624
-
625
- :param sandbox_id: Sandbox ID
626
- :param timeout: Timeout for the sandbox in **seconds**
627
- :param api_key: E2B API Key to use for authentication, defaults to `E2B_API_KEY` environment variable
628
- :param request_timeout: Timeout for the request in **seconds**
629
- :param proxy: Proxy to use for the request
630
- """
631
- ...
632
-
633
- @class_method_variant("_cls_set_timeout")
634
- def set_timeout( # type: ignore
635
- self,
636
- timeout: int,
637
- request_timeout: Optional[float] = None,
638
- ) -> None:
639
- config_dict = self.connection_config.__dict__
640
- config_dict.pop("access_token", None)
641
- config_dict.pop("api_url", None)
642
-
643
- if request_timeout:
644
- config_dict["request_timeout"] = request_timeout
645
-
646
- SandboxApi._cls_set_timeout(
647
- sandbox_id=self.sandbox_id,
648
- timeout=timeout,
649
- **config_dict,
650
- )
651
-
652
- @overload
653
- def get_info(
654
- self,
655
- request_timeout: Optional[float] = None,
656
- ) -> SandboxInfo:
657
- """
658
- Get sandbox information like sandbox ID, template, metadata, started at/end at date.
659
- :param request_timeout: Timeout for the request in **seconds**
660
- :return: Sandbox info
661
- """
662
- ...
663
-
664
- @overload
665
- @staticmethod
666
- def get_info(
667
- sandbox_id: str,
668
- api_key: Optional[str] = None,
669
- domain: Optional[str] = None,
670
- debug: Optional[bool] = None,
671
- request_timeout: Optional[float] = None,
672
- headers: Optional[Dict[str, str]] = None,
673
- proxy: Optional[ProxyTypes] = None,
674
- ) -> SandboxInfo:
675
- """
676
- Get sandbox information like sandbox ID, template, metadata, started at/end at date.
677
- :param sandbox_id: Sandbox ID
678
- :param api_key: E2B API Key to use for authentication, defaults to `E2B_API_KEY` environment variable
679
- :param domain: E2B domain to use for authentication, defaults to `E2B_DOMAIN` environment variable
680
- :param debug: Whether to use debug mode, defaults to `E2B_DEBUG` environment variable
681
- :param request_timeout: Timeout for the request in **seconds**
682
- :param headers: Custom headers to use for the request
683
- :param proxy: Proxy to use for the request
684
- :return: Sandbox info
685
- """
686
- ...
687
-
688
- @class_method_variant("_cls_get_info")
689
- def get_info( # type: ignore
690
- self,
691
- request_timeout: Optional[float] = None,
692
- ) -> SandboxInfo:
693
- """
694
- Get sandbox information like sandbox ID, template, metadata, started at/end at date.
695
- :param request_timeout: Timeout for the request in **seconds**
696
- :return: Sandbox info
697
- """
698
- config_dict = self.connection_config.__dict__
699
- config_dict.pop("access_token", None)
700
- config_dict.pop("api_url", None)
701
-
702
- if request_timeout:
703
- config_dict["request_timeout"] = request_timeout
704
-
705
- return SandboxApi._cls_get_info(
706
- sandbox_id=self.sandbox_id,
707
- **config_dict,
708
- )
709
-
710
- @overload
711
- def get_metrics( # type: ignore
712
- self,
713
- start: Optional[datetime.datetime] = None,
714
- end: Optional[datetime.datetime] = None,
715
- request_timeout: Optional[float] = None,
716
- ) -> List[SandboxMetrics]:
717
- """
718
- Get the metrics of the current sandbox.
719
-
720
- :param start: Start time for the metrics, defaults to the start of the sandbox
721
- :param end: End time for the metrics, defaults to current time
722
- :param request_timeout: Timeout for the request in **seconds**
723
-
724
- :return: List of sandbox metrics containing CPU, memory and disk usage information
725
- """
726
- ...
727
-
728
- @overload
729
- @staticmethod
730
- def get_metrics(
731
- sandbox_id: str,
732
- start: Optional[datetime.datetime] = None,
733
- end: Optional[datetime.datetime] = None,
734
- api_key: Optional[str] = None,
735
- domain: Optional[str] = None,
736
- debug: Optional[bool] = None,
737
- request_timeout: Optional[float] = None,
738
- ) -> List[SandboxMetrics]:
739
- """
740
- Get the metrics of the sandbox specified by sandbox ID.
741
-
742
- :param sandbox_id: Sandbox ID
743
- :param start: Start time for the metrics, defaults to the start of the sandbox
744
- :param end: End time for the metrics, defaults to current time
745
- :param api_key: E2B API Key to use for authentication, defaults to `E2B_API_KEY` environment variable
746
- :param request_timeout: Timeout for the request in **seconds**
747
-
748
- :return: List of sandbox metrics containing CPU, memory and disk usage information
749
- """
750
- ...
751
-
752
- @class_method_variant("_cls_get_metrics")
753
- def get_metrics( # type: ignore
754
- self,
755
- start: Optional[datetime.datetime] = None,
756
- end: Optional[datetime.datetime] = None,
757
- request_timeout: Optional[float] = None,
758
- ) -> List[SandboxMetrics]:
759
- """
760
- Get the metrics of the current sandbox.
761
-
762
- :param start: Start time for the metrics, defaults to the start of the sandbox
763
- :param end: End time for the metrics, defaults to current time
764
- :param request_timeout: Timeout for the request in **seconds**
765
-
766
- :return: List of sandbox metrics containing CPU, memory and disk usage information
767
- """
768
- if self._envd_version:
769
- if Version(self._envd_version) < Version("0.1.5"):
770
- raise SandboxException(
771
- "Metrics are not supported in this version of the sandbox, please rebuild your template."
772
- )
773
-
774
- if Version(self._envd_version) < Version("0.2.4"):
775
- logger.warning(
776
- "Disk metrics are not supported in this version of the sandbox, please rebuild the template to get disk metrics."
777
- )
778
-
779
- config_dict = self.connection_config.__dict__
780
- config_dict.pop("access_token", None)
781
- config_dict.pop("api_url", None)
782
- if request_timeout:
783
- config_dict["request_timeout"] = request_timeout
784
-
785
- return self._cls_get_metrics(
786
- sandbox_id=self.sandbox_id,
787
- start=start,
788
- end=end,
789
- **config_dict,
790
- )
1
+ import datetime
2
+ import logging
3
+ import socket
4
+ import time
5
+ from typing import Dict, List, Optional, TypedDict, overload
6
+
7
+ import httpx
8
+ import urllib3
9
+ from httpx import Timeout
10
+ from packaging.version import Version
11
+ from urllib3 import Retry
12
+
13
+ from ..api.client.types import Unset
14
+ from ..connection_config import ConnectionConfig, ProxyTypes
15
+ from ..exceptions import SandboxException, request_timeout_error
16
+ from ..generated.api import ENVD_API_HEALTH_ROUTE, handle_envd_api_exception
17
+ from ..sandbox.main import SandboxSetup
18
+ from ..sandbox.sandbox_api import SandboxMetrics
19
+ from ..sandbox.utils import class_method_variant
20
+ from ..sandbox_sync.commands.command import Commands
21
+ from ..sandbox_sync.commands.pty import Pty
22
+ from ..sandbox_sync.filesystem.filesystem import Filesystem
23
+ from ..sandbox_sync.sandbox_api import SandboxApi, SandboxInfo
24
+
25
+ logger = logging.getLogger(__name__)
26
+
27
+
28
+ class TransportWithLogger(httpx.HTTPTransport):
29
+ def handle_request(self, request):
30
+ url = f"{request.url.scheme}://{request.url.host}{request.url.path}"
31
+ logger.info(f"Request: {request.method} {url}")
32
+ response = super().handle_request(request)
33
+
34
+ # data = connect.GzipCompressor.decompress(response.read()).decode()
35
+ logger.info(f"Response: {response.status_code} {url}")
36
+
37
+ return response
38
+
39
+ class SandboxOpts(TypedDict):
40
+ sandbox_id: str
41
+ sandbox_domain: Optional[str]
42
+ envd_version: Optional[str]
43
+ envd_access_token: Optional[str]
44
+ connection_config: ConnectionConfig
45
+
46
+ class Sandbox(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 `Sandbox()` to create a new sandbox.
60
+
61
+ Example:
62
+ ```python
63
+ from e2b import Sandbox
64
+
65
+ sandbox = Sandbox()
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
+ Domain where the sandbox is hosted.
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: Optional[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__(
123
+ # self,
124
+ # template: Optional[str] = None,
125
+ # timeout: Optional[int] = None,
126
+ # metadata: Optional[Dict[str, str]] = None,
127
+ # envs: Optional[Dict[str, str]] = None,
128
+ # secure: Optional[bool] = None,
129
+ # api_key: Optional[str] = None,
130
+ # domain: Optional[str] = None,
131
+ # debug: Optional[bool] = None,
132
+ # sandbox_id: Optional[str] = None,
133
+ # request_timeout: Optional[float] = None,
134
+ # proxy: Optional[ProxyTypes] = None,
135
+ # allow_internet_access: Optional[bool] = True,
136
+ # ):
137
+ def __init__(self, **opts):
138
+ """
139
+ Create a new sandbox.
140
+
141
+ By default, the sandbox is created from the default `base` sandbox template.
142
+
143
+ :param template: Sandbox template name or ID
144
+ :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
145
+ :param metadata: Custom metadata for the sandbox
146
+ :param envs: Custom environment variables for the sandbox
147
+ :param api_key: E2B API Key to use for authentication, defaults to `E2B_API_KEY` environment variable
148
+ :param request_timeout: Timeout for the request in **seconds**
149
+ :param proxy: Proxy to use for the request and for the **requests made to the returned sandbox**
150
+ :param allow_internet_access: Allow sandbox to access the internet, defaults to `True`
151
+
152
+ :return: sandbox instance for the new sandbox
153
+ """
154
+ super().__init__()
155
+ self._connection_config = opts["connection_config"]
156
+
157
+ self._sandbox_id = opts["sandbox_id"]
158
+ self._sandbox_domain = opts["sandbox_domain"] or self.connection_config.domain
159
+ debug = self._connection_config.debug
160
+ # connection_headers = {"Authorization": "Bearer root", }
161
+
162
+ # if debug:
163
+ # self._sandbox_id = "debug_sandbox_id"
164
+ # self._sandbox_domain = None
165
+ # self._envd_version = None
166
+ # self._envd_access_token = None
167
+ # elif sandbox_id is not None:
168
+ # response = SandboxApi._cls_get_info(
169
+ # sandbox_id,
170
+ # api_key=api_key,
171
+ # domain=domain,
172
+ # debug=debug,
173
+ # request_timeout=request_timeout,
174
+ # proxy=proxy,
175
+ # )
176
+ #
177
+ # self._sandbox_id = sandbox_id
178
+ # self._sandbox_domain = response.sandbox_domain
179
+ # self._envd_version = response.envd_version
180
+ # self._envd_access_token = response._envd_access_token
181
+ #
182
+ # if response._envd_access_token is not None and not isinstance(
183
+ # response._envd_access_token, Unset
184
+ # ):
185
+ # connection_headers["X-Access-Token"] = response._envd_access_token
186
+ # else:
187
+ # template = template or self.default_template
188
+ # timeout = timeout or self.default_sandbox_timeout
189
+ # response = SandboxApi._create_sandbox(
190
+ # template=template,
191
+ # api_key=api_key,
192
+ # timeout=timeout,
193
+ # metadata=metadata,
194
+ # env_vars=envs,
195
+ # domain=domain,
196
+ # debug=debug,
197
+ # request_timeout=request_timeout,
198
+ # secure=secure or False,
199
+ # proxy=proxy,
200
+ # allow_internet_access=allow_internet_access,
201
+ # )
202
+ #
203
+ # self._sandbox_id = response.sandbox_id
204
+ # self._sandbox_domain = response.sandbox_domain
205
+ # self._envd_version = response.envd_version
206
+ #
207
+ # if response.envd_access_token is not None and not isinstance(
208
+ # response.envd_access_token, Unset
209
+ # ):
210
+ # self._envd_access_token = response.envd_access_token
211
+ # connection_headers["X-Access-Token"] = response.envd_access_token
212
+ # else:
213
+ # self._envd_access_token = None
214
+ # self._transport = TransportWithLogger(limits=self._limits, proxy=proxy)
215
+ # self._connection_config = ConnectionConfig(
216
+ # api_key=api_key,
217
+ # domain=domain,
218
+ # debug=debug,
219
+ # request_timeout=request_timeout,
220
+ # headers=connection_headers,
221
+ # proxy=proxy,
222
+ # )
223
+
224
+ self._sandbox_domain = self._sandbox_domain or self._connection_config.domain
225
+ # self._envd_api_url = f"{'http' if self.connection_config.debug else 'https'}://{self.get_host(self.envd_port)}"
226
+ if debug:
227
+ self._envd_api_url = f"http://{self.get_host(8888)}"
228
+ # elif self._sandbox_id is not None:
229
+ # response = SandboxApi._cls_get_info(
230
+ # self._sandbox_id,
231
+ # api_key=self._api_key(),
232
+ # domain=self._sandbox_domain,
233
+ # debug=debug,
234
+ # request_timeout=self.request_timeout,
235
+ # proxy=self.proxy,
236
+ # )
237
+ #
238
+ # self._sandbox_id = self._sandbox_id
239
+ # self._sandbox_domain = response.sandbox_domain
240
+ # self._envd_version = response.envd_version
241
+ # self._envd_access_token = response._envd_access_token
242
+ #
243
+ # if response._envd_access_token is not None and not isinstance(
244
+ # response._envd_access_token, Unset
245
+ # ):
246
+ # self._connection_config["X-Access-Token"] = response._envd_access_token
247
+ # self._envd_api_url = f"http://{self.get_host(self.envd_port)}"
248
+ else:
249
+ self._envd_api_url = f"https://{self.get_host(self.envd_port)}"
250
+ self._transport = TransportWithLogger(limits=self._limits, proxy=self._connection_config.proxy)
251
+ # self._envd_api_url = f"http://localhost:8088"
252
+ # self._envd_api_url = f"http://{self.get_host(self.envd_port)}"
253
+ # self._envd_api_url = f"http://localhost:31000"
254
+ self._envd_api = httpx.Client(
255
+ base_url=self._envd_api_url,
256
+ transport=self._transport,
257
+ headers=self.connection_config.headers,
258
+ )
259
+
260
+ self._envd_version=f"v1.0"
261
+ # 准备连接池参数
262
+ connection_pool_kw = {
263
+ # 连接池大小
264
+ "maxsize": 100,
265
+ "block": False,
266
+ # 超时设置
267
+ "timeout": self._connection_config.request_timeout,
268
+ # 重试策略
269
+ "retries": Retry(
270
+ total=3,
271
+ backoff_factor=0.1,
272
+ status_forcelist=[500, 502, 503, 504]
273
+ ),
274
+ # SSL 设置
275
+ # "cert_reqs": 'CERT_NONE',
276
+ "ca_certs": None,
277
+ # 套接字选项
278
+ "socket_options": [
279
+ (socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1),
280
+ (socket.IPPROTO_TCP, socket.TCP_NODELAY, 1),
281
+ ],
282
+ }
283
+
284
+ # 如果有代理配置,添加到连接池参数
285
+ if hasattr(self._connection_config, 'proxy') and self._connection_config.proxy:
286
+ connection_pool_kw["proxy_url"] = self._connection_config.proxy
287
+
288
+ # 创建 urllib3.PoolManager 连接池
289
+ self._urllib3_pool = urllib3.PoolManager(
290
+ num_pools=10, # 池的数量
291
+ headers=self._connection_config.headers, # 默认头部
292
+ **connection_pool_kw # 连接池参数
293
+ )
294
+
295
+ self._filesystem = Filesystem(
296
+ self.envd_api_url,
297
+ self._envd_version,
298
+ self.connection_config,
299
+ self._urllib3_pool,
300
+ self._envd_api,
301
+ )
302
+ self._commands = Commands(
303
+ self.envd_api_url,
304
+ self.connection_config,
305
+ self._urllib3_pool,
306
+ )
307
+ self._pty = Pty(
308
+ self.envd_api_url,
309
+ self.connection_config,
310
+ self._urllib3_pool,
311
+ )
312
+
313
+ @classmethod
314
+ def create(
315
+ cls,
316
+ template: Optional[str] = None,
317
+ timeout: Optional[int] = None,
318
+ metadata: Optional[Dict[str, str]] = None,
319
+ envs: Optional[Dict[str, str]] = None,
320
+ api_key: Optional[str] = None,
321
+ domain: Optional[str] = None,
322
+ debug: Optional[bool] = None,
323
+ sandbox_id: Optional[str] = None,
324
+ request_timeout: Optional[float] = None,
325
+ proxy: Optional[ProxyTypes] = None,
326
+ secure: Optional[bool] = None,
327
+ allow_internet_access: Optional[bool] = True,
328
+ ):
329
+ """
330
+ Create a new sandbox.
331
+
332
+ By default, the sandbox is created from the default `base` sandbox template.
333
+
334
+ :param template: Sandbox template name or ID
335
+ :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.
336
+ :param metadata: Custom metadata for the sandbox
337
+ :param envs: Custom environment variables for the sandbox
338
+ :param api_key: scalebox API Key to use for authentication, defaults to `CSX_API_KEY` environment variable
339
+ :param request_timeout: Timeout for the request in **seconds**
340
+ :param proxy: Proxy to use for the request and for the **requests made to the returned sandbox**
341
+ :param secure: Envd is secured with access token and cannot be used without it
342
+ :param allow_internet_access: Allow sandbox to access the internet, defaults to `True`.
343
+
344
+ :return: sandbox instance for the new sandbox
345
+
346
+ Use this method instead of using the constructor to create a new sandbox.
347
+ """
348
+ if sandbox_id and (metadata is not None or template is not None):
349
+ raise SandboxException(
350
+ "Cannot set metadata or timeout when connecting to an existing sandbox. "
351
+ "Use Sandbox.connect method instead.",
352
+ )
353
+ connection_headers = {"Authorization": "Bearer root", }
354
+ if debug:
355
+ sandbox_id = "debug_sandbox_id"
356
+ sandbox_domain = None
357
+ envd_version = None
358
+ envd_access_token = "123456789"
359
+ elif sandbox_id is not None:
360
+ response = SandboxApi._cls_get_info(
361
+ sandbox_id,
362
+ api_key=api_key,
363
+ domain=domain,
364
+ debug=debug,
365
+ request_timeout=request_timeout,
366
+ proxy=proxy,
367
+ )
368
+
369
+ sandbox_domain = response.sandbox_domain
370
+ envd_version = response.envd_version
371
+ envd_access_token = response._envd_access_token
372
+
373
+ if response._envd_access_token is not None and not isinstance(
374
+ response._envd_access_token, Unset
375
+ ):
376
+ connection_headers["X-Access-Token"] = response._envd_access_token
377
+ else:
378
+ response = SandboxApi._create_sandbox(
379
+ template=template or cls.default_template,
380
+ api_key=api_key,
381
+ timeout=timeout or cls.default_sandbox_timeout,
382
+ metadata=metadata,
383
+ domain=domain,
384
+ debug=debug,
385
+ request_timeout=request_timeout,
386
+ env_vars=envs,
387
+ secure=secure,
388
+ proxy=proxy,
389
+ allow_internet_access=allow_internet_access,
390
+ )
391
+
392
+ sandbox_id = response.sandbox_id
393
+ sandbox_domain = response.sandbox_domain
394
+ envd_version = response.envd_version
395
+ envd_access_token = response.envd_access_token
396
+
397
+ if envd_access_token is not None and not isinstance(
398
+ envd_access_token, Unset
399
+ ):
400
+ connection_headers["X-Access-Token"] = envd_access_token
401
+
402
+ connection_config = ConnectionConfig(
403
+ api_key=api_key,
404
+ domain=domain,
405
+ debug=debug,
406
+ request_timeout=request_timeout,
407
+ headers=connection_headers,
408
+ proxy=proxy,
409
+ )
410
+ print("connection_config" + str(connection_config.__dict__))
411
+ sanbox= cls(
412
+ sandbox_id=sandbox_id,
413
+ sandbox_domain=sandbox_domain,
414
+ envd_version=envd_version,
415
+ envd_access_token=envd_access_token,
416
+ connection_config=connection_config,
417
+ )
418
+
419
+ timeout = 5.0
420
+ interval = 0.3
421
+ elapsed = 0.0
422
+ while elapsed <= timeout:
423
+ try:
424
+ isRunning = sanbox.is_running(request_timeout=1)
425
+ if isRunning:
426
+ break
427
+ except Exception:
428
+ pass
429
+ time.sleep(interval)
430
+ elapsed += interval
431
+ else:
432
+ print("connect "+sandbox_domain+ENVD_API_HEALTH_ROUTE +" timeout 5s")
433
+ return sanbox
434
+
435
+ def is_running(self, request_timeout: Optional[float] = None) -> bool:
436
+ """
437
+ Check if the sandbox is running.
438
+
439
+ :param request_timeout: Timeout for the request in **seconds**
440
+
441
+ :return: `True` if the sandbox is running, `False` otherwise
442
+
443
+ Example
444
+ ```python
445
+ sandbox = Sandbox()
446
+ sandbox.is_running() # Returns True
447
+
448
+ sandbox.kill()
449
+ sandbox.is_running() # Returns False
450
+ ```
451
+ """
452
+ try:
453
+ r = self._envd_api.get(
454
+ ENVD_API_HEALTH_ROUTE,
455
+ timeout=self.connection_config.get_request_timeout(request_timeout),
456
+ )
457
+ print(r)
458
+ if r.status_code == 502:
459
+ return False
460
+
461
+ err = handle_envd_api_exception(r)
462
+
463
+ if err:
464
+ raise err
465
+
466
+ except httpx.TimeoutException:
467
+ raise request_timeout_error()
468
+
469
+ return True
470
+
471
+ @classmethod
472
+ def connect(
473
+ cls,
474
+ sandbox_id: str,
475
+ api_key: Optional[str] = None,
476
+ domain: Optional[str] = None,
477
+ debug: Optional[bool] = None,
478
+ proxy: Optional[ProxyTypes] = None,
479
+ ):
480
+ """
481
+ Connects to an existing Sandbox.
482
+ With sandbox ID you can connect to the same sandbox from different places or environments (serverless functions, etc).
483
+
484
+ :param sandbox_id: Sandbox ID
485
+ :param api_key: E2B API Key to use for authentication, defaults to `E2B_API_KEY` environment variable
486
+ :param proxy: Proxy to use for the request and for the **requests made to the returned sandbox**
487
+
488
+ :return: sandbox instance for the existing sandbox
489
+
490
+ @example
491
+ ```python
492
+ sandbox = Sandbox()
493
+ sandbox_id = sandbox.sandbox_id
494
+
495
+ # Another code block
496
+ same_sandbox = Sandbox.connect(sandbox_id)
497
+ ```
498
+ """
499
+ connection_headers = {"Authorization": "Bearer root"}
500
+
501
+ response = SandboxApi._cls_get_info(
502
+ sandbox_id,
503
+ api_key=api_key,
504
+ domain=domain,
505
+ debug=debug,
506
+ proxy=proxy,
507
+ )
508
+
509
+ if response._envd_access_token is not None and not isinstance(
510
+ response._envd_access_token, Unset
511
+ ):
512
+ connection_headers["X-Access-Token"] = response._envd_access_token
513
+ connection_config = ConnectionConfig(
514
+ api_key=api_key,
515
+ domain=domain,
516
+ debug=debug,
517
+ headers=connection_headers,
518
+ proxy=proxy,
519
+ )
520
+
521
+ return cls(
522
+ sandbox_id=sandbox_id,
523
+ sandbox_domain=response.sandbox_domain,
524
+ envd_version=response.envd_version,
525
+ envd_access_token=response._envd_access_token,
526
+ connection_config=connection_config,
527
+ )
528
+
529
+ def __enter__(self):
530
+ return self
531
+
532
+ def __exit__(self, exc_type, exc_value, traceback):
533
+ self.kill()
534
+
535
+ @overload
536
+ def kill(self, request_timeout: Optional[float] = None) -> bool:
537
+ """
538
+ Kill the sandbox.
539
+
540
+ :param request_timeout: Timeout for the request in **seconds**
541
+
542
+ :return: `True` if the sandbox was killed, `False` if the sandbox was not found
543
+ """
544
+ ...
545
+
546
+ @overload
547
+ @staticmethod
548
+ def kill(
549
+ sandbox_id: str,
550
+ api_key: Optional[str] = None,
551
+ domain: Optional[str] = None,
552
+ debug: Optional[bool] = None,
553
+ request_timeout: Optional[float] = None,
554
+ proxy: Optional[ProxyTypes] = None,
555
+ ) -> bool:
556
+ """
557
+ Kill the sandbox specified by sandbox ID.
558
+
559
+ :param sandbox_id: Sandbox ID
560
+ :param api_key: E2B API Key to use for authentication, defaults to `E2B_API_KEY` environment variable
561
+ :param request_timeout: Timeout for the request in **seconds**
562
+ :param proxy: Proxy to use for the request
563
+
564
+ :return: `True` if the sandbox was killed, `False` if the sandbox was not found
565
+ """
566
+ ...
567
+
568
+ @class_method_variant("_cls_kill")
569
+ def kill(self, request_timeout: Optional[float] = None) -> bool: # type: ignore
570
+ """
571
+ Kill the sandbox.
572
+
573
+ :param request_timeout: Timeout for the request
574
+ :return: `True` if the sandbox was killed, `False` if the sandbox was not found
575
+ """
576
+ config_dict = self.connection_config.__dict__
577
+ config_dict.pop("access_token", None)
578
+ config_dict.pop("api_url", None)
579
+
580
+ if request_timeout:
581
+ config_dict["request_timeout"] = request_timeout
582
+
583
+ SandboxApi._cls_kill(
584
+ sandbox_id=self.sandbox_id,
585
+ **config_dict,
586
+ )
587
+
588
+ @overload
589
+ def set_timeout(
590
+ self,
591
+ timeout: int,
592
+ request_timeout: Optional[float] = None,
593
+ ) -> None:
594
+ """
595
+ Set the timeout of the sandbox.
596
+ After the timeout expires the sandbox will be automatically killed.
597
+ This method can extend or reduce the sandbox timeout set when creating the sandbox or from the last call to `.set_timeout`.
598
+
599
+ 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.
600
+
601
+ :param timeout: Timeout for the sandbox in **seconds**
602
+ :param request_timeout: Timeout for the request in **seconds**
603
+ """
604
+ ...
605
+
606
+ @overload
607
+ @staticmethod
608
+ def set_timeout(
609
+ sandbox_id: str,
610
+ timeout: int,
611
+ api_key: Optional[str] = None,
612
+ domain: Optional[str] = None,
613
+ debug: Optional[bool] = None,
614
+ request_timeout: Optional[float] = None,
615
+ proxy: Optional[ProxyTypes] = None,
616
+ ) -> None:
617
+ """
618
+ Set the timeout of the sandbox specified by sandbox ID.
619
+ After the timeout expires the sandbox will be automatically killed.
620
+ This method can extend or reduce the sandbox timeout set when creating the sandbox or from the last call to `.set_timeout`.
621
+
622
+ 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.
623
+
624
+ :param sandbox_id: Sandbox ID
625
+ :param timeout: Timeout for the sandbox in **seconds**
626
+ :param api_key: E2B API Key to use for authentication, defaults to `E2B_API_KEY` environment variable
627
+ :param request_timeout: Timeout for the request in **seconds**
628
+ :param proxy: Proxy to use for the request
629
+ """
630
+ ...
631
+
632
+ @class_method_variant("_cls_set_timeout")
633
+ def set_timeout( # type: ignore
634
+ self,
635
+ timeout: int,
636
+ request_timeout: Optional[float] = None,
637
+ ) -> None:
638
+ config_dict = self.connection_config.__dict__
639
+ config_dict.pop("access_token", None)
640
+ config_dict.pop("api_url", None)
641
+
642
+ if request_timeout:
643
+ config_dict["request_timeout"] = request_timeout
644
+
645
+ SandboxApi._cls_set_timeout(
646
+ sandbox_id=self.sandbox_id,
647
+ timeout=timeout,
648
+ **config_dict,
649
+ )
650
+
651
+ @overload
652
+ def get_info(
653
+ self,
654
+ request_timeout: Optional[float] = None,
655
+ ) -> SandboxInfo:
656
+ """
657
+ Get sandbox information like sandbox ID, template, metadata, started at/end at date.
658
+ :param request_timeout: Timeout for the request in **seconds**
659
+ :return: Sandbox info
660
+ """
661
+ ...
662
+
663
+ @overload
664
+ @staticmethod
665
+ def get_info(
666
+ sandbox_id: str,
667
+ api_key: Optional[str] = None,
668
+ domain: Optional[str] = None,
669
+ debug: Optional[bool] = None,
670
+ request_timeout: Optional[float] = None,
671
+ headers: Optional[Dict[str, str]] = None,
672
+ proxy: Optional[ProxyTypes] = None,
673
+ ) -> SandboxInfo:
674
+ """
675
+ Get sandbox information like sandbox ID, template, metadata, started at/end at date.
676
+ :param sandbox_id: Sandbox ID
677
+ :param api_key: E2B API Key to use for authentication, defaults to `E2B_API_KEY` environment variable
678
+ :param domain: E2B domain to use for authentication, defaults to `E2B_DOMAIN` environment variable
679
+ :param debug: Whether to use debug mode, defaults to `E2B_DEBUG` environment variable
680
+ :param request_timeout: Timeout for the request in **seconds**
681
+ :param headers: Custom headers to use for the request
682
+ :param proxy: Proxy to use for the request
683
+ :return: Sandbox info
684
+ """
685
+ ...
686
+
687
+ @class_method_variant("_cls_get_info")
688
+ def get_info( # type: ignore
689
+ self,
690
+ request_timeout: Optional[float] = None,
691
+ ) -> SandboxInfo:
692
+ """
693
+ Get sandbox information like sandbox ID, template, metadata, started at/end at date.
694
+ :param request_timeout: Timeout for the request in **seconds**
695
+ :return: Sandbox info
696
+ """
697
+ config_dict = self.connection_config.__dict__
698
+ config_dict.pop("access_token", None)
699
+ config_dict.pop("api_url", None)
700
+
701
+ if request_timeout:
702
+ config_dict["request_timeout"] = request_timeout
703
+
704
+ return SandboxApi._cls_get_info(
705
+ sandbox_id=self.sandbox_id,
706
+ **config_dict,
707
+ )
708
+
709
+ @overload
710
+ def get_metrics( # type: ignore
711
+ self,
712
+ start: Optional[datetime.datetime] = None,
713
+ end: Optional[datetime.datetime] = None,
714
+ request_timeout: Optional[float] = None,
715
+ ) -> List[SandboxMetrics]:
716
+ """
717
+ Get the metrics of the current sandbox.
718
+
719
+ :param start: Start time for the metrics, defaults to the start of the sandbox
720
+ :param end: End time for the metrics, defaults to current time
721
+ :param request_timeout: Timeout for the request in **seconds**
722
+
723
+ :return: List of sandbox metrics containing CPU, memory and disk usage information
724
+ """
725
+ ...
726
+
727
+ @overload
728
+ @staticmethod
729
+ def get_metrics(
730
+ sandbox_id: str,
731
+ start: Optional[datetime.datetime] = None,
732
+ end: Optional[datetime.datetime] = None,
733
+ api_key: Optional[str] = None,
734
+ domain: Optional[str] = None,
735
+ debug: Optional[bool] = None,
736
+ request_timeout: Optional[float] = None,
737
+ ) -> List[SandboxMetrics]:
738
+ """
739
+ Get the metrics of the sandbox specified by sandbox ID.
740
+
741
+ :param sandbox_id: Sandbox ID
742
+ :param start: Start time for the metrics, defaults to the start of the sandbox
743
+ :param end: End time for the metrics, defaults to current time
744
+ :param api_key: E2B API Key to use for authentication, defaults to `E2B_API_KEY` environment variable
745
+ :param request_timeout: Timeout for the request in **seconds**
746
+
747
+ :return: List of sandbox metrics containing CPU, memory and disk usage information
748
+ """
749
+ ...
750
+
751
+ @class_method_variant("_cls_get_metrics")
752
+ def get_metrics( # type: ignore
753
+ self,
754
+ start: Optional[datetime.datetime] = None,
755
+ end: Optional[datetime.datetime] = None,
756
+ request_timeout: Optional[float] = None,
757
+ ) -> List[SandboxMetrics]:
758
+ """
759
+ Get the metrics of the current sandbox.
760
+
761
+ :param start: Start time for the metrics, defaults to the start of the sandbox
762
+ :param end: End time for the metrics, defaults to current time
763
+ :param request_timeout: Timeout for the request in **seconds**
764
+
765
+ :return: List of sandbox metrics containing CPU, memory and disk usage information
766
+ """
767
+ if self._envd_version:
768
+ if Version(self._envd_version) < Version("0.1.5"):
769
+ raise SandboxException(
770
+ "Metrics are not supported in this version of the sandbox, please rebuild your template."
771
+ )
772
+
773
+ if Version(self._envd_version) < Version("0.2.4"):
774
+ logger.warning(
775
+ "Disk metrics are not supported in this version of the sandbox, please rebuild the template to get disk metrics."
776
+ )
777
+
778
+ config_dict = self.connection_config.__dict__
779
+ config_dict.pop("access_token", None)
780
+ config_dict.pop("api_url", None)
781
+ if request_timeout:
782
+ config_dict["request_timeout"] = request_timeout
783
+
784
+ return self._cls_get_metrics(
785
+ sandbox_id=self.sandbox_id,
786
+ start=start,
787
+ end=end,
788
+ **config_dict,
789
+ )