scalebox-sdk 0.1.24__py3-none-any.whl → 1.0.1__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 (87) hide show
  1. scalebox/__init__.py +2 -2
  2. scalebox/api/__init__.py +130 -128
  3. scalebox/api/client/__init__.py +8 -8
  4. scalebox/api/client/api/sandboxes/get_sandboxes_sandbox_id_metrics.py +2 -2
  5. scalebox/api/client/api/sandboxes/post_sandboxes.py +2 -2
  6. scalebox/api/client/api/sandboxes/post_sandboxes_sandbox_id_connect.py +193 -0
  7. scalebox/api/client/client.py +288 -288
  8. scalebox/api/client/models/connect_sandbox.py +59 -0
  9. scalebox/api/client/models/error.py +2 -2
  10. scalebox/api/client/models/listed_sandbox.py +19 -1
  11. scalebox/api/client/models/new_sandbox.py +10 -0
  12. scalebox/api/client/models/sandbox.py +138 -125
  13. scalebox/api/client/models/sandbox_detail.py +24 -0
  14. scalebox/api/client/types.py +46 -46
  15. scalebox/cli.py +125 -125
  16. scalebox/client/aclient.py +57 -57
  17. scalebox/client/client.py +102 -102
  18. scalebox/code_interpreter/__init__.py +12 -12
  19. scalebox/code_interpreter/charts.py +230 -230
  20. scalebox/code_interpreter/constants.py +3 -3
  21. scalebox/code_interpreter/exceptions.py +13 -13
  22. scalebox/code_interpreter/models.py +485 -485
  23. scalebox/connection_config.py +34 -1
  24. scalebox/csx_connect/__init__.py +1 -1
  25. scalebox/csx_connect/client.py +485 -485
  26. scalebox/csx_desktop/main.py +651 -651
  27. scalebox/exceptions.py +83 -83
  28. scalebox/generated/api.py +61 -61
  29. scalebox/generated/api_pb2.py +203 -203
  30. scalebox/generated/api_pb2.pyi +956 -956
  31. scalebox/generated/api_pb2_connect.py +1407 -1407
  32. scalebox/generated/rpc.py +50 -50
  33. scalebox/sandbox/main.py +146 -139
  34. scalebox/sandbox/sandbox_api.py +105 -91
  35. scalebox/sandbox/signature.py +40 -40
  36. scalebox/sandbox/utils.py +34 -34
  37. scalebox/sandbox_async/commands/command.py +307 -307
  38. scalebox/sandbox_async/commands/command_handle.py +187 -187
  39. scalebox/sandbox_async/commands/pty.py +187 -187
  40. scalebox/sandbox_async/filesystem/filesystem.py +557 -557
  41. scalebox/sandbox_async/filesystem/watch_handle.py +61 -61
  42. scalebox/sandbox_async/main.py +228 -46
  43. scalebox/sandbox_async/sandbox_api.py +124 -3
  44. scalebox/sandbox_async/utils.py +7 -7
  45. scalebox/sandbox_sync/__init__.py +2 -2
  46. scalebox/sandbox_sync/commands/command.py +300 -300
  47. scalebox/sandbox_sync/commands/command_handle.py +150 -150
  48. scalebox/sandbox_sync/commands/pty.py +181 -181
  49. scalebox/sandbox_sync/filesystem/filesystem.py +3 -3
  50. scalebox/sandbox_sync/filesystem/watch_handle.py +66 -66
  51. scalebox/sandbox_sync/main.py +208 -133
  52. scalebox/sandbox_sync/sandbox_api.py +119 -3
  53. scalebox/test/CODE_INTERPRETER_TESTS_READY.md +323 -323
  54. scalebox/test/README.md +329 -329
  55. scalebox/test/bedrock_openai_adapter.py +67 -0
  56. scalebox/test/code_interpreter_test.py +34 -34
  57. scalebox/test/code_interpreter_test_sync.py +34 -34
  58. scalebox/test/run_stress_code_interpreter_sync.py +166 -0
  59. scalebox/test/simple_upload_example.py +123 -0
  60. scalebox/test/stabitiy_test.py +310 -0
  61. scalebox/test/test_browser_use.py +25 -0
  62. scalebox/test/test_browser_use_scalebox.py +61 -0
  63. scalebox/test/test_code_interpreter_sync_comprehensive.py +115 -65
  64. scalebox/test/test_connect_pause_async.py +277 -0
  65. scalebox/test/test_connect_pause_sync.py +267 -0
  66. scalebox/test/test_desktop_sandbox_sf.py +117 -0
  67. scalebox/test/test_download_url.py +49 -0
  68. scalebox/test/test_sandbox_async_comprehensive.py +1 -1
  69. scalebox/test/test_sandbox_object_storage_example.py +146 -0
  70. scalebox/test/test_sandbox_object_storage_example_async.py +156 -0
  71. scalebox/test/test_sf.py +137 -0
  72. scalebox/test/test_watch_dir_async.py +56 -0
  73. scalebox/test/testacreate.py +1 -1
  74. scalebox/test/testagetinfo.py +1 -1
  75. scalebox/test/testcomputeuse.py +243 -243
  76. scalebox/test/testsandbox_api.py +13 -0
  77. scalebox/test/testsandbox_sync.py +1 -1
  78. scalebox/test/upload_100mb_example.py +355 -0
  79. scalebox/utils/httpcoreclient.py +297 -297
  80. scalebox/utils/httpxclient.py +403 -403
  81. scalebox/version.py +2 -2
  82. {scalebox_sdk-0.1.24.dist-info → scalebox_sdk-1.0.1.dist-info}/METADATA +1 -1
  83. {scalebox_sdk-0.1.24.dist-info → scalebox_sdk-1.0.1.dist-info}/RECORD +87 -69
  84. {scalebox_sdk-0.1.24.dist-info → scalebox_sdk-1.0.1.dist-info}/WHEEL +1 -1
  85. {scalebox_sdk-0.1.24.dist-info → scalebox_sdk-1.0.1.dist-info}/entry_points.txt +0 -0
  86. {scalebox_sdk-0.1.24.dist-info → scalebox_sdk-1.0.1.dist-info}/licenses/LICENSE +0 -0
  87. {scalebox_sdk-0.1.24.dist-info → scalebox_sdk-1.0.1.dist-info}/top_level.txt +0 -0
