scalebox-sdk 0.1.0__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 (157) hide show
  1. scalebox/__init__.py +80 -0
  2. scalebox/api/__init__.py +128 -0
  3. scalebox/api/client/__init__.py +8 -0
  4. scalebox/api/client/api/__init__.py +1 -0
  5. scalebox/api/client/api/sandboxes/__init__.py +0 -0
  6. scalebox/api/client/api/sandboxes/delete_sandboxes_sandbox_id.py +161 -0
  7. scalebox/api/client/api/sandboxes/get_sandboxes.py +176 -0
  8. scalebox/api/client/api/sandboxes/get_sandboxes_metrics.py +173 -0
  9. scalebox/api/client/api/sandboxes/get_sandboxes_sandbox_id.py +163 -0
  10. scalebox/api/client/api/sandboxes/get_sandboxes_sandbox_id_logs.py +199 -0
  11. scalebox/api/client/api/sandboxes/get_sandboxes_sandbox_id_metrics.py +214 -0
  12. scalebox/api/client/api/sandboxes/get_v2_sandboxes.py +229 -0
  13. scalebox/api/client/api/sandboxes/post_sandboxes.py +174 -0
  14. scalebox/api/client/api/sandboxes/post_sandboxes_sandbox_id_pause.py +165 -0
  15. scalebox/api/client/api/sandboxes/post_sandboxes_sandbox_id_refreshes.py +182 -0
  16. scalebox/api/client/api/sandboxes/post_sandboxes_sandbox_id_resume.py +190 -0
  17. scalebox/api/client/api/sandboxes/post_sandboxes_sandbox_id_timeout.py +194 -0
  18. scalebox/api/client/client.py +288 -0
  19. scalebox/api/client/errors.py +16 -0
  20. scalebox/api/client/models/__init__.py +81 -0
  21. scalebox/api/client/models/build_log_entry.py +79 -0
  22. scalebox/api/client/models/created_access_token.py +100 -0
  23. scalebox/api/client/models/created_team_api_key.py +166 -0
  24. scalebox/api/client/models/error.py +67 -0
  25. scalebox/api/client/models/identifier_masking_details.py +83 -0
  26. scalebox/api/client/models/listed_sandbox.py +138 -0
  27. scalebox/api/client/models/log_level.py +11 -0
  28. scalebox/api/client/models/new_access_token.py +59 -0
  29. scalebox/api/client/models/new_sandbox.py +125 -0
  30. scalebox/api/client/models/new_team_api_key.py +59 -0
  31. scalebox/api/client/models/node.py +154 -0
  32. scalebox/api/client/models/node_detail.py +152 -0
  33. scalebox/api/client/models/node_status.py +11 -0
  34. scalebox/api/client/models/node_status_change.py +61 -0
  35. scalebox/api/client/models/post_sandboxes_sandbox_id_refreshes_body.py +59 -0
  36. scalebox/api/client/models/post_sandboxes_sandbox_id_timeout_body.py +59 -0
  37. scalebox/api/client/models/resumed_sandbox.py +68 -0
  38. scalebox/api/client/models/sandbox.py +125 -0
  39. scalebox/api/client/models/sandbox_detail.py +178 -0
  40. scalebox/api/client/models/sandbox_log.py +70 -0
  41. scalebox/api/client/models/sandbox_logs.py +73 -0
  42. scalebox/api/client/models/sandbox_metric.py +110 -0
  43. scalebox/api/client/models/sandbox_state.py +9 -0
  44. scalebox/api/client/models/sandboxes_with_metrics.py +59 -0
  45. scalebox/api/client/models/team.py +83 -0
  46. scalebox/api/client/models/team_api_key.py +158 -0
  47. scalebox/api/client/models/team_user.py +68 -0
  48. scalebox/api/client/models/template.py +179 -0
  49. scalebox/api/client/models/template_build.py +117 -0
  50. scalebox/api/client/models/template_build_file_upload.py +70 -0
  51. scalebox/api/client/models/template_build_request.py +115 -0
  52. scalebox/api/client/models/template_build_request_v2.py +88 -0
  53. scalebox/api/client/models/template_build_start_v2.py +114 -0
  54. scalebox/api/client/models/template_build_status.py +11 -0
  55. scalebox/api/client/models/template_step.py +91 -0
  56. scalebox/api/client/models/template_update_request.py +59 -0
  57. scalebox/api/client/models/update_team_api_key.py +59 -0
  58. scalebox/api/client/py.typed +1 -0
  59. scalebox/api/client/types.py +46 -0
  60. scalebox/api/metadata.py +19 -0
  61. scalebox/cli.py +125 -0
  62. scalebox/client/__init__.py +0 -0
  63. scalebox/client/aclient.py +57 -0
  64. scalebox/client/api.proto +460 -0
  65. scalebox/client/buf.gen.yaml +8 -0
  66. scalebox/client/client.py +102 -0
  67. scalebox/client/requirements.txt +5 -0
  68. scalebox/code_interpreter/__init__.py +12 -0
  69. scalebox/code_interpreter/charts.py +230 -0
  70. scalebox/code_interpreter/code_interpreter_async.py +369 -0
  71. scalebox/code_interpreter/code_interpreter_sync.py +317 -0
  72. scalebox/code_interpreter/constants.py +3 -0
  73. scalebox/code_interpreter/exceptions.py +13 -0
  74. scalebox/code_interpreter/models.py +485 -0
  75. scalebox/connection_config.py +92 -0
  76. scalebox/csx_connect/__init__.py +1 -0
  77. scalebox/csx_connect/client.py +485 -0
  78. scalebox/csx_desktop/__init__.py +0 -0
  79. scalebox/csx_desktop/main.py +651 -0
  80. scalebox/exceptions.py +83 -0
  81. scalebox/generated/__init__.py +0 -0
  82. scalebox/generated/api.py +61 -0
  83. scalebox/generated/api_pb2.py +203 -0
  84. scalebox/generated/api_pb2.pyi +956 -0
  85. scalebox/generated/api_pb2_connect.py +1456 -0
  86. scalebox/generated/rpc.py +50 -0
  87. scalebox/generated/versions.py +3 -0
  88. scalebox/requirements.txt +36 -0
  89. scalebox/sandbox/__init__.py +0 -0
  90. scalebox/sandbox/commands/__init__.py +0 -0
  91. scalebox/sandbox/commands/command_handle.py +69 -0
  92. scalebox/sandbox/commands/main.py +39 -0
  93. scalebox/sandbox/filesystem/__init__.py +0 -0
  94. scalebox/sandbox/filesystem/filesystem.py +95 -0
  95. scalebox/sandbox/filesystem/watch_handle.py +60 -0
  96. scalebox/sandbox/main.py +139 -0
  97. scalebox/sandbox/sandbox_api.py +91 -0
  98. scalebox/sandbox/signature.py +40 -0
  99. scalebox/sandbox/utils.py +34 -0
  100. scalebox/sandbox_async/__init__.py +1 -0
  101. scalebox/sandbox_async/commands/command.py +307 -0
  102. scalebox/sandbox_async/commands/command_handle.py +187 -0
  103. scalebox/sandbox_async/commands/pty.py +187 -0
  104. scalebox/sandbox_async/filesystem/filesystem.py +557 -0
  105. scalebox/sandbox_async/filesystem/watch_handle.py +61 -0
  106. scalebox/sandbox_async/main.py +646 -0
  107. scalebox/sandbox_async/sandbox_api.py +365 -0
  108. scalebox/sandbox_async/utils.py +7 -0
  109. scalebox/sandbox_sync/__init__.py +2 -0
  110. scalebox/sandbox_sync/commands/__init__.py +0 -0
  111. scalebox/sandbox_sync/commands/command.py +300 -0
  112. scalebox/sandbox_sync/commands/command_handle.py +150 -0
  113. scalebox/sandbox_sync/commands/pty.py +181 -0
  114. scalebox/sandbox_sync/filesystem/__init__.py +0 -0
  115. scalebox/sandbox_sync/filesystem/filesystem.py +543 -0
  116. scalebox/sandbox_sync/filesystem/watch_handle.py +66 -0
  117. scalebox/sandbox_sync/main.py +790 -0
  118. scalebox/sandbox_sync/sandbox_api.py +356 -0
  119. scalebox/test/CODE_INTERPRETER_TESTS_READY.md +323 -0
  120. scalebox/test/README.md +329 -0
  121. scalebox/test/__init__.py +0 -0
  122. scalebox/test/aclient.py +72 -0
  123. scalebox/test/code_interpreter_centext.py +21 -0
  124. scalebox/test/code_interpreter_centext_sync.py +21 -0
  125. scalebox/test/code_interpreter_test.py +34 -0
  126. scalebox/test/code_interpreter_test_sync.py +34 -0
  127. scalebox/test/run_all_validation_tests.py +334 -0
  128. scalebox/test/run_code_interpreter_tests.sh +67 -0
  129. scalebox/test/run_tests.sh +230 -0
  130. scalebox/test/test_basic.py +78 -0
  131. scalebox/test/test_code_interpreter_async_comprehensive.py +2653 -0
  132. scalebox/test/test_code_interpreter_e2basync_comprehensive.py +2655 -0
  133. scalebox/test/test_code_interpreter_e2bsync_comprehensive.py +3416 -0
  134. scalebox/test/test_code_interpreter_sync_comprehensive.py +3412 -0
  135. scalebox/test/test_e2b_first.py +11 -0
  136. scalebox/test/test_sandbox_async_comprehensive.py +738 -0
  137. scalebox/test/test_sandbox_stress_and_edge_cases.py +778 -0
  138. scalebox/test/test_sandbox_sync_comprehensive.py +770 -0
  139. scalebox/test/test_sandbox_usage_examples.py +987 -0
  140. scalebox/test/testacreate.py +24 -0
  141. scalebox/test/testagetinfo.py +18 -0
  142. scalebox/test/testcodeinterpreter_async.py +508 -0
  143. scalebox/test/testcodeinterpreter_sync.py +239 -0
  144. scalebox/test/testcomputeuse.py +243 -0
  145. scalebox/test/testnovnc.py +12 -0
  146. scalebox/test/testsandbox_async.py +118 -0
  147. scalebox/test/testsandbox_sync.py +38 -0
  148. scalebox/utils/__init__.py +0 -0
  149. scalebox/utils/httpcoreclient.py +297 -0
  150. scalebox/utils/httpxclient.py +403 -0
  151. scalebox/version.py +16 -0
  152. scalebox_sdk-0.1.0.dist-info/METADATA +292 -0
  153. scalebox_sdk-0.1.0.dist-info/RECORD +157 -0
  154. scalebox_sdk-0.1.0.dist-info/WHEEL +5 -0
  155. scalebox_sdk-0.1.0.dist-info/entry_points.txt +2 -0
  156. scalebox_sdk-0.1.0.dist-info/licenses/LICENSE +21 -0
  157. scalebox_sdk-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,150 @@
