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.
Files changed (68) hide show
  1. scalebox/__init__.py +1 -1
  2. scalebox/api/__init__.py +128 -128
  3. scalebox/api/client/__init__.py +8 -8
  4. scalebox/api/client/api/sandboxes/get_sandboxes.py +5 -3
  5. scalebox/api/client/api/sandboxes/get_sandboxes_sandbox_id_metrics.py +2 -2
  6. scalebox/api/client/api/sandboxes/post_sandboxes.py +2 -2
  7. scalebox/api/client/client.py +288 -288
  8. scalebox/api/client/models/listed_sandbox.py +11 -9
  9. scalebox/api/client/models/new_sandbox.py +1 -1
  10. scalebox/api/client/models/sandbox.py +125 -125
  11. scalebox/api/client/models/sandbox_state.py +1 -0
  12. scalebox/api/client/types.py +46 -46
  13. scalebox/code_interpreter/code_interpreter_async.py +370 -369
  14. scalebox/code_interpreter/code_interpreter_sync.py +318 -317
  15. scalebox/connection_config.py +92 -92
  16. scalebox/csx_desktop/main.py +12 -12
  17. scalebox/generated/api_pb2_connect.py +17 -66
  18. scalebox/sandbox_async/commands/command.py +307 -307
  19. scalebox/sandbox_async/commands/command_handle.py +187 -187
  20. scalebox/sandbox_async/commands/pty.py +187 -187
  21. scalebox/sandbox_async/filesystem/filesystem.py +557 -557
  22. scalebox/sandbox_async/filesystem/watch_handle.py +61 -61
  23. scalebox/sandbox_async/main.py +647 -646
  24. scalebox/sandbox_async/sandbox_api.py +365 -365
  25. scalebox/sandbox_async/utils.py +7 -7
  26. scalebox/sandbox_sync/__init__.py +2 -2
  27. scalebox/sandbox_sync/commands/command.py +300 -300
  28. scalebox/sandbox_sync/commands/command_handle.py +150 -150
  29. scalebox/sandbox_sync/commands/pty.py +181 -181
  30. scalebox/sandbox_sync/filesystem/filesystem.py +543 -543
  31. scalebox/sandbox_sync/filesystem/watch_handle.py +66 -66
  32. scalebox/sandbox_sync/main.py +789 -790
  33. scalebox/sandbox_sync/sandbox_api.py +356 -356
  34. scalebox/test/CODE_INTERPRETER_TESTS_READY.md +256 -256
  35. scalebox/test/README.md +164 -164
  36. scalebox/test/aclient.py +72 -72
  37. scalebox/test/code_interpreter_centext.py +21 -21
  38. scalebox/test/code_interpreter_centext_sync.py +21 -21
  39. scalebox/test/code_interpreter_test.py +1 -1
  40. scalebox/test/code_interpreter_test_sync.py +1 -1
  41. scalebox/test/run_all_validation_tests.py +334 -334
  42. scalebox/test/test_basic.py +78 -78
  43. scalebox/test/test_code_interpreter_async_comprehensive.py +2653 -2653
  44. scalebox/test/{test_code_interpreter_e2bsync_comprehensive.py → test_code_interpreter_execcode.py} +328 -392
  45. scalebox/test/test_code_interpreter_sync_comprehensive.py +3416 -3412
  46. scalebox/test/test_csx_desktop_examples.py +130 -0
  47. scalebox/test/test_sandbox_async_comprehensive.py +736 -738
  48. scalebox/test/test_sandbox_stress_and_edge_cases.py +778 -778
  49. scalebox/test/test_sandbox_sync_comprehensive.py +779 -770
  50. scalebox/test/test_sandbox_usage_examples.py +987 -987
  51. scalebox/test/testacreate.py +24 -24
  52. scalebox/test/testagetinfo.py +18 -18
  53. scalebox/test/testcodeinterpreter_async.py +508 -508
  54. scalebox/test/testcodeinterpreter_sync.py +239 -239
  55. scalebox/test/testcomputeuse.py +2 -2
  56. scalebox/test/testnovnc.py +12 -12
  57. scalebox/test/testsandbox_api.py +15 -0
  58. scalebox/test/testsandbox_async.py +202 -118
  59. scalebox/test/testsandbox_sync.py +71 -38
  60. scalebox/version.py +2 -2
  61. {scalebox_sdk-0.1.4.dist-info → scalebox_sdk-0.1.25.dist-info}/METADATA +104 -103
  62. {scalebox_sdk-0.1.4.dist-info → scalebox_sdk-0.1.25.dist-info}/RECORD +66 -66
  63. scalebox/test/test_code_interpreter_e2basync_comprehensive.py +0 -2655
  64. scalebox/test/test_e2b_first.py +0 -11
  65. {scalebox_sdk-0.1.4.dist-info → scalebox_sdk-0.1.25.dist-info}/WHEEL +0 -0
  66. {scalebox_sdk-0.1.4.dist-info → scalebox_sdk-0.1.25.dist-info}/entry_points.txt +0 -0
  67. {scalebox_sdk-0.1.4.dist-info → scalebox_sdk-0.1.25.dist-info}/licenses/LICENSE +0 -0
  68. {scalebox_sdk-0.1.4.dist-info → scalebox_sdk-0.1.25.dist-info}/top_level.txt +0 -0