@@ -148,7 +148,7 @@ class Filesystem:
148
148
  self,
149
149
  path: str,
150
150
  data: Union[str, bytes, IO],
151
- user: Username = "user",
151
+ user: Username = "root",
152
152
  request_timeout: Optional[float] = None,
153
153
  ) -> WriteInfo:
154
154
  """
@@ -172,7 +172,7 @@ class Filesystem:
172
172
  def write(
173
173
  self,
174
174
  files: List[WriteEntry],
175
- user: Optional[Username] = "user",
175
+ user: Optional[Username] = "root",
176
176
  request_timeout: Optional[float] = None,
177
177
  ) -> List[WriteInfo]:
178
178
  """
@@ -190,7 +190,7 @@ class Filesystem:
190
190
  def write(
191
191
  self,
192
192
  path_or_files: Union[str, List[WriteEntry]],
193
- data_or_user: Union[str, bytes, IO, Username] = "user",
193
+ data_or_user: Union[str, bytes, IO, Username] = "root",
194
194
  user_or_request_timeout: Optional[Union[float, Username]] = None,
195
195
  request_timeout_or_none: Optional[float] = None,
196
196
  ) -> Union[WriteInfo, List[WriteInfo]]:
@@ -1,66 +1,66 @@
1
- from typing import List
2
-
3
- from ...exceptions import SandboxException
4
- from ...generated import api_pb2_connect
5
- from ...generated.api_pb2 import GetWatcherEventsRequest, RemoveWatcherRequest
6
- from ...generated.rpc import handle_rpc_exception
7
- from ...sandbox.filesystem.watch_handle import FilesystemEvent, map_event_type
8
-
9
-
10
- class WatchHandle:
11
- """
12
- Handle for watching filesystem events.
13
- It is used to get the latest events that have occurred in the watched directory.
14
-
15
- Use `.stop()` to stop watching the directory.
16
- """
17
-
18
- def __init__(
19
- self,
20
- rpc: api_pb2_connect.FilesystemClient,
21
- watcher_id: str,
22
- ):
23
- self._rpc = rpc
24
- self._watcher_id = watcher_id
25
- self._closed = False
26
-
27
- def stop(self):
28
- """
29
- Stop watching the directory.
30
- After you stop the watcher you won't be able to get the events anymore.
31
- """
32
- try:
33
- self._rpc.remove_watcher(RemoveWatcherRequest(watcher_id=self._watcher_id))
34
- except Exception as e:
35
- raise handle_rpc_exception(e)
36
-
37
- self._closed = True
38
-
39
- def get_new_events(self) -> List[FilesystemEvent]:
40
- """
41
- Get the latest events that have occurred in the watched directory since the last call, or from the beginning of the watching, up until now.
42
-
43
- :return: List of filesystem events
44
- """
45
- if self._closed:
46
- raise SandboxException("The watcher is already stopped")
47
-
48
- try:
49
- r = self._rpc.get_watcher_events(
50
- GetWatcherEventsRequest(watcher_id=self._watcher_id)
51
- )
52
- except Exception as e:
53
- raise handle_rpc_exception(e)
54
-
55
- events = []
56
- for event in r.events:
57
- event_type = map_event_type(event.type)
58
- if event_type:
59
- events.append(
60
- FilesystemEvent(
61
- name=event.name,
62
- type=event_type,
63
- )
64
- )
65
-
66
- return events
1
+ from typing import List
2
+
3
+ from ...exceptions import SandboxException
4
+ from ...generated import api_pb2_connect
5
+ from ...generated.api_pb2 import GetWatcherEventsRequest, RemoveWatcherRequest
6
+ from ...generated.rpc import handle_rpc_exception
7
+ from ...sandbox.filesystem.watch_handle import FilesystemEvent, map_event_type
8
+
9
+
10
+ class WatchHandle:
11
+ """
12
+ Handle for watching filesystem events.
13
+ It is used to get the latest events that have occurred in the watched directory.
14
+
15
+ Use `.stop()` to stop watching the directory.
16
+ """
17
+
18
+ def __init__(
19
+ self,
20
+ rpc: api_pb2_connect.FilesystemClient,
21
+ watcher_id: str,
22
+ ):
23
+ self._rpc = rpc
24
+ self._watcher_id = watcher_id
25
+ self._closed = False
26
+
27
+ def stop(self):
28
+ """
29
+ Stop watching the directory.
30
+ After you stop the watcher you won't be able to get the events anymore.
31
+ """
32
+ try:
33
+ self._rpc.remove_watcher(RemoveWatcherRequest(watcher_id=self._watcher_id))
34
+ except Exception as e:
35
+ raise handle_rpc_exception(e)
36
+
37
+ self._closed = True
38
+
39
+ def get_new_events(self) -> List[FilesystemEvent]:
40
+ """
41
+ Get the latest events that have occurred in the watched directory since the last call, or from the beginning of the watching, up until now.
42
+
43
+ :return: List of filesystem events
44
+ """
45
+ if self._closed:
46
+ raise SandboxException("The watcher is already stopped")
47
+
48
+ try:
49
+ r = self._rpc.get_watcher_events(
50
+ GetWatcherEventsRequest(watcher_id=self._watcher_id)
51
+ )
52
+ except Exception as e:
53
+ raise handle_rpc_exception(e)
54
+
55
+ events = []
56
+ for event in r.events:
57
+ event_type = map_event_type(event.type)
58
+ if event_type:
59
+ events.append(
60
+ FilesystemEvent(
61
+ name=event.name,
62
+ type=event_type,
63
+ )
64
+ )
65
+
66
+ return events
@@ -8,10 +8,11 @@ import httpx
8
8
  import urllib3
