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.
- scalebox/__init__.py +1 -1
- scalebox/api/__init__.py +128 -128
- scalebox/api/client/__init__.py +8 -8
- scalebox/api/client/api/sandboxes/get_sandboxes.py +5 -3
- scalebox/api/client/api/sandboxes/get_sandboxes_sandbox_id_metrics.py +2 -2
- scalebox/api/client/api/sandboxes/post_sandboxes.py +2 -2
- scalebox/api/client/client.py +288 -288
- scalebox/api/client/models/listed_sandbox.py +11 -9
- scalebox/api/client/models/new_sandbox.py +1 -1
- scalebox/api/client/models/sandbox.py +125 -125
- scalebox/api/client/models/sandbox_state.py +1 -0
- scalebox/api/client/types.py +46 -46
- scalebox/code_interpreter/code_interpreter_async.py +370 -369
- scalebox/code_interpreter/code_interpreter_sync.py +318 -317
- scalebox/connection_config.py +92 -92
- scalebox/csx_desktop/main.py +12 -12
- scalebox/generated/api_pb2_connect.py +17 -66
- scalebox/sandbox_async/commands/command.py +307 -307
- scalebox/sandbox_async/commands/command_handle.py +187 -187
- scalebox/sandbox_async/commands/pty.py +187 -187
- scalebox/sandbox_async/filesystem/filesystem.py +557 -557
- scalebox/sandbox_async/filesystem/watch_handle.py +61 -61
- scalebox/sandbox_async/main.py +647 -646
- scalebox/sandbox_async/sandbox_api.py +365 -365
- scalebox/sandbox_async/utils.py +7 -7
- scalebox/sandbox_sync/__init__.py +2 -2
- scalebox/sandbox_sync/commands/command.py +300 -300
- scalebox/sandbox_sync/commands/command_handle.py +150 -150
- scalebox/sandbox_sync/commands/pty.py +181 -181
- scalebox/sandbox_sync/filesystem/filesystem.py +543 -543
- scalebox/sandbox_sync/filesystem/watch_handle.py +66 -66
- scalebox/sandbox_sync/main.py +789 -790
- scalebox/sandbox_sync/sandbox_api.py +356 -356
- scalebox/test/CODE_INTERPRETER_TESTS_READY.md +256 -256
- scalebox/test/README.md +164 -164
- scalebox/test/aclient.py +72 -72
- scalebox/test/code_interpreter_centext.py +21 -21
- scalebox/test/code_interpreter_centext_sync.py +21 -21
- scalebox/test/code_interpreter_test.py +1 -1
- scalebox/test/code_interpreter_test_sync.py +1 -1
- scalebox/test/run_all_validation_tests.py +334 -334
- scalebox/test/test_basic.py +78 -78
- scalebox/test/test_code_interpreter_async_comprehensive.py +2653 -2653
- scalebox/test/{test_code_interpreter_e2bsync_comprehensive.py → test_code_interpreter_execcode.py} +328 -392
- scalebox/test/test_code_interpreter_sync_comprehensive.py +3416 -3412
- scalebox/test/test_csx_desktop_examples.py +130 -0
- scalebox/test/test_sandbox_async_comprehensive.py +736 -738
- scalebox/test/test_sandbox_stress_and_edge_cases.py +778 -778
- scalebox/test/test_sandbox_sync_comprehensive.py +779 -770
- scalebox/test/test_sandbox_usage_examples.py +987 -987
- scalebox/test/testacreate.py +24 -24
- scalebox/test/testagetinfo.py +18 -18
- scalebox/test/testcodeinterpreter_async.py +508 -508
- scalebox/test/testcodeinterpreter_sync.py +239 -239
- scalebox/test/testcomputeuse.py +2 -2
- scalebox/test/testnovnc.py +12 -12
- scalebox/test/testsandbox_api.py +15 -0
- scalebox/test/testsandbox_async.py +202 -118
- scalebox/test/testsandbox_sync.py +71 -38
- scalebox/version.py +2 -2
- {scalebox_sdk-0.1.4.dist-info → scalebox_sdk-0.1.25.dist-info}/METADATA +104 -103
- {scalebox_sdk-0.1.4.dist-info → scalebox_sdk-0.1.25.dist-info}/RECORD +66 -66
- scalebox/test/test_code_interpreter_e2basync_comprehensive.py +0 -2655
- scalebox/test/test_e2b_first.py +0 -11
- {scalebox_sdk-0.1.4.dist-info → scalebox_sdk-0.1.25.dist-info}/WHEEL +0 -0
- {scalebox_sdk-0.1.4.dist-info → scalebox_sdk-0.1.25.dist-info}/entry_points.txt +0 -0
- {scalebox_sdk-0.1.4.dist-info → scalebox_sdk-0.1.25.dist-info}/licenses/LICENSE +0 -0
- {scalebox_sdk-0.1.4.dist-info → scalebox_sdk-0.1.25.dist-info}/top_level.txt +0 -0
scalebox/connection_config.py
CHANGED
|
@@ -1,92 +1,92 @@
|
|
|
1
|
-
import os
|
|
2
|
-
from typing import Dict, Literal, Optional
|
|
3
|
-
|
|
4
|
-
from httpx._types import ProxyTypes
|
|
5
|
-
|
|
6
|
-
# from .api.metadata import package_version
|
|
7
|
-
|
|
8
|
-
REQUEST_TIMEOUT: float = 30.0 # 30 seconds
|
|
9
|
-
|
|
10
|
-
KEEPALIVE_PING_INTERVAL_SEC = 50 # 50 seconds
|
|
11
|
-
KEEPALIVE_PING_HEADER = "Keepalive-Ping-Interval"
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
class ConnectionConfig:
|
|
15
|
-
"""
|
|
16
|
-
Configuration for the connection to the API.
|
|
17
|
-
"""
|
|
18
|
-
|
|
19
|
-
@staticmethod
|
|
20
|
-
def _domain():
|
|
21
|
-
return os.getenv("
|
|
22
|
-
|
|
23
|
-
@staticmethod
|
|
24
|
-
def _debug():
|
|
25
|
-
return os.getenv("
|
|
26
|
-
|
|
27
|
-
@staticmethod
|
|
28
|
-
def _api_key():
|
|
29
|
-
return os.getenv("
|
|
30
|
-
|
|
31
|
-
@staticmethod
|
|
32
|
-
def _access_token():
|
|
33
|
-
return os.getenv("
|
|
34
|
-
|
|
35
|
-
def __init__(
|
|
36
|
-
self,
|
|
37
|
-
domain: Optional[str] = None,
|
|
38
|
-
debug: Optional[bool] = None,
|
|
39
|
-
api_key: Optional[str] = None,
|
|
40
|
-
access_token: Optional[str] = None,
|
|
41
|
-
request_timeout: Optional[float] = None,
|
|
42
|
-
headers: Optional[Dict[str, str]] = None,
|
|
43
|
-
proxy: Optional[ProxyTypes] = None,
|
|
44
|
-
):
|
|
45
|
-
self.domain = domain or ConnectionConfig._domain()
|
|
46
|
-
self.debug = debug or ConnectionConfig._debug()
|
|
47
|
-
self.api_key = api_key or ConnectionConfig._api_key()
|
|
48
|
-
self.access_token = access_token or ConnectionConfig._access_token()
|
|
49
|
-
self.headers = headers or {}
|
|
50
|
-
# self.headers["User-Agent"] = f"csx-python-sdk/{package_version}"
|
|
51
|
-
|
|
52
|
-
self.proxy = proxy
|
|
53
|
-
|
|
54
|
-
self.request_timeout = ConnectionConfig._get_request_timeout(
|
|
55
|
-
REQUEST_TIMEOUT,
|
|
56
|
-
request_timeout,
|
|
57
|
-
)
|
|
58
|
-
|
|
59
|
-
if request_timeout == 0:
|
|
60
|
-
self.request_timeout = None
|
|
61
|
-
elif request_timeout is not None:
|
|
62
|
-
self.request_timeout = request_timeout
|
|
63
|
-
else:
|
|
64
|
-
self.request_timeout = REQUEST_TIMEOUT
|
|
65
|
-
|
|
66
|
-
self.api_url = f"https://{self.domain}"
|
|
67
|
-
|
|
68
|
-
@staticmethod
|
|
69
|
-
def _get_request_timeout(
|
|
70
|
-
default_timeout: Optional[float],
|
|
71
|
-
request_timeout: Optional[float],
|
|
72
|
-
):
|
|
73
|
-
if request_timeout == 0:
|
|
74
|
-
return None
|
|
75
|
-
elif request_timeout is not None:
|
|
76
|
-
return request_timeout
|
|
77
|
-
else:
|
|
78
|
-
return default_timeout
|
|
79
|
-
|
|
80
|
-
def get_request_timeout(self, request_timeout: Optional[float] = None):
|
|
81
|
-
return self._get_request_timeout(self.request_timeout, request_timeout)
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
Username = Literal["root", "user"]
|
|
85
|
-
"""
|
|
86
|
-
User used for the operation in the sandbox.
|
|
87
|
-
"""
|
|
88
|
-
|
|
89
|
-
default_username: Username = "user"
|
|
90
|
-
"""
|
|
91
|
-
Default user used for the operation in the sandbox.
|
|
92
|
-
"""
|
|
1
|
+
import os
|
|
2
|
+
from typing import Dict, Literal, Optional
|
|
3
|
+
|
|
4
|
+
from httpx._types import ProxyTypes
|
|
5
|
+
|
|
6
|
+
# from .api.metadata import package_version
|
|
7
|
+
|
|
8
|
+
REQUEST_TIMEOUT: float = 30.0 # 30 seconds
|
|
9
|
+
|
|
10
|
+
KEEPALIVE_PING_INTERVAL_SEC = 50 # 50 seconds
|
|
11
|
+
KEEPALIVE_PING_HEADER = "Keepalive-Ping-Interval"
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ConnectionConfig:
|
|
15
|
+
"""
|
|
16
|
+
Configuration for the connection to the API.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
@staticmethod
|
|
20
|
+
def _domain():
|
|
21
|
+
return os.getenv("SBX_DOMAIN") or "api.scalebox.dev/v1"
|
|
22
|
+
|
|
23
|
+
@staticmethod
|
|
24
|
+
def _debug():
|
|
25
|
+
return os.getenv("SBX_DEBUG", "false").lower() == "true"
|
|
26
|
+
|
|
27
|
+
@staticmethod
|
|
28
|
+
def _api_key():
|
|
29
|
+
return os.getenv("SBX_API_KEY")
|
|
30
|
+
|
|
31
|
+
@staticmethod
|
|
32
|
+
def _access_token():
|
|
33
|
+
return os.getenv("SBX_ACCESS_TOKEN")
|
|
34
|
+
|
|
35
|
+
def __init__(
|
|
36
|
+
self,
|
|
37
|
+
domain: Optional[str] = None,
|
|
38
|
+
debug: Optional[bool] = None,
|
|
39
|
+
api_key: Optional[str] = None,
|
|
40
|
+
access_token: Optional[str] = None,
|
|
41
|
+
request_timeout: Optional[float] = None,
|
|
42
|
+
headers: Optional[Dict[str, str]] = None,
|
|
43
|
+
proxy: Optional[ProxyTypes] = None,
|
|
44
|
+
):
|
|
45
|
+
self.domain = domain or ConnectionConfig._domain()
|
|
46
|
+
self.debug = debug or ConnectionConfig._debug()
|
|
47
|
+
self.api_key = api_key or ConnectionConfig._api_key()
|
|
48
|
+
self.access_token = access_token or ConnectionConfig._access_token()
|
|
49
|
+
self.headers = headers or {}
|
|
50
|
+
# self.headers["User-Agent"] = f"csx-python-sdk/{package_version}"
|
|
51
|
+
|
|
52
|
+
self.proxy = proxy
|
|
53
|
+
|
|
54
|
+
self.request_timeout = ConnectionConfig._get_request_timeout(
|
|
55
|
+
REQUEST_TIMEOUT,
|
|
56
|
+
request_timeout,
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
if request_timeout == 0:
|
|
60
|
+
self.request_timeout = None
|
|
61
|
+
elif request_timeout is not None:
|
|
62
|
+
self.request_timeout = request_timeout
|
|
63
|
+
else:
|
|
64
|
+
self.request_timeout = REQUEST_TIMEOUT
|
|
65
|
+
|
|
66
|
+
self.api_url = f"https://{self.domain}"
|
|
67
|
+
|
|
68
|
+
@staticmethod
|
|
69
|
+
def _get_request_timeout(
|
|
70
|
+
default_timeout: Optional[float],
|
|
71
|
+
request_timeout: Optional[float],
|
|
72
|
+
):
|
|
73
|
+
if request_timeout == 0:
|
|
74
|
+
return None
|
|
75
|
+
elif request_timeout is not None:
|
|
76
|
+
return request_timeout
|
|
77
|
+
else:
|
|
78
|
+
return default_timeout
|
|
79
|
+
|
|
80
|
+
def get_request_timeout(self, request_timeout: Optional[float] = None):
|
|
81
|
+
return self._get_request_timeout(self.request_timeout, request_timeout)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
Username = Literal["root", "user"]
|
|
85
|
+
"""
|
|
86
|
+
User used for the operation in the sandbox.
|
|
87
|
+
"""
|
|
88
|
+
|
|
89
|
+
default_username: Username = "user"
|
|
90
|
+
"""
|
|
91
|
+
Default user used for the operation in the sandbox.
|
|
92
|
+
"""
|
scalebox/csx_desktop/main.py
CHANGED
|
@@ -228,10 +228,10 @@ class Sandbox(SandboxBase):
|
|
|
228
228
|
# :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
|
|
229
229
|
# :param metadata: Custom metadata for the sandbox
|
|
230
230
|
# :param envs: Custom environment variables for the sandbox
|
|
231
|
-
# :param api_key:
|
|
232
|
-
# :param domain:
|
|
233
|
-
# :param debug: If True, the sandbox will be created in debug mode, defaults to `
|
|
234
|
-
# :param sandbox_id: Sandbox ID to connect to, defaults to `
|
|
231
|
+
# :param api_key: API Key to use for authentication, defaults to `SBX_API_KEY` environment variable
|
|
232
|
+
# :param domain: Domain to use for authentication, defaults to `SBX_DOMAIN` environment variable
|
|
233
|
+
# :param debug: If True, the sandbox will be created in debug mode, defaults to `SBX_DEBUG` environment variable
|
|
234
|
+
# :param sandbox_id: Sandbox ID to connect to, defaults to `SBX_SANDBOX_ID` environment variable
|
|
235
235
|
# :param request_timeout: Timeout for the request in **seconds**
|
|
236
236
|
# :param proxy: Proxy to use for the request and for the requests made to the returned sandbox
|
|
237
237
|
#
|
|
@@ -307,16 +307,16 @@ class Sandbox(SandboxBase):
|
|
|
307
307
|
proxy: Optional[ProxyTypes] = None,
|
|
308
308
|
) -> "Sandbox":
|
|
309
309
|
"""
|
|
310
|
-
|
|
310
|
+
Synchronously create or connect to a desktop sandbox.
|
|
311
311
|
|
|
312
|
-
|
|
312
|
+
Parameters have the same meaning as the base class. Xvfb + xfce4 will be automatically started on first creation.
|
|
313
313
|
"""
|
|
314
314
|
display = display or ":0"
|
|
315
315
|
if envs is None:
|
|
316
316
|
envs = {}
|
|
317
317
|
envs["DISPLAY"] = display
|
|
318
318
|
|
|
319
|
-
# 1.
|
|
319
|
+
# 1. Let the parent class factory actually create / reuse
|
|
320
320
|
base = SandboxBase.create(
|
|
321
321
|
template=template or cls.default_template,
|
|
322
322
|
timeout=timeout,
|
|
@@ -330,27 +330,27 @@ class Sandbox(SandboxBase):
|
|
|
330
330
|
proxy=proxy,
|
|
331
331
|
)
|
|
332
332
|
|
|
333
|
-
# 2.
|
|
333
|
+
# 2. Dynamically upgrade type to Sandbox
|
|
334
334
|
base.__class__ = cls
|
|
335
335
|
base._display = display
|
|
336
336
|
base._last_xfce4_pid = None
|
|
337
337
|
|
|
338
|
-
# 3.
|
|
338
|
+
# 3. Only start desktop on first creation
|
|
339
339
|
if not sandbox_id:
|
|
340
340
|
base._start_desktop(resolution, dpi)
|
|
341
341
|
else:
|
|
342
|
-
#
|
|
342
|
+
# Connect to existing sandbox, only initialize VNC
|
|
343
343
|
base.__vnc_server = _VNCServer(base)
|
|
344
344
|
|
|
345
345
|
return base
|
|
346
346
|
|
|
347
|
-
# ======================
|
|
347
|
+
# ====================== Subclass Private Methods ======================
|
|
348
348
|
def _start_desktop(
|
|
349
349
|
self,
|
|
350
350
|
resolution: Optional[Tuple[int, int]] = None,
|
|
351
351
|
dpi: Optional[int] = None,
|
|
352
352
|
) -> None:
|
|
353
|
-
"""
|
|
353
|
+
"""Start Xvfb and wait for success, then start xfce4 + VNC."""
|
|
354
354
|
width, height = resolution or (1024, 768)
|
|
355
355
|
self.commands.run(
|
|
356
356
|
f"Xvfb {self._display} -ac -screen 0 {width}x{height}x24 "
|
|
@@ -8,69 +8,20 @@ from collections.abc import AsyncIterator, Iterable, Iterator
|
|
|
8
8
|
|
|
9
9
|
import aiohttp
|
|
10
10
|
import urllib3
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
from connectrpc.streams import AsyncStreamOutput, StreamInput, StreamOutput
|
|
26
|
-
from connectrpc.unary import ClientStreamingOutput, UnaryOutput
|
|
27
|
-
except ImportError:
|
|
28
|
-
# connectrpc not available, define dummy classes
|
|
29
|
-
class AsyncConnectClient:
|
|
30
|
-
pass
|
|
31
|
-
|
|
32
|
-
class ConnectProtocolError(Exception):
|
|
33
|
-
pass
|
|
34
|
-
|
|
35
|
-
class ConnectProtocol:
|
|
36
|
-
CONNECT_PROTOBUF = "connect_protobuf"
|
|
37
|
-
|
|
38
|
-
class ConnectClient:
|
|
39
|
-
pass
|
|
40
|
-
|
|
41
|
-
class HeaderInput:
|
|
42
|
-
pass
|
|
43
|
-
|
|
44
|
-
class ClientRequest:
|
|
45
|
-
pass
|
|
46
|
-
|
|
47
|
-
class ClientStream:
|
|
48
|
-
pass
|
|
49
|
-
|
|
50
|
-
class ServerResponse:
|
|
51
|
-
pass
|
|
52
|
-
|
|
53
|
-
class ServerStream:
|
|
54
|
-
pass
|
|
55
|
-
|
|
56
|
-
class ConnectWSGI:
|
|
57
|
-
pass
|
|
58
|
-
|
|
59
|
-
class AsyncStreamOutput:
|
|
60
|
-
pass
|
|
61
|
-
|
|
62
|
-
class StreamInput:
|
|
63
|
-
pass
|
|
64
|
-
|
|
65
|
-
class StreamOutput:
|
|
66
|
-
pass
|
|
67
|
-
|
|
68
|
-
class ClientStreamingOutput:
|
|
69
|
-
pass
|
|
70
|
-
|
|
71
|
-
class UnaryOutput:
|
|
72
|
-
pass
|
|
73
|
-
|
|
11
|
+
from connectrpc.client_async import AsyncConnectClient
|
|
12
|
+
from connectrpc.client_connect import ConnectProtocolError
|
|
13
|
+
from connectrpc.client_protocol import ConnectProtocol
|
|
14
|
+
from connectrpc.client_sync import ConnectClient
|
|
15
|
+
from connectrpc.headers import HeaderInput
|
|
16
|
+
from connectrpc.server import (
|
|
17
|
+
ClientRequest,
|
|
18
|
+
ClientStream,
|
|
19
|
+
ServerResponse,
|
|
20
|
+
ServerStream,
|
|
21
|
+
)
|
|
22
|
+
from connectrpc.server_sync import ConnectWSGI
|
|
23
|
+
from connectrpc.streams import AsyncStreamOutput, StreamInput, StreamOutput
|
|
24
|
+
from connectrpc.unary import ClientStreamingOutput, UnaryOutput
|
|
74
25
|
|
|
75
26
|
if typing.TYPE_CHECKING:
|
|
76
27
|
# wsgiref.types was added in Python 3.11.
|
|
@@ -739,7 +690,7 @@ class ProcessClient:
|
|
|
739
690
|
extra_headers: HeaderInput | None = None,
|
|
740
691
|
timeout_seconds: float | None = None,
|
|
741
692
|
) -> Iterator[api_pb2.ConnectResponse]:
|
|
742
|
-
stream_output = self.call_connect(req, extra_headers)
|
|
693
|
+
stream_output = self.call_connect(req, extra_headers,timeout_seconds)
|
|
743
694
|
err = stream_output.error()
|
|
744
695
|
if err is not None:
|
|
745
696
|
raise err
|
|
@@ -774,7 +725,7 @@ class ProcessClient:
|
|
|
774
725
|
extra_headers: HeaderInput | None = None,
|
|
775
726
|
timeout_seconds: float | None = None,
|
|
776
727
|
) -> Iterator[api_pb2.StartResponse]:
|
|
777
|
-
stream_output = self.call_start(req, extra_headers)
|
|
728
|
+
stream_output = self.call_start(req, extra_headers,timeout_seconds)
|
|
778
729
|
err = stream_output.error()
|
|
779
730
|
if err is not None:
|
|
780
731
|
raise err
|
|
@@ -992,7 +943,7 @@ class AsyncProcessClient:
|
|
|
992
943
|
extra_headers: HeaderInput | None = None,
|
|
993
944
|
timeout_seconds: float | None = None,
|
|
994
945
|
) -> AsyncIterator[api_pb2.StartResponse]:
|
|
995
|
-
stream_output = await self.call_start(req, extra_headers)
|
|
946
|
+
stream_output = await self.call_start(req, extra_headers,timeout_seconds)
|
|
996
947
|
err = stream_output.error()
|
|
997
948
|
if err is not None:
|
|
998
949
|
raise err
|