scalebox-sdk 0.1.25__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.
- scalebox/__init__.py +2 -2
- scalebox/api/__init__.py +3 -1
- scalebox/api/client/api/sandboxes/post_sandboxes_sandbox_id_connect.py +193 -0
- scalebox/api/client/models/connect_sandbox.py +59 -0
- scalebox/api/client/models/error.py +2 -2
- scalebox/api/client/models/listed_sandbox.py +19 -1
- scalebox/api/client/models/new_sandbox.py +10 -0
- scalebox/api/client/models/sandbox.py +13 -0
- scalebox/api/client/models/sandbox_detail.py +24 -0
- scalebox/cli.py +125 -125
- scalebox/client/aclient.py +57 -57
- scalebox/client/client.py +102 -102
- scalebox/code_interpreter/__init__.py +12 -12
- scalebox/code_interpreter/charts.py +230 -230
- scalebox/code_interpreter/constants.py +3 -3
- scalebox/code_interpreter/exceptions.py +13 -13
- scalebox/code_interpreter/models.py +485 -485
- scalebox/connection_config.py +34 -1
- scalebox/csx_connect/__init__.py +1 -1
- scalebox/csx_connect/client.py +485 -485
- scalebox/csx_desktop/main.py +651 -651
- scalebox/exceptions.py +83 -83
- scalebox/generated/api.py +61 -61
- scalebox/generated/api_pb2.py +203 -203
- scalebox/generated/api_pb2.pyi +956 -956
- scalebox/generated/api_pb2_connect.py +1407 -1407
- scalebox/generated/rpc.py +50 -50
- scalebox/sandbox/main.py +146 -139
- scalebox/sandbox/sandbox_api.py +105 -91
- scalebox/sandbox/signature.py +40 -40
- scalebox/sandbox/utils.py +34 -34
- scalebox/sandbox_async/main.py +226 -44
- scalebox/sandbox_async/sandbox_api.py +124 -3
- scalebox/sandbox_sync/main.py +205 -130
- scalebox/sandbox_sync/sandbox_api.py +119 -3
- scalebox/test/CODE_INTERPRETER_TESTS_READY.md +323 -323
- scalebox/test/README.md +329 -329
- scalebox/test/bedrock_openai_adapter.py +67 -0
- scalebox/test/code_interpreter_test.py +34 -34
- scalebox/test/code_interpreter_test_sync.py +34 -34
- scalebox/test/run_stress_code_interpreter_sync.py +166 -0
- scalebox/test/simple_upload_example.py +123 -0
- scalebox/test/stabitiy_test.py +310 -0
- scalebox/test/test_browser_use.py +25 -0
- scalebox/test/test_browser_use_scalebox.py +61 -0
- scalebox/test/test_code_interpreter_sync_comprehensive.py +115 -65
- scalebox/test/test_connect_pause_async.py +277 -0
- scalebox/test/test_connect_pause_sync.py +267 -0
- scalebox/test/test_desktop_sandbox_sf.py +117 -0
- scalebox/test/test_download_url.py +49 -0
- scalebox/test/test_sandbox_async_comprehensive.py +1 -1
- scalebox/test/test_sandbox_object_storage_example.py +146 -0
- scalebox/test/test_sandbox_object_storage_example_async.py +156 -0
- scalebox/test/test_sf.py +137 -0
- scalebox/test/test_watch_dir_async.py +56 -0
- scalebox/test/testacreate.py +1 -1
- scalebox/test/testagetinfo.py +1 -1
- scalebox/test/testcomputeuse.py +243 -243
- scalebox/test/testsandbox_api.py +1 -3
- scalebox/test/testsandbox_sync.py +1 -1
- scalebox/test/upload_100mb_example.py +355 -0
- scalebox/utils/httpcoreclient.py +297 -297
- scalebox/utils/httpxclient.py +403 -403
- scalebox/version.py +2 -2
- {scalebox_sdk-0.1.25.dist-info → scalebox_sdk-1.0.1.dist-info}/METADATA +1 -1
- {scalebox_sdk-0.1.25.dist-info → scalebox_sdk-1.0.1.dist-info}/RECORD +70 -53
- {scalebox_sdk-0.1.25.dist-info → scalebox_sdk-1.0.1.dist-info}/WHEEL +1 -1
- {scalebox_sdk-0.1.25.dist-info → scalebox_sdk-1.0.1.dist-info}/entry_points.txt +0 -0
- {scalebox_sdk-0.1.25.dist-info → scalebox_sdk-1.0.1.dist-info}/licenses/LICENSE +0 -0
- {scalebox_sdk-0.1.25.dist-info → scalebox_sdk-1.0.1.dist-info}/top_level.txt +0 -0
scalebox/generated/rpc.py
CHANGED
|
@@ -1,50 +1,50 @@
|
|
|
1
|
-
import base64
|
|
2
|
-
from typing import Optional
|
|
3
|
-
|
|
4
|
-
from ..connection_config import Username, default_username
|
|
5
|
-
from ..csx_connect.client import Code, ConnectException
|
|
6
|
-
from ..exceptions import (
|
|
7
|
-
AuthenticationException,
|
|
8
|
-
InvalidArgumentException,
|
|
9
|
-
NotFoundException,
|
|
10
|
-
RateLimitException,
|
|
11
|
-
SandboxException,
|
|
12
|
-
TimeoutException,
|
|
13
|
-
sandbox_timeout_exception,
|
|
14
|
-
)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def handle_rpc_exception(e: Exception):
|
|
18
|
-
if isinstance(e, ConnectException):
|
|
19
|
-
if e.status == Code.invalid_argument:
|
|
20
|
-
return InvalidArgumentException(e.message)
|
|
21
|
-
elif e.status == Code.unauthenticated:
|
|
22
|
-
return AuthenticationException(e.message)
|
|
23
|
-
elif e.status == Code.not_found:
|
|
24
|
-
return NotFoundException(e.message)
|
|
25
|
-
elif e.status == Code.unavailable:
|
|
26
|
-
return sandbox_timeout_exception(e.message)
|
|
27
|
-
elif e.status == Code.resource_exhausted:
|
|
28
|
-
return RateLimitException(
|
|
29
|
-
f"{e.message}: Rate limit exceeded, please try again later."
|
|
30
|
-
)
|
|
31
|
-
elif e.status == Code.canceled:
|
|
32
|
-
return TimeoutException(
|
|
33
|
-
f"{e.message}: This error is likely due to exceeding 'request_timeout'. You can pass the request timeout value as an option when making the request."
|
|
34
|
-
)
|
|
35
|
-
elif e.status == Code.deadline_exceeded:
|
|
36
|
-
return TimeoutException(
|
|
37
|
-
f"{e.message}: This error is likely due to exceeding 'timeout' — the total time a long running request (like process or directory watch) can be active. It can be modified by passing 'timeout' when making the request. Use '0' to disable the timeout."
|
|
38
|
-
)
|
|
39
|
-
else:
|
|
40
|
-
return SandboxException(f"{e.status}: {e.message}")
|
|
41
|
-
else:
|
|
42
|
-
return e
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
def authentication_header(user: Optional[Username] = None):
|
|
46
|
-
value = f"{user if user is not None else default_username}:"
|
|
47
|
-
|
|
48
|
-
encoded = base64.b64encode(value.encode("utf-8")).decode("utf-8")
|
|
49
|
-
|
|
50
|
-
return {"Authorization": f"Basic {encoded}"}
|
|
1
|
+
import base64
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
from ..connection_config import Username, default_username
|
|
5
|
+
from ..csx_connect.client import Code, ConnectException
|
|
6
|
+
from ..exceptions import (
|
|
7
|
+
AuthenticationException,
|
|
8
|
+
InvalidArgumentException,
|
|
9
|
+
NotFoundException,
|
|
10
|
+
RateLimitException,
|
|
11
|
+
SandboxException,
|
|
12
|
+
TimeoutException,
|
|
13
|
+
sandbox_timeout_exception,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def handle_rpc_exception(e: Exception):
|
|
18
|
+
if isinstance(e, ConnectException):
|
|
19
|
+
if e.status == Code.invalid_argument:
|
|
20
|
+
return InvalidArgumentException(e.message)
|
|
21
|
+
elif e.status == Code.unauthenticated:
|
|
22
|
+
return AuthenticationException(e.message)
|
|
23
|
+
elif e.status == Code.not_found:
|
|
24
|
+
return NotFoundException(e.message)
|
|
25
|
+
elif e.status == Code.unavailable:
|
|
26
|
+
return sandbox_timeout_exception(e.message)
|
|
27
|
+
elif e.status == Code.resource_exhausted:
|
|
28
|
+
return RateLimitException(
|
|
29
|
+
f"{e.message}: Rate limit exceeded, please try again later."
|
|
30
|
+
)
|
|
31
|
+
elif e.status == Code.canceled:
|
|
32
|
+
return TimeoutException(
|
|
33
|
+
f"{e.message}: This error is likely due to exceeding 'request_timeout'. You can pass the request timeout value as an option when making the request."
|
|
34
|
+
)
|
|
35
|
+
elif e.status == Code.deadline_exceeded:
|
|
36
|
+
return TimeoutException(
|
|
37
|
+
f"{e.message}: This error is likely due to exceeding 'timeout' — the total time a long running request (like process or directory watch) can be active. It can be modified by passing 'timeout' when making the request. Use '0' to disable the timeout."
|
|
38
|
+
)
|
|
39
|
+
else:
|
|
40
|
+
return SandboxException(f"{e.status}: {e.message}")
|
|
41
|
+
else:
|
|
42
|
+
return e
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def authentication_header(user: Optional[Username] = None):
|
|
46
|
+
value = f"{user if user is not None else default_username}:"
|
|
47
|
+
|
|
48
|
+
encoded = base64.b64encode(value.encode("utf-8")).decode("utf-8")
|
|
49
|
+
|
|
50
|
+
return {"Authorization": f"Basic {encoded}"}
|
scalebox/sandbox/main.py
CHANGED
|
@@ -1,139 +1,146 @@
|
|
|
1
|
-
import urllib.parse
|
|
2
|
-
from abc import ABC, abstractmethod
|
|
3
|
-
from typing import Optional
|
|
4
|
-
|
|
5
|
-
from httpx import Limits
|
|
6
|
-
|
|
7
|
-
from ..connection_config import ConnectionConfig
|
|
8
|
-
from ..generated.api import
|
|
9
|
-
from .signature import get_signature
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class SandboxSetup(ABC):
|
|
13
|
-
_limits = Limits(
|
|
14
|
-
max_keepalive_connections=40,
|
|
15
|
-
max_connections=40,
|
|
16
|
-
keepalive_expiry=300,
|
|
17
|
-
)
|
|
18
|
-
|
|
19
|
-
envd_port = 443
|
|
20
|
-
|
|
21
|
-
default_sandbox_timeout = 300
|
|
22
|
-
default_template = "base"
|
|
23
|
-
|
|
24
|
-
@property
|
|
25
|
-
@abstractmethod
|
|
26
|
-
def connection_config(self) -> ConnectionConfig: ...
|
|
27
|
-
|
|
28
|
-
@property
|
|
29
|
-
@abstractmethod
|
|
30
|
-
def _envd_access_token(self) -> Optional[str]: ...
|
|
31
|
-
|
|
32
|
-
@property
|
|
33
|
-
@abstractmethod
|
|
34
|
-
def envd_api_url(self) -> str: ...
|
|
35
|
-
|
|
36
|
-
@property
|
|
37
|
-
@abstractmethod
|
|
38
|
-
def sandbox_id(self) -> str: ...
|
|
39
|
-
|
|
40
|
-
@property
|
|
41
|
-
@abstractmethod
|
|
42
|
-
def sandbox_domain(self) -> str: ...
|
|
43
|
-
|
|
44
|
-
def _file_url(
|
|
45
|
-
self,
|
|
46
|
-
path: Optional[str] = None,
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
query = {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
query
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
:
|
|
81
|
-
:
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
1
|
+
import urllib.parse
|
|
2
|
+
from abc import ABC, abstractmethod
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
from httpx import Limits
|
|
6
|
+
|
|
7
|
+
from ..connection_config import ConnectionConfig
|
|
8
|
+
from ..generated.api import ENVD_API_DOWNLOAD_FILES_ROUTE,ENVD_API_UPLOAD_FILES_ROUTE
|
|
9
|
+
from .signature import get_signature, Operation
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class SandboxSetup(ABC):
|
|
13
|
+
_limits = Limits(
|
|
14
|
+
max_keepalive_connections=40,
|
|
15
|
+
max_connections=40,
|
|
16
|
+
keepalive_expiry=300,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
envd_port = 443
|
|
20
|
+
|
|
21
|
+
default_sandbox_timeout = 300
|
|
22
|
+
default_template = "base"
|
|
23
|
+
|
|
24
|
+
@property
|
|
25
|
+
@abstractmethod
|
|
26
|
+
def connection_config(self) -> ConnectionConfig: ...
|
|
27
|
+
|
|
28
|
+
@property
|
|
29
|
+
@abstractmethod
|
|
30
|
+
def _envd_access_token(self) -> Optional[str]: ...
|
|
31
|
+
|
|
32
|
+
@property
|
|
33
|
+
@abstractmethod
|
|
34
|
+
def envd_api_url(self) -> str: ...
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
@abstractmethod
|
|
38
|
+
def sandbox_id(self) -> str: ...
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
@abstractmethod
|
|
42
|
+
def sandbox_domain(self) -> str: ...
|
|
43
|
+
|
|
44
|
+
def _file_url(
|
|
45
|
+
self,
|
|
46
|
+
path: Optional[str] = None,
|
|
47
|
+
operation: Operation = "read",
|
|
48
|
+
user: str = "root",
|
|
49
|
+
signature: Optional[str] = None,
|
|
50
|
+
signature_expiration: Optional[int] = None,
|
|
51
|
+
) -> str:
|
|
52
|
+
query = {}
|
|
53
|
+
url = urllib.parse.urljoin(self.envd_api_url, ENVD_API_DOWNLOAD_FILES_ROUTE)
|
|
54
|
+
if operation == "write":
|
|
55
|
+
url = urllib.parse.urljoin(self.envd_api_url, ENVD_API_UPLOAD_FILES_ROUTE)
|
|
56
|
+
query = {**query,"path": path}
|
|
57
|
+
else:
|
|
58
|
+
url = f"{url}/{path.lstrip('/')}"
|
|
59
|
+
query = {**query, "username": user}
|
|
60
|
+
|
|
61
|
+
if signature:
|
|
62
|
+
query["signature"] = signature
|
|
63
|
+
|
|
64
|
+
if signature_expiration:
|
|
65
|
+
if signature is None:
|
|
66
|
+
raise ValueError("signature_expiration requires signature to be set")
|
|
67
|
+
query["signature_expiration"] = str(signature_expiration)
|
|
68
|
+
|
|
69
|
+
params = urllib.parse.urlencode(
|
|
70
|
+
query,
|
|
71
|
+
quote_via=urllib.parse.quote,
|
|
72
|
+
)
|
|
73
|
+
url = urllib.parse.urljoin(url, f"?{params}")
|
|
74
|
+
|
|
75
|
+
return url
|
|
76
|
+
|
|
77
|
+
def download_url(
|
|
78
|
+
self,
|
|
79
|
+
path: str,
|
|
80
|
+
user: str = "root",
|
|
81
|
+
use_signature_expiration: Optional[int] = None,
|
|
82
|
+
) -> str:
|
|
83
|
+
"""
|
|
84
|
+
Get the URL to download a file from the sandbox.
|
|
85
|
+
|
|
86
|
+
:param path: Path to the file to download
|
|
87
|
+
:param user: User to upload the file as
|
|
88
|
+
:param use_signature_expiration: Expiration time for the signed URL in seconds
|
|
89
|
+
|
|
90
|
+
:return: URL for downloading file
|
|
91
|
+
"""
|
|
92
|
+
|
|
93
|
+
use_signature = self._envd_access_token is not None
|
|
94
|
+
if use_signature:
|
|
95
|
+
signature = get_signature(
|
|
96
|
+
path, "read", user, self._envd_access_token, use_signature_expiration
|
|
97
|
+
)
|
|
98
|
+
return self._file_url(
|
|
99
|
+
path,"read", user, signature["signature"], signature["expiration"]
|
|
100
|
+
)
|
|
101
|
+
else:
|
|
102
|
+
return self._file_url(path)
|
|
103
|
+
|
|
104
|
+
def upload_url(
|
|
105
|
+
self,
|
|
106
|
+
path: Optional[str] = None,
|
|
107
|
+
user: str = "root",
|
|
108
|
+
use_signature_expiration: Optional[int] = None,
|
|
109
|
+
) -> str:
|
|
110
|
+
"""
|
|
111
|
+
Get the URL to upload a file to the sandbox.
|
|
112
|
+
|
|
113
|
+
You have to send a POST request to this URL with the file as multipart/form-data.
|
|
114
|
+
|
|
115
|
+
:param path: Path to the file to upload
|
|
116
|
+
:param user: User to upload the file as
|
|
117
|
+
:param use_signature_expiration: Expiration time for the signed URL in seconds
|
|
118
|
+
|
|
119
|
+
:return: URL for uploading file
|
|
120
|
+
"""
|
|
121
|
+
|
|
122
|
+
use_signature = self._envd_access_token is not None
|
|
123
|
+
if use_signature:
|
|
124
|
+
signature = get_signature(
|
|
125
|
+
path, "write", user, self._envd_access_token, use_signature_expiration
|
|
126
|
+
)
|
|
127
|
+
return self._file_url(
|
|
128
|
+
path,"write", user, signature["signature"], signature["expiration"]
|
|
129
|
+
)
|
|
130
|
+
else:
|
|
131
|
+
return self._file_url(path)
|
|
132
|
+
|
|
133
|
+
def get_host(self, port: int) -> str:
|
|
134
|
+
"""
|
|
135
|
+
Get the host address to connect to the sandbox.
|
|
136
|
+
You can then use this address to connect to the sandbox port from outside the sandbox via HTTP or WebSocket.
|
|
137
|
+
|
|
138
|
+
:param port: Port to connect to
|
|
139
|
+
|
|
140
|
+
:return: Host address to connect to
|
|
141
|
+
"""
|
|
142
|
+
if self.connection_config.debug:
|
|
143
|
+
debug_host = self.connection_config.debug_host
|
|
144
|
+
return f"{debug_host}:{port}"
|
|
145
|
+
return f"{self.sandbox_domain}"
|
|
146
|
+
# return f"{port}-{self.sandbox_id}.{self.sandbox_domain}"
|
scalebox/sandbox/sandbox_api.py
CHANGED
|
@@ -1,91 +1,105 @@
|
|
|
1
|
-
from abc import ABC
|
|
2
|
-
from dataclasses import dataclass
|
|
3
|
-
from datetime import datetime
|
|
4
|
-
from typing import Dict, Optional
|
|
5
|
-
|
|
6
|
-
from httpx import Limits
|
|
7
|
-
|
|
8
|
-
from ..api.client.models import SandboxState
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
@dataclass
|
|
12
|
-
class SandboxInfo:
|
|
13
|
-
"""Information about a sandbox."""
|
|
14
|
-
|
|
15
|
-
sandbox_id: str
|
|
16
|
-
"""Sandbox ID."""
|
|
17
|
-
sandbox_domain: Optional[str]
|
|
18
|
-
"""Domain where the sandbox is hosted."""
|
|
19
|
-
template_id: str
|
|
20
|
-
"""Template ID."""
|
|
21
|
-
name: Optional[str]
|
|
22
|
-
"""Template name."""
|
|
23
|
-
metadata: Dict[str, str]
|
|
24
|
-
"""Saved sandbox metadata."""
|
|
25
|
-
started_at: datetime
|
|
26
|
-
"""Sandbox start time."""
|
|
27
|
-
|
|
28
|
-
"""Sandbox
|
|
29
|
-
|
|
30
|
-
"""
|
|
31
|
-
|
|
32
|
-
"""
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
"""Sandbox
|
|
47
|
-
|
|
48
|
-
"""
|
|
49
|
-
|
|
50
|
-
"""
|
|
51
|
-
|
|
52
|
-
"""
|
|
53
|
-
|
|
54
|
-
"""Sandbox
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
"""
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
"""
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
"""
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
"""
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
1
|
+
from abc import ABC
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from typing import Dict, Optional
|
|
5
|
+
|
|
6
|
+
from httpx import Limits
|
|
7
|
+
|
|
8
|
+
from ..api.client.models import SandboxState
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclass
|
|
12
|
+
class SandboxInfo:
|
|
13
|
+
"""Information about a sandbox."""
|
|
14
|
+
|
|
15
|
+
sandbox_id: str
|
|
16
|
+
"""Sandbox ID."""
|
|
17
|
+
sandbox_domain: Optional[str]
|
|
18
|
+
"""Domain where the sandbox is hosted."""
|
|
19
|
+
template_id: str
|
|
20
|
+
"""Template ID."""
|
|
21
|
+
name: Optional[str]
|
|
22
|
+
"""Template name."""
|
|
23
|
+
metadata: Dict[str, str]
|
|
24
|
+
"""Saved sandbox metadata."""
|
|
25
|
+
started_at: datetime
|
|
26
|
+
"""Sandbox start time."""
|
|
27
|
+
uptime: int
|
|
28
|
+
"""Sandbox up time."""
|
|
29
|
+
end_at: datetime
|
|
30
|
+
"""Sandbox expiration date."""
|
|
31
|
+
timeout: int
|
|
32
|
+
"""Sandbox timeout."""
|
|
33
|
+
envd_version: Optional[str]
|
|
34
|
+
"""Envd version."""
|
|
35
|
+
_envd_access_token: Optional[str]
|
|
36
|
+
"""Envd access token."""
|
|
37
|
+
object_storage: Optional[Dict[str, str]]
|
|
38
|
+
"""Object storage."""
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@dataclass
|
|
42
|
+
class ListedSandbox:
|
|
43
|
+
"""Information about a sandbox."""
|
|
44
|
+
|
|
45
|
+
sandbox_id: str
|
|
46
|
+
"""Sandbox ID."""
|
|
47
|
+
template_id: str
|
|
48
|
+
"""Template ID."""
|
|
49
|
+
name: Optional[str]
|
|
50
|
+
"""Template Alias."""
|
|
51
|
+
state: SandboxState
|
|
52
|
+
"""Sandbox state."""
|
|
53
|
+
cpu_count: int
|
|
54
|
+
"""Sandbox CPU count."""
|
|
55
|
+
memory_mb: int
|
|
56
|
+
"""Sandbox Memory size in MB."""
|
|
57
|
+
metadata: Dict[str, str]
|
|
58
|
+
"""Saved sandbox metadata."""
|
|
59
|
+
started_at: datetime
|
|
60
|
+
"""Sandbox start time."""
|
|
61
|
+
uptime: int
|
|
62
|
+
"""Sandbox up time."""
|
|
63
|
+
end_at: datetime
|
|
64
|
+
"""Sandbox expiration date."""
|
|
65
|
+
timeout: int
|
|
66
|
+
"""Sandbox timeout."""
|
|
67
|
+
object_storage: Optional[Dict[str, str]]
|
|
68
|
+
"""Object storage."""
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@dataclass
|
|
72
|
+
class SandboxQuery:
|
|
73
|
+
"""Query parameters for listing sandboxes."""
|
|
74
|
+
|
|
75
|
+
metadata: Optional[dict[str, str]] = None
|
|
76
|
+
"""Filter sandboxes by metadata."""
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
@dataclass
|
|
80
|
+
class SandboxMetrics:
|
|
81
|
+
"""Sandbox metrics."""
|
|
82
|
+
|
|
83
|
+
cpu_count: int
|
|
84
|
+
"""Number of CPUs."""
|
|
85
|
+
cpu_used_pct: float
|
|
86
|
+
"""CPU usage percentage."""
|
|
87
|
+
disk_total: int
|
|
88
|
+
"""Total disk space in bytes."""
|
|
89
|
+
disk_used: int
|
|
90
|
+
"""Disk used in bytes."""
|
|
91
|
+
mem_total: int
|
|
92
|
+
"""Total memory in bytes."""
|
|
93
|
+
mem_used: int
|
|
94
|
+
"""Memory used in bytes."""
|
|
95
|
+
timestamp: datetime
|
|
96
|
+
"""Timestamp of the metric entry."""
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
class SandboxApiBase(ABC):
|
|
100
|
+
_limits = Limits(
|
|
101
|
+
max_keepalive_connections=10,
|
|
102
|
+
max_connections=20,
|
|
103
|
+
keepalive_expiry=20,
|
|
104
|
+
)
|
|
105
|
+
default_sandbox_timeout = 300
|