9
9
  from httpx import Timeout
10
10
  from packaging.version import Version
11
+ from typing_extensions import Self, Unpack
11
12
  from urllib3 import Retry
12
13
 
13
14
  from ..api.client.types import Unset
14
- from ..connection_config import ConnectionConfig, ProxyTypes
15
+ from ..connection_config import ConnectionConfig, ProxyTypes,ApiParams
15
16
  from ..exceptions import SandboxException, request_timeout_error
16
17
  from ..generated.api import ENVD_API_HEALTH_ROUTE, handle_envd_api_exception
17
18
  from ..sandbox.main import SandboxSetup
@@ -101,6 +102,17 @@ class Sandbox(SandboxSetup, SandboxApi):
101
102
  """
102
103
  return self._sandbox_domain
103
104
 
105
+ @property
106
+ def object_storage(self) -> Optional[Dict[str, str]]:
107
+ """
108
+ Object storage configuration returned during sandbox creation (if any).
109
+ Only synchronous sandboxes currently expose this field.
110
+ """
111
+ return self._object_storage
112
+
113
+ def network_proxy(self) -> Optional[Dict[str, any]]:
114
+ return self._network_proxy
115
+
104
116
  @property
105
117
  def envd_api_url(self) -> str:
106
118
  return self._envd_api_url
@@ -153,104 +165,19 @@ class Sandbox(SandboxSetup, SandboxApi):
153
165
  """