@@ -1,187 +1,187 @@
1
- import asyncio
2
- import inspect
3
- from typing import Any, AsyncIterator, Callable, Coroutine, Optional, Tuple, Union
4
-
5
- from ...generated import api_pb2
6
- from ...generated.rpc import handle_rpc_exception
7
- from ...sandbox.commands.command_handle import (
8
- CommandExitException,
9
- CommandResult,
10
- PtyOutput,
11
- Stderr,
12
- Stdout,
13
- )
14
- from ...sandbox_async.utils import OutputHandler
15
-
16
-
17
- class AsyncCommandHandle:
18
- """
19
- Command execution handle.
20
-
21
- It provides methods for waiting for the command to finish, retrieving stdout/stderr, and killing the command.
22
- """
23
-
24
- @property
25
- def pid(self):
26
- """
27
- Command process ID.
28
- """
29
- return self._pid
30
-
31
- @property
32
- def stdout(self):
33
- """
34
- Command stdout output.
35
- """
36
- return self._stdout
37
-
38
- @property
39
- def stderr(self):
40
- """
41
- Command stderr output.
42
- """
43
- return self._stderr
44
-
45
- @property
46
- def error(self):
47
- """
48
- Command execution error message.
49
- """
50
- if self._result is None:
51
- return None
52
- return self._result.error
53
-
54
- @property
55
- def exit_code(self):
56
- """
57
- Command execution exit code.
58
-
59
- `0` if the command finished successfully.
60
-
61
- It is `None` if the command is still running.
62
- """
63
- if self._result is None:
64
- return None
65
- return self._result.exit_code
66
-
67
- def __init__(
68
- self,
69
- pid: int,
70
- handle_kill: Callable[[], Coroutine[Any, Any, bool]],
71
- events: AsyncIterator[
72
- Union[api_pb2.StartResponse, api_pb2.ConnectResponse]
73
- ],
74
- on_stdout: Optional[OutputHandler[Stdout]] = None,
75
- on_stderr: Optional[OutputHandler[Stderr]] = None,
76
- on_pty: Optional[OutputHandler[PtyOutput]] = None,
77
- ):
78
- self._pid = pid
79
- self._handle_kill = handle_kill
80
- self._events = events
81
-
82
- self._stdout: str = ""
83
- self._stderr: str = ""
84
-
85
- self._on_stdout = on_stdout
86
- self._on_stderr = on_stderr
87
- self._on_pty = on_pty
88
-
89
- self._result: Optional[CommandResult] = None
90
- self._iteration_exception: Optional[Exception] = None
91
-
92
- self._wait = asyncio.create_task(self._handle_events())
93
-
94
- async def _iterate_events(
95
- self,
96
- ) -> AsyncIterator[
97
- Union[
98
- Tuple[Stdout, None, None],
99
- Tuple[None, Stderr, None],
100
- Tuple[None, None, PtyOutput],
101
- ],
102
- ]:
103
- async for event in self._events:
104
- if event.event.HasField("data"):
105
- if event.event.data.stdout:
106
- out = event.event.data.stdout.decode("utf-8", "replace")
107
- self._stdout += out
108
- yield out, None, None
109
- if event.event.data.stderr:
110
- out = event.event.data.stderr.decode("utf-8", "replace")
111
- self._stderr += out
112
- yield None, out, None
113
- if event.event.data.pty:
114
- yield None, None, event.event.data.pty
115
- if event.event.HasField("end"):
116
- self._result = CommandResult(
117
- stdout=self._stdout,
118
- stderr=self._stderr,
119
- exit_code=event.event.end.exit_code,
120
- error=event.event.end.error,
121
- )
122
-
123
- async def disconnect(self) -> None:
124
- """
125
- Disconnects from the command.
126
-
127
- The command is not killed, but SDK stops receiving events from the command.
128
- You can reconnect to the command using `sandbox.commands.connect` method.
129
- """
130
- self._wait.cancel()
131
- # BUG: In Python 3.8 closing async generator can throw RuntimeError.
132
- # await self._events.aclose()
133
-
134
- async def _handle_events(self):
135
- try:
136
- async for stdout, stderr, pty in self._iterate_events():
137
- if stdout is not None and self._on_stdout:
138
- cb = self._on_stdout(stdout)
139
- if inspect.isawaitable(cb):
140
- await cb
141
- elif stderr is not None and self._on_stderr:
142
- cb = self._on_stderr(stderr)
143
- if inspect.isawaitable(cb):
144
- await cb
145
- elif pty is not None and self._on_pty:
146
- cb = self._on_pty(pty)
147
- if inspect.isawaitable(cb):
148
- await cb
149
- except StopAsyncIteration:
150
- pass
151
- except Exception as e:
152
- self._iteration_exception = handle_rpc_exception(e)
153
-
154
- async def wait(self) -> CommandResult:
155
- """
156
- Wait for the command to finish and return the result.
157
- If the command exits with a non-zero exit code, it throws a `CommandExitException`.
158
-
159
- :return: `CommandResult` result of command execution
160
- """
161
- await self._wait
162
- if self._iteration_exception:
163
- raise self._iteration_exception
164
-
165
- if self._result is None:
166
- raise Exception("Command ended without an end event")
167
-
168
- if self._result.exit_code != 0:
169
- raise CommandExitException(
170
- stdout=self._stdout,
171
- stderr=self._stderr,
172
- exit_code=self._result.exit_code,
173
- error=self._result.error,
174
- )
175
-
176
- return self._result
177
-
178
- async def kill(self) -> bool:
179
- """
180
- Kills the command.
181
-
182
- It uses `SIGKILL` signal to kill the command
183
-
184
- :return: `True` if the command was killed successfully, `False` if the command was not found
185
- """
186
- result = await self._handle_kill()
187
- return result
1
+ import asyncio
2
+ import inspect
3
+ from typing import Any, AsyncIterator, Callable, Coroutine, Optional, Tuple, Union
4
+
5
+ from ...generated import api_pb2
6
+ from ...generated.rpc import handle_rpc_exception
7
+ from ...sandbox.commands.command_handle import (
8
+ CommandExitException,
9
+ CommandResult,
10
+ PtyOutput,
11
+ Stderr,
12
+ Stdout,
13
+ )
14
+ from ...sandbox_async.utils import OutputHandler
15
+
16
+
17
+ class AsyncCommandHandle:
18
+ """
19
+ Command execution handle.
20
+
21
+ It provides methods for waiting for the command to finish, retrieving stdout/stderr, and killing the command.
22
+ """
23
+
24
+ @property
25
+ def pid(self):
26
+ """
27
+ Command process ID.
28
+ """
29
+ return self._pid
30
+
31
+ @property
32
+ def stdout(self):
33
+ """
34
+ Command stdout output.
35
+ """
36
+ return self._stdout
37
+
38
+ @property
39
+ def stderr(self):
40
+ """
41
+ Command stderr output.
42
+ """
43
+ return self._stderr
44
+
45
+ @property
46
+ def error(self):
47
+ """
48
+ Command execution error message.
49
+ """
50
+ if self._result is None:
51
+ return None
52
+ return self._result.error
53
+
54
+ @property
55
+ def exit_code(self):
56
+ """
57
+ Command execution exit code.
58
+
59
+ `0` if the command finished successfully.
60
+
61
+ It is `None` if the command is still running.
62
+ """
63
+ if self._result is None:
64
+ return None
65
+ return self._result.exit_code
66
+
67
+ def __init__(
68
+ self,
69
+ pid: int,
70
+ handle_kill: Callable[[], Coroutine[Any, Any, bool]],
71
+ events: AsyncIterator[
72
+ Union[api_pb2.StartResponse, api_pb2.ConnectResponse]
73
+ ],
74
+ on_stdout: Optional[OutputHandler[Stdout]] = None,
75
+ on_stderr: Optional[OutputHandler[Stderr]] = None,
76
+ on_pty: Optional[OutputHandler[PtyOutput]] = None,
77
+ ):
78
+ self._pid = pid
79
+ self._handle_kill = handle_kill
80
+ self._events = events
81
+
82
+ self._stdout: str = ""
83
+ self._stderr: str = ""
84
+
85
+ self._on_stdout = on_stdout
86
+ self._on_stderr = on_stderr
87
+ self._on_pty = on_pty
88
+
89
+ self._result: Optional[CommandResult] = None
90
+ self._iteration_exception: Optional[Exception] = None
91
+
92
+ self._wait = asyncio.create_task(self._handle_events())
93
+
94
+ async def _iterate_events(
95
+ self,
96
+ ) -> AsyncIterator[
97
+ Union[
98
+ Tuple[Stdout, None, None],
99
+ Tuple[None, Stderr, None],
100
+ Tuple[None, None, PtyOutput],
101
+ ],
102
+ ]:
103
+ async for event in self._events:
104
+ if event.event.HasField("data"):
105
+ if event.event.data.stdout:
106
+ out = event.event.data.stdout.decode("utf-8", "replace")
107
+ self._stdout += out
108
+ yield out, None, None
109
+ if event.event.data.stderr:
110
+ out = event.event.data.stderr.decode("utf-8", "replace")
111
+ self._stderr += out
112
+ yield None, out, None
113
+ if event.event.data.pty:
114
+ yield None, None, event.event.data.pty
115
+ if event.event.HasField("end"):
116
+ self._result = CommandResult(
117
+ stdout=self._stdout,
118
+ stderr=self._stderr,
119
+ exit_code=event.event.end.exit_code,
120
+ error=event.event.end.error,
121
+ )
122
+
123
+ async def disconnect(self) -> None:
124
+ """
125
+ Disconnects from the command.
126
+
127
+ The command is not killed, but SDK stops receiving events from the command.
128
+ You can reconnect to the command using `sandbox.commands.connect` method.
129
+ """
130
+ self._wait.cancel()
131
+ # BUG: In Python 3.8 closing async generator can throw RuntimeError.
132
+ # await self._events.aclose()
133
+
134
+ async def _handle_events(self):
135
+ try:
136
+ async for stdout, stderr, pty in self._iterate_events():
137
+ if stdout is not None and self._on_stdout:
138
+ cb = self._on_stdout(stdout)
139
+ if inspect.isawaitable(cb):
140
+ await cb
141
+ elif stderr is not None and self._on_stderr:
142
+ cb = self._on_stderr(stderr)
143
+ if inspect.isawaitable(cb):
144
+ await cb
145
+ elif pty is not None and self._on_pty:
146
+ cb = self._on_pty(pty)
147
+ if inspect.isawaitable(cb):
148
+ await cb
149
+ except StopAsyncIteration:
150
+ pass
151
+ except Exception as e:
152
+ self._iteration_exception = handle_rpc_exception(e)
153
+
154
+ async def wait(self) -> CommandResult:
155
+ """
156
+ Wait for the command to finish and return the result.
157
+ If the command exits with a non-zero exit code, it throws a `CommandExitException`.
158
+
159
+ :return: `CommandResult` result of command execution
160
+ """
161
+ await self._wait
162
+ if self._iteration_exception:
163
+ raise self._iteration_exception
164
+
165
+ if self._result is None:
166
+ raise Exception("Command ended without an end event")
167
+
168
+ if self._result.exit_code != 0:
169
+ raise CommandExitException(
170
+ stdout=self._stdout,
171
+ stderr=self._stderr,
172
+ exit_code=self._result.exit_code,
173
+ error=self._result.error,
174
+ )
175
+
176
+ return self._result
177
+
178
+ async def kill(self) -> bool:
179
+ """
180
+ Kills the command.
181
+
182
+ It uses `SIGKILL` signal to kill the command
183
+
184
+ :return: `True` if the command was killed successfully, `False` if the command was not found
185
+ """
186
+ result = await self._handle_kill()
187
+ return result