1
+ from typing import Any, Callable, Generator, Iterator, Optional, Tuple, Union
2
+
3
+ from ...generated import api_pb2
4
+ from ...generated.rpc import handle_rpc_exception
5
+ from ...sandbox.commands.command_handle import (
6
+ CommandExitException,
7
+ CommandResult,
8
+ PtyOutput,
9
+ Stderr,
10
+ Stdout,
11
+ )
12
+
13
+
14
+ class CommandHandle:
15
+ """
16
+ Command execution handle.
17
+
18
+ It provides methods for waiting for the command to finish, retrieving stdout/stderr, and killing the command.
19
+ """
20
+
21
+ @property
22
+ def pid(self):
23
+ """
24
+ Command process ID.
25
+ """
26
+ return self._pid
27
+
28
+ def __init__(
29
+ self,
30
+ pid: int,
31
+ handle_kill: Callable[[], bool],
32
+ events: Iterator[
33
+ Union[api_pb2.StartResponse, api_pb2.ConnectResponse]
34
+ ],
35
+ ):
36
+ self._pid = pid
37
+ self._handle_kill = handle_kill
38
+ self._events = events
39
+
40
+ self._stdout: str = ""
41
+ self._stderr: str = ""
42
+
43
+ self._result: Optional[CommandResult] = None
44
+ self._iteration_exception: Optional[Exception] = None
45
+
46
+ def __iter__(self):
47
+ """
48
+ Iterate over the command output.
49
+
50
+ :return: Generator of command outputs
51
+ """
52
+ return self._handle_events()
53
+
54
+ def _handle_events(
55
+ self,
56
+ ) -> Generator[
57
+ Union[
58
+ Tuple[Stdout, None, None],
59
+ Tuple[None, Stderr, None],
60
+ Tuple[None, None, PtyOutput],
61
+ ],
62
+ None,
63
+ None,
64
+ ]:
65
+ try:
66
+ for event in self._events:
67
+ if event.event.HasField("data"):
68
+ if event.event.data.stdout:
69
+ out = event.event.data.stdout.decode("utf-8", "replace")
70
+ self._stdout += out
71
+ yield out, None, None
72
+ if event.event.data.stderr:
73
+ out = event.event.data.stderr.decode("utf-8", "replace")
74
+ self._stderr += out
75
+ yield None, out, None
76
+ if event.event.data.pty:
77
+ yield None, None, event.event.data.pty
78
+ if event.event.HasField("end"):
79
+ self._result = CommandResult(
80
+ stdout=self._stdout,
81
+ stderr=self._stderr,
82
+ exit_code=event.event.end.exit_code,
83
+ error=event.event.end.error,
84
+ )
85
+ except Exception as e:
86
+ raise handle_rpc_exception(e)
87
+
88
+ def disconnect(self) -> None:
89
+ """
90
+ Disconnect from the command.
91
+
92
+ The command is not killed, but SDK stops receiving events from the command.
93
+ You can reconnect to the command using `sandbox.commands.connect` method.
94
+ """
95
+ self._events.close()
96
+
97
+ def wait(
98
+ self,
99
+ on_pty: Optional[Callable[[PtyOutput], None]] = None,
100
+ on_stdout: Optional[Callable[[str], None]] = None,
101
+ on_stderr: Optional[Callable[[str], None]] = None,
102
+ ) -> CommandResult:
103
+ """
104
+ Wait for the command to finish and returns the result.
105
+ If the command exits with a non-zero exit code, it throws a `CommandExitException`.
106
+
107
+ :param on_pty: Callback for pty output
108
+ :param on_stdout: Callback for stdout output
109
+ :param on_stderr: Callback for stderr output
110
+
111
+ :return: `CommandResult` result of command execution
112
+ """
113
+ try:
114
+ for stdout, stderr, pty in self:
115
+ if stdout is not None and on_stdout:
116
+ on_stdout(stdout)
117
+ elif stderr is not None and on_stderr:
118
+ on_stderr(stderr)
119
+ elif pty is not None and on_pty:
120
+ on_pty(pty)
121
+ except StopIteration:
122
+ pass
123
+ except Exception as e:
124
+ self._iteration_exception = handle_rpc_exception(e)
125
+
126
+ if self._iteration_exception:
127
+ raise self._iteration_exception
128
+
129
+ if self._result is None:
130
+ raise Exception("Command ended without an end event")
131
+
132
+ if self._result.exit_code != 0:
133
+ raise CommandExitException(
134
+ stdout=self._stdout,
135
+ stderr=self._stderr,
136
+ exit_code=self._result.exit_code,
137
+ error=self._result.error,
138
+ )
139
+
140
+ return self._result
141
+
142
+ def kill(self) -> bool:
143
+ """
144
+ Kills the command.
145
+
146
+ It uses `SIGKILL` signal to kill the command.
147
+
148
+ :return: Whether the command was killed successfully
149
+ """
150
+ return self._handle_kill()
@@ -0,0 +1,181 @@
1
+ from typing import Dict, Optional
2
+
3
+ import httpcore
4
+ import urllib3
5
+
6
+ from ... import csx_connect
7
+ from ...connection_config import (
8
+ KEEPALIVE_PING_HEADER,
9
+ KEEPALIVE_PING_INTERVAL_SEC,
10
+ ConnectionConfig,
11
+ Username,
12
+ )
13
+ from ...exceptions import SandboxException
14
+ from ...generated import api_pb2, api_pb2_connect
15
+ from ...generated.rpc import authentication_header, handle_rpc_exception
16
+ from ...sandbox.commands.command_handle import PtySize
17
+ from ...sandbox_sync.commands.command_handle import CommandHandle
18
+
19
+
20
+ class Pty:
21
+ """
22
+ Module for interacting with PTYs (pseudo-terminals) in the sandbox.
23
+ """
24
+
25
+ def __init__(
26
+ self,
27
+ envd_api_url: str,
28
+ connection_config: ConnectionConfig,
29
+ pool: urllib3.PoolManager,
30
+ ) -> None:
31
+ self._connection_config = connection_config
32
+ self._rpc = api_pb2_connect.ProcessClient(
33
+ envd_api_url,
34
+ http_client=pool,
35
+ )
36
+ self._headers = connection_config.headers
37
+ self._pool = pool
38
+
39
+ def kill(
40
+ self,
41
+ pid: int,
42
+ request_timeout: Optional[float] = None,
43
+ ) -> bool:
44
+ """
45
+ Kill PTY.
46
+
47
+ :param pid: Process ID of the PTY
48
+ :param request_timeout: Timeout for the request in **seconds**
49
+
50
+ :return: `true` if the PTY was killed, `false` if the PTY was not found
51
+ """
52
+ try:
53
+ self._rpc.send_signal(
54
+ api_pb2.SendSignalRequest(
55
+ process=api_pb2.ProcessSelector(pid=pid),
56
+ signal=api_pb2.Signal.SIGNAL_SIGKILL,
57
+ ),
58
+ self._headers,
59
+ timeout_seconds=self._connection_config.get_request_timeout(
60
+ request_timeout
61
+ ),
62
+ )
63
+ return True
64
+ except Exception as e:
65
+ if isinstance(e, csx_connect.ConnectException):
66
+ if e.status == csx_connect.Code.not_found:
67
+ return False
68
+ raise handle_rpc_exception(e)
69
+
70
+ def send_stdin(
71
+ self,
72
+ pid: int,
73
+ data: bytes,
74
+ request_timeout: Optional[float] = None,
75
+ ) -> None:
76
+ """
77
+ Send input to a PTY.
78
+
79
+ :param pid: Process ID of the PTY
80
+ :param data: Input data to send
81
+ :param request_timeout: Timeout for the request in **seconds**
82
+ """
83
+ try:
84
+ self._rpc.send_input(
85
+ api_pb2.SendInputRequest(
86
+ process=api_pb2.ProcessSelector(pid=pid),
87
+ input=api_pb2.ProcessInput(
88
+ pty=data,
89
+ ),
90
+ ),
91
+ self._headers,
92
+ timeout_seconds=self._connection_config.get_request_timeout(
93
+ request_timeout
94
+ ),
95
+ )
96
+ except Exception as e:
97
+ raise handle_rpc_exception(e)
98
+
99
+ def create(
100
+ self,
101
+ size: PtySize,
102
+ user: Username = "user",
103
+ cwd: Optional[str] = None,
104
+ envs: Optional[Dict[str, str]] = None,
105
+ timeout: Optional[float] = 60,
106
+ request_timeout: Optional[float] = None,
107
+ ) -> CommandHandle:
108
+ """
109
+ Start a new PTY (pseudo-terminal).
110
+
111
+ :param size: Size of the PTY
112
+ :param user: User to use for the PTY
113
+ :param cwd: Working directory for the PTY
114
+ :param envs: Environment variables for the PTY
115
+ :param timeout: Timeout for the PTY in **seconds**
116
+ :param request_timeout: Timeout for the request in **seconds**
117
+
118
+ :return: Handle to interact with the PTY
119
+ """
120
+ envs = envs or {}
121
+ envs["TERM"] = "xterm-256color"
122
+ events = self._rpc.start(
123
+ api_pb2.StartRequest(
124
+ process=api_pb2.ProcessConfig(
125
+ cmd="/bin/bash",
126
+ envs=envs,
127
+ args=["-i", "-l"],
128
+ cwd=cwd,
129
+ ),
130
+ pty=api_pb2.PTY(
131
+ size=api_pb2.PTY.Size(rows=size.rows, cols=size.cols)
132
+ ),
133
+ ),
134
+ self._headers,
135
+ timeout_seconds=self._connection_config.get_request_timeout(
136
+ request_timeout
137
+ ),
138
+ )
139
+
140
+ try:
141
+ start_event = events.__next__()
142
+
143
+ if not start_event.HasField("event"):
144
+ raise SandboxException(
145
+ f"Failed to start process: expected start event, got {start_event}"
146
+ )
147
+
148
+ return CommandHandle(
149
+ pid=start_event.event.start.pid,
150
+ handle_kill=lambda: self.kill(start_event.event.start.pid),
151
+ events=events,
152
+ )
153
+ except Exception as e:
154
+ raise handle_rpc_exception(e)
155
+
156
+ def resize(
157
+ self,
158
+ pid: int,
159
+ size: PtySize,
160
+ request_timeout: Optional[float] = None,
161
+ ) -> None:
162
+ """
163
+ Resize PTY.
164
+ Call this when the terminal window is resized and the number of columns and rows has changed.
165
+
166
+ :param pid: Process ID of the PTY
167
+ :param size: New size of the PTY
168
+ :param request_timeout: Timeout for the request in **seconds**s
169
+ """
170
+ self._rpc.update(
171
+ api_pb2.UpdateRequest(
172
+ process=api_pb2.ProcessSelector(pid=pid),
173
+ pty=api_pb2.PTY(
174
+ size=api_pb2.PTY.Size(rows=size.rows, cols=size.cols),
175
+ ),
176
+ ),
177
+ self._headers,
178
+ timeout_seconds=self._connection_config.get_request_timeout(
179
+ request_timeout
180
+ ),
181
+ )
File without changes