154
166
  super().__init__()
155
167
  self._connection_config = opts["connection_config"]
156
-
168
+ self._object_storage = opts["object_storage"]
157
169
  self._sandbox_id = opts["sandbox_id"]
170
+ self._network_proxy = opts["network_proxy"]
158
171
  self._sandbox_domain = opts["sandbox_domain"] or self.connection_config.domain
159
172
  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
- # )
173
+ self.__envd_access_token=opts["envd_access_token"]
223
174
 
224
175
  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
176
  if debug:
227
177
  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
178
  else:
249
179
  self._envd_api_url = f"https://{self.get_host(self.envd_port)}"
250
180
  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
181
  self._envd_api = httpx.Client(
255
182
  base_url=self._envd_api_url,
256
183
  transport=self._transport,
@@ -317,6 +244,7 @@ class Sandbox(SandboxSetup, SandboxApi):
317
244
  timeout: Optional[int] = None,
318
245
  metadata: Optional[Dict[str, str]] = None,
319
246
  envs: Optional[Dict[str, str]] = None,
247
+ object_storage:Optional[Dict[str, str]] = None,
320
248
  api_key: Optional[str] = None,
321
249
  domain: Optional[str] = None,
322
250
  debug: Optional[bool] = None,
@@ -325,6 +253,7 @@ class Sandbox(SandboxSetup, SandboxApi):
325
253
  proxy: Optional[ProxyTypes] = None,
326
254
  secure: Optional[bool] = None,
327
255
  allow_internet_access: Optional[bool] = True,
256
+ net_proxy_country: Optional[str] = None
328
257
  ):
329
258
  """
330
259
  Create a new sandbox.
@@ -350,6 +279,7 @@ class Sandbox(SandboxSetup, SandboxApi):
350
279
  "Cannot set metadata or timeout when connecting to an existing sandbox. "
351
280
  "Use Sandbox.connect method instead.",
352
281
  )
282
+ network_proxy = {}
353
283
  connection_headers = {"Authorization": "Bearer root", }
354
284
  if debug:
355
285
  sandbox_id = "debug_sandbox_id"
@@ -369,6 +299,8 @@ class Sandbox(SandboxSetup, SandboxApi):
369
299
  sandbox_domain = response.sandbox_domain
370
300
  envd_version = response.envd_version
371
301
  envd_access_token = response._envd_access_token
302
+ object_storage = response.object_storage
303
+ network_proxy = response.network_proxy
372
304
 
373
305
  if response._envd_access_token is not None and not isinstance(
374
306
  response._envd_access_token, Unset
@@ -387,12 +319,16 @@ class Sandbox(SandboxSetup, SandboxApi):
387
319
  secure=secure,
388
320
  proxy=proxy,
389
321
  allow_internet_access=allow_internet_access,
322
+ object_storage=object_storage,
323
+ net_proxy_country=net_proxy_country
390
324
  )
391
325
 
392
326
  sandbox_id = response.sandbox_id
393
327
  sandbox_domain = response.sandbox_domain
394
328
  envd_version = response.envd_version
395
329
  envd_access_token = response.envd_access_token
330
+ object_storage = response.object_storage
331
+ network_proxy = response.network_proxy
396
332
 
397
333
  if envd_access_token is not None and not isinstance(
398
334
  envd_access_token, Unset
@@ -407,16 +343,18 @@ class Sandbox(SandboxSetup, SandboxApi):
407
343
  headers=connection_headers,
408
344
  proxy=proxy,
409
345
  )
410
- print("connection_config" + str(connection_config.__dict__))
346
+ # print("connection_config" + str(connection_config.__dict__))
411
347
  sanbox= cls(
412
348
  sandbox_id=sandbox_id,
413
349
  sandbox_domain=sandbox_domain,
414
350
  envd_version=envd_version,
415
351
  envd_access_token=envd_access_token,
416
352
  connection_config=connection_config,
353
+ object_storage=object_storage,
354
+ network_proxy=network_proxy
417
355
  )
418
356
 
419
- timeout = 5.0
357
+ timeout = 10.0
420
358
  interval = 0.3
421
359
  elapsed = 0.0
422
360
  while elapsed <= timeout:
@@ -429,7 +367,7 @@ class Sandbox(SandboxSetup, SandboxApi):
429
367
  time.sleep(interval)
430
368
  elapsed += interval
431
369
  else:
432
- print("connect "+sandbox_domain+ENVD_API_HEALTH_ROUTE +" timeout 5s")
370
+ print("connect "+sandbox_domain+ENVD_API_HEALTH_ROUTE +" timeout 10s")
433
371
  return sanbox
434
372
 
435
373
  def is_running(self, request_timeout: Optional[float] = None) -> bool:
@@ -454,7 +392,7 @@ class Sandbox(SandboxSetup, SandboxApi):
454
392
  ENVD_API_HEALTH_ROUTE,
455
393
  timeout=self.connection_config.get_request_timeout(request_timeout),
456
394
  )
457
- print(r)
395
+ # print(r)
458
396
  if r.status_code == 502:
459
397
  return False
460
398
 
@@ -468,64 +406,155 @@ class Sandbox(SandboxSetup, SandboxApi):
468
406
 
469
407
  return True
470
408
 
409
+ @overload
410
+ def connect(
411
+ self,
412
+ timeout: Optional[int] = None,
413
+ **opts: Unpack[ApiParams],
414
+ ) -> Self:
415
+ """
416
+ Connect to a sandbox. If the sandbox is paused, it will be automatically resumed.
417
+ Sandbox must be either running or be paused.
418
+
419
+ With sandbox ID you can connect to the same sandbox from different places or environments (serverless functions, etc).
420
+
421
+ :param timeout: Timeout for the sandbox in **seconds**
422
+ For running sandboxes, the timeout will update only if the new timeout is longer than the existing one.
423
+ :return: A running sandbox instance
424
+
425
+ @example
426
+ ```python
427
+ sandbox = Sandbox.create()
428
+ sandbox.beta_pause()
429
+
430
+ # Another code block
431
+ same_sandbox = sandbox.connect()
432
+
433
+ :return: A running sandbox instance
434
+ """
435
+ ...
436
+
437
+ @overload
471
438
  @classmethod
472
439
  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
- ):
440
+ cls,
441
+ sandbox_id: str,
442
+ timeout: Optional[int] = None,
443
+ **opts: Unpack[ApiParams],
444
+ ) -> Self:
480
445
  """
481
- Connects to an existing Sandbox.
446
+ Connect to a sandbox. If the sandbox is paused, it will be automatically resumed.
447
+ Sandbox must be either running or be paused.
448
+
482
449
  With sandbox ID you can connect to the same sandbox from different places or environments (serverless functions, etc).
483
450
 
484
451
  :param sandbox_id: Sandbox ID
485
- :param api_key: Scalebox API Key to use for authentication, defaults to `SBX_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
452
+ :param timeout: Timeout for the sandbox in **seconds**.
453
+ For running sandboxes, the timeout will update only if the new timeout is longer than the existing one.
454
+ :return: A running sandbox instance
489
455
 
490
456
  @example
491
457
  ```python
492
- sandbox = Sandbox()
493
- sandbox_id = sandbox.sandbox_id
458
+ sandbox = Sandbox.create()
459
+ Sandbox.beta_pause(sandbox.sandbox_id)
494
460
 
495
461
  # Another code block
496
- same_sandbox = Sandbox.connect(sandbox_id)
462
+ same_sandbox = Sandbox.connect(sandbox.sandbox_id)
497
463
  ```
498
464
  """
499
- connection_headers = {"Authorization": "Bearer root"}
465
+ ...
500
466
 
501
- response = SandboxApi._cls_get_info(
502
- sandbox_id,
503
- api_key=api_key,
504
- domain=domain,
505
- debug=debug,
506
- proxy=proxy,
507
- )
467
+ @class_method_variant("_cls_connect")
468
+ def connect(
469
+ self,
470
+ timeout: Optional[int] = None,
471
+ **opts: Unpack[ApiParams],
472
+ ) -> Self:
473
+ """
474
+ Connect to a sandbox. If the sandbox is paused, it will be automatically resumed.
475
+ Sandbox must be either running or be paused.
508
476
 
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
- )
477
+ With sandbox ID you can connect to the same sandbox from different places or environments (serverless functions, etc).
520
478
 
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,
479
+ :param timeout: Timeout for the sandbox in **seconds**.
480
+ For running sandboxes, the timeout will update only if the new timeout is longer than the existing one.
481
+ :return: A running sandbox instance
482
+
483
+ @example
484
+ ```python
485
+ sandbox = Sandbox.create()
486
+ sandbox.beta_pause()
487
+
488
+ # Another code block
489
+ same_sandbox = sandbox.connect()
490
+ ```
491
+ """
492
+ SandboxApi._cls_connect(
493
+ sandbox_id=self.sandbox_id,
494
+ timeout=timeout,
495
+ **opts,
527
496
  )
528
497
 
498
+ return self
499
+
500
+ # @classmethod
501
+ # def connect(
502
+ # cls,
503
+ # sandbox_id: str,
504
+ # api_key: Optional[str] = None,
505
+ # domain: Optional[str] = None,
506
+ # debug: Optional[bool] = None,
507
+ # proxy: Optional[ProxyTypes] = None,
508
+ # ):
509
+ # """
510
+ # Connects to an existing Sandbox.
511
+ # With sandbox ID you can connect to the same sandbox from different places or environments (serverless functions, etc).
512
+ #
513
+ # :param sandbox_id: Sandbox ID
514
+ # :param api_key: Scalebox API Key to use for authentication, defaults to `SBX_API_KEY` environment variable
515
+ # :param proxy: Proxy to use for the request and for the **requests made to the returned sandbox**
516
+ #
517
+ # :return: sandbox instance for the existing sandbox
518
+ #
519
+ # @example
520
+ # ```python
521
+ # sandbox = Sandbox()
522
+ # sandbox_id = sandbox.sandbox_id
523
+ #
524
+ # # Another code block
525
+ # same_sandbox = Sandbox.connect(sandbox_id)
526
+ # ```
527
+ # """
528
+ # connection_headers = {"Authorization": "Bearer root"}
529
+ #
530
+ # response = SandboxApi._cls_get_info(
531
+ # sandbox_id,
532
+ # api_key=api_key,
533
+ # domain=domain,
534
+ # debug=debug,
535
+ # proxy=proxy,
536
+ # )
537
+ #
538
+ # if response._envd_access_token is not None and not isinstance(
539
+ # response._envd_access_token, Unset
540
+ # ):
541
+ # connection_headers["X-Access-Token"] = response._envd_access_token
542
+ # connection_config = ConnectionConfig(
543
+ # api_key=api_key,
544
+ # domain=domain,
545
+ # debug=debug,
546
+ # headers=connection_headers,
547
+ # proxy=proxy,
548
+ # )
549
+ #
550
+ # return cls(
551
+ # sandbox_id=sandbox_id,
552
+ # sandbox_domain=response.sandbox_domain,
553
+ # envd_version=response.envd_version,
554
+ # envd_access_token=response._envd_access_token,
555
+ # connection_config=connection_config,
556
+ # )
557
+
529
558
  def __enter__(self):
530
559
  return self
531
560
 
@@ -787,3 +816,49 @@ class Sandbox(SandboxSetup, SandboxApi):
787
816
  end=end,
788
817
  **config_dict,
789
818
  )
819
+
820
+ @overload
821
+ def beta_pause(
822
+ self,
823
+ **opts: Unpack[ApiParams],
824
+ ) -> None:
825
+ """
826
+ [BETA] This feature is in beta and may change in the future.
827
+
828
+ Pause the sandbox.
829
+ """
830
+ ...
831
+
832
+ @overload
833
+ @classmethod
834
+ def beta_pause(
835
+ cls,
836
+ sandbox_id: str,
837
+ **opts: Unpack[ApiParams],
838
+ ) -> None:
839
+ """
840
+ [BETA] This feature is in beta and may change in the future.
841
+
842
+ Pause the sandbox specified by sandbox ID.
843
+
844
+ :param sandbox_id: Sandbox ID
845
+ """
846
+ ...
847
+
848
+ @class_method_variant("_cls_pause")
849
+ def beta_pause(
850
+ self,
851
+ **opts: Unpack[ApiParams],
852
+ ) -> None:
853
+ """
854
+ [BETA] This feature is in beta and may change in the future.
855
+
856
+ Pause the sandbox.
857
+
858
+ :return: Sandbox ID that can be used to resume the sandbox
859
+ """
860
+
861
+ SandboxApi._cls_pause(
862
+ sandbox_id=self.sandbox_id,
863
+ **opts,
864
+ )