scalebox-sdk 0.1.15__py3-none-any.whl → 0.1.16__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/code_interpreter/code_interpreter_async.py +370 -369
- scalebox/code_interpreter/code_interpreter_sync.py +318 -317
- scalebox/version.py +2 -2
- {scalebox_sdk-0.1.15.dist-info → scalebox_sdk-0.1.16.dist-info}/METADATA +1 -1
- {scalebox_sdk-0.1.15.dist-info → scalebox_sdk-0.1.16.dist-info}/RECORD +10 -10
- {scalebox_sdk-0.1.15.dist-info → scalebox_sdk-0.1.16.dist-info}/WHEEL +0 -0
- {scalebox_sdk-0.1.15.dist-info → scalebox_sdk-0.1.16.dist-info}/entry_points.txt +0 -0
- {scalebox_sdk-0.1.15.dist-info → scalebox_sdk-0.1.16.dist-info}/licenses/LICENSE +0 -0
- {scalebox_sdk-0.1.15.dist-info → scalebox_sdk-0.1.16.dist-info}/top_level.txt +0 -0
|
@@ -1,369 +1,370 @@
|
|
|
1
|
-
import logging
|
|
2
|
-
from typing import Dict, Literal, Optional, Union, overload
|
|
3
|
-
|
|
4
|
-
import aiohttp
|
|
5
|
-
import httpx
|
|
6
|
-
from aiohttp import TCPConnector
|
|
7
|
-
from httpx import AsyncClient
|
|
8
|
-
|
|
9
|
-
from ..connection_config import ConnectionConfig
|
|
10
|
-
from ..exceptions import InvalidArgumentException
|
|
11
|
-
from ..generated import api_pb2, api_pb2_connect
|
|
12
|
-
from ..sandbox_async.main import AsyncSandbox as BaseAsyncSandbox
|
|
13
|
-
from .constants import DEFAULT_TEMPLATE, DEFAULT_TIMEOUT, JUPYTER_PORT
|
|
14
|
-
from .exceptions import format_execution_timeout_error, format_request_timeout_error
|
|
15
|
-
from .models import (
|
|
16
|
-
Context,
|
|
17
|
-
Execution,
|
|
18
|
-
ExecutionError,
|
|
19
|
-
OutputHandler,
|
|
20
|
-
OutputMessage,
|
|
21
|
-
Result,
|
|
22
|
-
aextract_exception,
|
|
23
|
-
parse_output,
|
|
24
|
-
)
|
|
25
|
-
|
|
26
|
-
logger = logging.getLogger(__name__)
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
class AsyncSandbox(BaseAsyncSandbox):
|
|
30
|
-
"""
|
|
31
|
-
Scalebox cloud sandbox is a secure and isolated cloud environment.
|
|
32
|
-
|
|
33
|
-
The sandbox allows you to:
|
|
34
|
-
- Access Linux OS
|
|
35
|
-
- Create, list, and delete files and directories
|
|
36
|
-
- Run commands
|
|
37
|
-
- Run isolated code
|
|
38
|
-
- Access the internet
|
|
39
|
-
|
|
40
|
-
Check docs for more information.
|
|
41
|
-
|
|
42
|
-
Use the `AsyncSandbox.create()` to create a new sandbox.
|
|
43
|
-
|
|
44
|
-
Example:
|
|
45
|
-
```python
|
|
46
|
-
from scalebox.code_interpreter import AsyncSandbox
|
|
47
|
-
sandbox = await AsyncSandbox.create()
|
|
48
|
-
```
|
|
49
|
-
"""
|
|
50
|
-
|
|
51
|
-
default_template = DEFAULT_TEMPLATE
|
|
52
|
-
|
|
53
|
-
@property
|
|
54
|
-
def _jupyter_url(self) -> str:
|
|
55
|
-
return f"{'http' if self.connection_config.debug else 'https'}://{self.get_host(JUPYTER_PORT)}"
|
|
56
|
-
|
|
57
|
-
@property
|
|
58
|
-
def _client(self) -> AsyncClient:
|
|
59
|
-
return AsyncClient(transport=self._transport)
|
|
60
|
-
|
|
61
|
-
@overload
|
|
62
|
-
async def run_code(
|
|
63
|
-
self,
|
|
64
|
-
code: str,
|
|
65
|
-
language: Union[Literal["python"], None] = None,
|
|
66
|
-
on_stdout: Optional[OutputHandler[OutputMessage]] = None,
|
|
67
|
-
on_stderr: Optional[OutputHandler[OutputMessage]] = None,
|
|
68
|
-
on_result: Optional[OutputHandler[Result]] = None,
|
|
69
|
-
on_error: Optional[OutputHandler[ExecutionError]] = None,
|
|
70
|
-
envs: Optional[Dict[str, str]] = None,
|
|
71
|
-
timeout: Optional[float] = None,
|
|
72
|
-
request_timeout: Optional[float] = None,
|
|
73
|
-
) -> Execution:
|
|
74
|
-
"""
|
|
75
|
-
Runs the code as Python.
|
|
76
|
-
|
|
77
|
-
Specify the `language` or `context` option to run the code as a different language or in a different `Context`.
|
|
78
|
-
|
|
79
|
-
You can reference previously defined variables, imports, and functions in the code.
|
|
80
|
-
|
|
81
|
-
:param code: Code to execute
|
|
82
|
-
:param language: Language to use for code execution. If not defined, the default Python context is used.
|
|
83
|
-
:param on_stdout: Callback for stdout messages
|
|
84
|
-
:param on_stderr: Callback for stderr messages
|
|
85
|
-
:param on_result: Callback for the `Result` object
|
|
86
|
-
:param on_error: Callback for the `ExecutionError` object
|
|
87
|
-
:param envs: Custom environment variables
|
|
88
|
-
:param timeout: Timeout for the code execution in **seconds**
|
|
89
|
-
:param request_timeout: Timeout for the request in **seconds**
|
|
90
|
-
|
|
91
|
-
:return: `Execution` result object
|
|
92
|
-
"""
|
|
93
|
-
...
|
|
94
|
-
|
|
95
|
-
@overload
|
|
96
|
-
async def run_code(
|
|
97
|
-
self,
|
|
98
|
-
code: str,
|
|
99
|
-
language: Optional[str] = "python",
|
|
100
|
-
on_stdout: Optional[OutputHandler[OutputMessage]] = None,
|
|
101
|
-
on_stderr: Optional[OutputHandler[OutputMessage]] = None,
|
|
102
|
-
on_result: Optional[OutputHandler[Result]] = None,
|
|
103
|
-
on_error: Optional[OutputHandler[ExecutionError]] = None,
|
|
104
|
-
envs: Optional[Dict[str, str]] = None,
|
|
105
|
-
timeout: Optional[float] = None,
|
|
106
|
-
request_timeout: Optional[float] = None,
|
|
107
|
-
) -> Execution:
|
|
108
|
-
"""
|
|
109
|
-
Runs the code for the specified language.
|
|
110
|
-
|
|
111
|
-
Specify the `language` or `context` option to run the code as a different language or in a different `Context`.
|
|
112
|
-
If no language is specified, Python is used.
|
|
113
|
-
|
|
114
|
-
You can reference previously defined variables, imports, and functions in the code.
|
|
115
|
-
|
|
116
|
-
:param code: Code to execute
|
|
117
|
-
:param language: Language to use for code execution. If not defined, the default Python context is used.
|
|
118
|
-
:param on_stdout: Callback for stdout messages
|
|
119
|
-
:param on_stderr: Callback for stderr messages
|
|
120
|
-
:param on_result: Callback for the `Result` object
|
|
121
|
-
:param on_error: Callback for the `ExecutionError` object
|
|
122
|
-
:param envs: Custom environment variables
|
|
123
|
-
:param timeout: Timeout for the code execution in **seconds**
|
|
124
|
-
:param request_timeout: Timeout for the request in **seconds**
|
|
125
|
-
|
|
126
|
-
:return: `Execution` result object
|
|
127
|
-
"""
|
|
128
|
-
...
|
|
129
|
-
|
|
130
|
-
@overload
|
|
131
|
-
async def run_code(
|
|
132
|
-
self,
|
|
133
|
-
code: str,
|
|
134
|
-
context: Optional[Context] = None,
|
|
135
|
-
on_stdout: Optional[OutputHandler[OutputMessage]] = None,
|
|
136
|
-
on_stderr: Optional[OutputHandler[OutputMessage]] = None,
|
|
137
|
-
on_result: Optional[OutputHandler[Result]] = None,
|
|
138
|
-
on_error: Optional[OutputHandler[ExecutionError]] = None,
|
|
139
|
-
envs: Optional[Dict[str, str]] = None,
|
|
140
|
-
timeout: Optional[float] = None,
|
|
141
|
-
request_timeout: Optional[float] = None,
|
|
142
|
-
) -> Execution:
|
|
143
|
-
"""
|
|
144
|
-
Runs the code in the specified context, if not specified, the default context is used.
|
|
145
|
-
|
|
146
|
-
Specify the `language` or `context` option to run the code as a different language or in a different `Context`.
|
|
147
|
-
|
|
148
|
-
You can reference previously defined variables, imports, and functions in the code.
|
|
149
|
-
|
|
150
|
-
:param code: Code to execute
|
|
151
|
-
:param context: Concrete context to run the code in. If not specified, the default context for the language is used. It's mutually exclusive with the language.
|
|
152
|
-
:param on_stdout: Callback for stdout messages
|
|
153
|
-
:param on_stderr: Callback for stderr messages
|
|
154
|
-
:param on_result: Callback for the `Result` object
|
|
155
|
-
:param on_error: Callback for the `ExecutionError` object
|
|
156
|
-
:param envs: Custom environment variables
|
|
157
|
-
:param timeout: Timeout for the code execution in **seconds**
|
|
158
|
-
:param request_timeout: Timeout for the request in **seconds**
|
|
159
|
-
|
|
160
|
-
:return: `Execution` result object
|
|
161
|
-
"""
|
|
162
|
-
...
|
|
163
|
-
|
|
164
|
-
async def run_code(
|
|
165
|
-
self,
|
|
166
|
-
code: str,
|
|
167
|
-
language: Optional[str] = None,
|
|
168
|
-
context: Optional[Context] = None,
|
|
169
|
-
on_stdout: Optional[OutputHandler[OutputMessage]] = None,
|
|
170
|
-
on_stderr: Optional[OutputHandler[OutputMessage]] = None,
|
|
171
|
-
on_result: Optional[OutputHandler[Result]] = None,
|
|
172
|
-
on_error: Optional[OutputHandler[ExecutionError]] = None,
|
|
173
|
-
envs: Optional[Dict[str, str]] = None,
|
|
174
|
-
timeout: Optional[float] = None,
|
|
175
|
-
request_timeout: Optional[float] = None,
|
|
176
|
-
) -> Execution:
|
|
177
|
-
logger.debug(f"Executing code {code}")
|
|
178
|
-
|
|
179
|
-
"""
|
|
180
|
-
Execute code in the sandbox and return the execution result.
|
|
181
|
-
"""
|
|
182
|
-
logger.debug(f"Executing code: {code}")
|
|
183
|
-
|
|
184
|
-
if context and language:
|
|
185
|
-
raise Exception(
|
|
186
|
-
"You can provide context or language, but not both at the same time."
|
|
187
|
-
)
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
# headers
|
|
209
|
-
#
|
|
210
|
-
#
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
client
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
:param
|
|
268
|
-
:param
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
#
|
|
303
|
-
#
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
"
|
|
320
|
-
"
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
#
|
|
366
|
-
#
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Dict, Literal, Optional, Union, overload
|
|
3
|
+
|
|
4
|
+
import aiohttp
|
|
5
|
+
import httpx
|
|
6
|
+
from aiohttp import TCPConnector
|
|
7
|
+
from httpx import AsyncClient
|
|
8
|
+
|
|
9
|
+
from ..connection_config import ConnectionConfig
|
|
10
|
+
from ..exceptions import InvalidArgumentException
|
|
11
|
+
from ..generated import api_pb2, api_pb2_connect
|
|
12
|
+
from ..sandbox_async.main import AsyncSandbox as BaseAsyncSandbox
|
|
13
|
+
from .constants import DEFAULT_TEMPLATE, DEFAULT_TIMEOUT, JUPYTER_PORT
|
|
14
|
+
from .exceptions import format_execution_timeout_error, format_request_timeout_error
|
|
15
|
+
from .models import (
|
|
16
|
+
Context,
|
|
17
|
+
Execution,
|
|
18
|
+
ExecutionError,
|
|
19
|
+
OutputHandler,
|
|
20
|
+
OutputMessage,
|
|
21
|
+
Result,
|
|
22
|
+
aextract_exception,
|
|
23
|
+
parse_output,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
logger = logging.getLogger(__name__)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class AsyncSandbox(BaseAsyncSandbox):
|
|
30
|
+
"""
|
|
31
|
+
Scalebox cloud sandbox is a secure and isolated cloud environment.
|
|
32
|
+
|
|
33
|
+
The sandbox allows you to:
|
|
34
|
+
- Access Linux OS
|
|
35
|
+
- Create, list, and delete files and directories
|
|
36
|
+
- Run commands
|
|
37
|
+
- Run isolated code
|
|
38
|
+
- Access the internet
|
|
39
|
+
|
|
40
|
+
Check docs for more information.
|
|
41
|
+
|
|
42
|
+
Use the `AsyncSandbox.create()` to create a new sandbox.
|
|
43
|
+
|
|
44
|
+
Example:
|
|
45
|
+
```python
|
|
46
|
+
from scalebox.code_interpreter import AsyncSandbox
|
|
47
|
+
sandbox = await AsyncSandbox.create()
|
|
48
|
+
```
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
default_template = DEFAULT_TEMPLATE
|
|
52
|
+
|
|
53
|
+
@property
|
|
54
|
+
def _jupyter_url(self) -> str:
|
|
55
|
+
return f"{'http' if self.connection_config.debug else 'https'}://{self.get_host(JUPYTER_PORT)}"
|
|
56
|
+
|
|
57
|
+
@property
|
|
58
|
+
def _client(self) -> AsyncClient:
|
|
59
|
+
return AsyncClient(transport=self._transport)
|
|
60
|
+
|
|
61
|
+
@overload
|
|
62
|
+
async def run_code(
|
|
63
|
+
self,
|
|
64
|
+
code: str,
|
|
65
|
+
language: Union[Literal["python"], None] = None,
|
|
66
|
+
on_stdout: Optional[OutputHandler[OutputMessage]] = None,
|
|
67
|
+
on_stderr: Optional[OutputHandler[OutputMessage]] = None,
|
|
68
|
+
on_result: Optional[OutputHandler[Result]] = None,
|
|
69
|
+
on_error: Optional[OutputHandler[ExecutionError]] = None,
|
|
70
|
+
envs: Optional[Dict[str, str]] = None,
|
|
71
|
+
timeout: Optional[float] = None,
|
|
72
|
+
request_timeout: Optional[float] = None,
|
|
73
|
+
) -> Execution:
|
|
74
|
+
"""
|
|
75
|
+
Runs the code as Python.
|
|
76
|
+
|
|
77
|
+
Specify the `language` or `context` option to run the code as a different language or in a different `Context`.
|
|
78
|
+
|
|
79
|
+
You can reference previously defined variables, imports, and functions in the code.
|
|
80
|
+
|
|
81
|
+
:param code: Code to execute
|
|
82
|
+
:param language: Language to use for code execution. If not defined, the default Python context is used.
|
|
83
|
+
:param on_stdout: Callback for stdout messages
|
|
84
|
+
:param on_stderr: Callback for stderr messages
|
|
85
|
+
:param on_result: Callback for the `Result` object
|
|
86
|
+
:param on_error: Callback for the `ExecutionError` object
|
|
87
|
+
:param envs: Custom environment variables
|
|
88
|
+
:param timeout: Timeout for the code execution in **seconds**
|
|
89
|
+
:param request_timeout: Timeout for the request in **seconds**
|
|
90
|
+
|
|
91
|
+
:return: `Execution` result object
|
|
92
|
+
"""
|
|
93
|
+
...
|
|
94
|
+
|
|
95
|
+
@overload
|
|
96
|
+
async def run_code(
|
|
97
|
+
self,
|
|
98
|
+
code: str,
|
|
99
|
+
language: Optional[str] = "python",
|
|
100
|
+
on_stdout: Optional[OutputHandler[OutputMessage]] = None,
|
|
101
|
+
on_stderr: Optional[OutputHandler[OutputMessage]] = None,
|
|
102
|
+
on_result: Optional[OutputHandler[Result]] = None,
|
|
103
|
+
on_error: Optional[OutputHandler[ExecutionError]] = None,
|
|
104
|
+
envs: Optional[Dict[str, str]] = None,
|
|
105
|
+
timeout: Optional[float] = None,
|
|
106
|
+
request_timeout: Optional[float] = None,
|
|
107
|
+
) -> Execution:
|
|
108
|
+
"""
|
|
109
|
+
Runs the code for the specified language.
|
|
110
|
+
|
|
111
|
+
Specify the `language` or `context` option to run the code as a different language or in a different `Context`.
|
|
112
|
+
If no language is specified, Python is used.
|
|
113
|
+
|
|
114
|
+
You can reference previously defined variables, imports, and functions in the code.
|
|
115
|
+
|
|
116
|
+
:param code: Code to execute
|
|
117
|
+
:param language: Language to use for code execution. If not defined, the default Python context is used.
|
|
118
|
+
:param on_stdout: Callback for stdout messages
|
|
119
|
+
:param on_stderr: Callback for stderr messages
|
|
120
|
+
:param on_result: Callback for the `Result` object
|
|
121
|
+
:param on_error: Callback for the `ExecutionError` object
|
|
122
|
+
:param envs: Custom environment variables
|
|
123
|
+
:param timeout: Timeout for the code execution in **seconds**
|
|
124
|
+
:param request_timeout: Timeout for the request in **seconds**
|
|
125
|
+
|
|
126
|
+
:return: `Execution` result object
|
|
127
|
+
"""
|
|
128
|
+
...
|
|
129
|
+
|
|
130
|
+
@overload
|
|
131
|
+
async def run_code(
|
|
132
|
+
self,
|
|
133
|
+
code: str,
|
|
134
|
+
context: Optional[Context] = None,
|
|
135
|
+
on_stdout: Optional[OutputHandler[OutputMessage]] = None,
|
|
136
|
+
on_stderr: Optional[OutputHandler[OutputMessage]] = None,
|
|
137
|
+
on_result: Optional[OutputHandler[Result]] = None,
|
|
138
|
+
on_error: Optional[OutputHandler[ExecutionError]] = None,
|
|
139
|
+
envs: Optional[Dict[str, str]] = None,
|
|
140
|
+
timeout: Optional[float] = None,
|
|
141
|
+
request_timeout: Optional[float] = None,
|
|
142
|
+
) -> Execution:
|
|
143
|
+
"""
|
|
144
|
+
Runs the code in the specified context, if not specified, the default context is used.
|
|
145
|
+
|
|
146
|
+
Specify the `language` or `context` option to run the code as a different language or in a different `Context`.
|
|
147
|
+
|
|
148
|
+
You can reference previously defined variables, imports, and functions in the code.
|
|
149
|
+
|
|
150
|
+
:param code: Code to execute
|
|
151
|
+
:param context: Concrete context to run the code in. If not specified, the default context for the language is used. It's mutually exclusive with the language.
|
|
152
|
+
:param on_stdout: Callback for stdout messages
|
|
153
|
+
:param on_stderr: Callback for stderr messages
|
|
154
|
+
:param on_result: Callback for the `Result` object
|
|
155
|
+
:param on_error: Callback for the `ExecutionError` object
|
|
156
|
+
:param envs: Custom environment variables
|
|
157
|
+
:param timeout: Timeout for the code execution in **seconds**
|
|
158
|
+
:param request_timeout: Timeout for the request in **seconds**
|
|
159
|
+
|
|
160
|
+
:return: `Execution` result object
|
|
161
|
+
"""
|
|
162
|
+
...
|
|
163
|
+
|
|
164
|
+
async def run_code(
|
|
165
|
+
self,
|
|
166
|
+
code: str,
|
|
167
|
+
language: Optional[str] = None,
|
|
168
|
+
context: Optional[Context] = None,
|
|
169
|
+
on_stdout: Optional[OutputHandler[OutputMessage]] = None,
|
|
170
|
+
on_stderr: Optional[OutputHandler[OutputMessage]] = None,
|
|
171
|
+
on_result: Optional[OutputHandler[Result]] = None,
|
|
172
|
+
on_error: Optional[OutputHandler[ExecutionError]] = None,
|
|
173
|
+
envs: Optional[Dict[str, str]] = None,
|
|
174
|
+
timeout: Optional[float] = None,
|
|
175
|
+
request_timeout: Optional[float] = None,
|
|
176
|
+
) -> Execution:
|
|
177
|
+
logger.debug(f"Executing code {code}")
|
|
178
|
+
|
|
179
|
+
"""
|
|
180
|
+
Execute code in the sandbox and return the execution result.
|
|
181
|
+
"""
|
|
182
|
+
logger.debug(f"Executing code: {code}")
|
|
183
|
+
|
|
184
|
+
if context and language:
|
|
185
|
+
raise Exception(
|
|
186
|
+
"You can provide context or language, but not both at the same time."
|
|
187
|
+
)
|
|
188
|
+
if language is None and context is None:
|
|
189
|
+
language = "python"
|
|
190
|
+
# timeout = None if timeout == 0 else (timeout or 30)
|
|
191
|
+
request_timeout = request_timeout or self._connection_config.request_timeout
|
|
192
|
+
context_id = context.id if context else None
|
|
193
|
+
|
|
194
|
+
# Ensure session exists
|
|
195
|
+
if not self._session or self._session.closed:
|
|
196
|
+
connector = aiohttp.TCPConnector(
|
|
197
|
+
limit=100,
|
|
198
|
+
limit_per_host=20,
|
|
199
|
+
keepalive_timeout=30,
|
|
200
|
+
enable_cleanup_closed=True,
|
|
201
|
+
ssl=False,
|
|
202
|
+
)
|
|
203
|
+
self._session = aiohttp.ClientSession(
|
|
204
|
+
connector=connector,
|
|
205
|
+
timeout=aiohttp.ClientTimeout(total=request_timeout),
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
# Set headers
|
|
209
|
+
# headers = {
|
|
210
|
+
# "Authorization": "Bearer root",
|
|
211
|
+
# }
|
|
212
|
+
|
|
213
|
+
try:
|
|
214
|
+
# Create client and execute request
|
|
215
|
+
client = api_pb2_connect.AsyncExecutionServiceClient(
|
|
216
|
+
http_client=self._session,
|
|
217
|
+
base_url=self.envd_api_url,
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
# Build request
|
|
221
|
+
request = api_pb2.ExecuteRequest(
|
|
222
|
+
code=code,
|
|
223
|
+
language=language or "",
|
|
224
|
+
context_id=context_id or "",
|
|
225
|
+
env_vars=envs or {},
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
# Execute request and get response stream
|
|
229
|
+
responses = client.execute(
|
|
230
|
+
req=request,
|
|
231
|
+
extra_headers=self.connection_config.headers,
|
|
232
|
+
timeout_seconds=request_timeout,
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
execution = Execution()
|
|
236
|
+
|
|
237
|
+
# Process response stream
|
|
238
|
+
async for response in responses:
|
|
239
|
+
parse_output(
|
|
240
|
+
execution,
|
|
241
|
+
response,
|
|
242
|
+
on_stdout=on_stdout,
|
|
243
|
+
on_stderr=on_stderr,
|
|
244
|
+
on_result=on_result,
|
|
245
|
+
on_error=on_error,
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
return execution
|
|
249
|
+
|
|
250
|
+
except Exception as e:
|
|
251
|
+
# Handle exception
|
|
252
|
+
logger.error(f"Error executing code: {e}")
|
|
253
|
+
raise
|
|
254
|
+
finally:
|
|
255
|
+
# Don't close session here, let context manager handle it
|
|
256
|
+
pass
|
|
257
|
+
|
|
258
|
+
async def create_code_context(
|
|
259
|
+
self,
|
|
260
|
+
cwd: Optional[str] = None,
|
|
261
|
+
language: Optional[str] = None,
|
|
262
|
+
request_timeout: Optional[float] = None,
|
|
263
|
+
) -> Context:
|
|
264
|
+
"""
|
|
265
|
+
Creates a new context to run code in.
|
|
266
|
+
|
|
267
|
+
:param cwd: Set the current working directory for the context, defaults to `/home/user`
|
|
268
|
+
:param language: Language of the context. If not specified, defaults to Python
|
|
269
|
+
:param request_timeout: Timeout for the request in **milliseconds**
|
|
270
|
+
|
|
271
|
+
:return: Context object
|
|
272
|
+
"""
|
|
273
|
+
logger.debug(f"Creating new {language} context")
|
|
274
|
+
|
|
275
|
+
request_timeout = request_timeout or self._connection_config.request_timeout
|
|
276
|
+
|
|
277
|
+
# Ensure session exists
|
|
278
|
+
if not self._session or self._session.closed:
|
|
279
|
+
connector = aiohttp.TCPConnector(
|
|
280
|
+
limit=100,
|
|
281
|
+
limit_per_host=20,
|
|
282
|
+
keepalive_timeout=30,
|
|
283
|
+
enable_cleanup_closed=True,
|
|
284
|
+
ssl=False,
|
|
285
|
+
)
|
|
286
|
+
self._session = aiohttp.ClientSession(
|
|
287
|
+
connector=connector,
|
|
288
|
+
timeout=aiohttp.ClientTimeout(total=request_timeout),
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
data = {}
|
|
292
|
+
if language:
|
|
293
|
+
data["language"] = language
|
|
294
|
+
if cwd:
|
|
295
|
+
data["cwd"] = cwd
|
|
296
|
+
|
|
297
|
+
try:
|
|
298
|
+
client = api_pb2_connect.AsyncContextServiceClient(
|
|
299
|
+
http_client=self._session,
|
|
300
|
+
base_url=self.envd_api_url,
|
|
301
|
+
)
|
|
302
|
+
# headers = {
|
|
303
|
+
# "Authorization": "Bearer root",
|
|
304
|
+
# }
|
|
305
|
+
|
|
306
|
+
# Build request
|
|
307
|
+
request = api_pb2.CreateContextRequest(
|
|
308
|
+
language=language or "",
|
|
309
|
+
cwd=cwd or "",
|
|
310
|
+
)
|
|
311
|
+
|
|
312
|
+
# Execute request and get response stream
|
|
313
|
+
response = await client.create_context(
|
|
314
|
+
req=request,
|
|
315
|
+
extra_headers=self.connection_config.headers,
|
|
316
|
+
)
|
|
317
|
+
return Context.from_json(
|
|
318
|
+
{
|
|
319
|
+
"id": response.id,
|
|
320
|
+
"language": response.language,
|
|
321
|
+
"cwd": response.cwd,
|
|
322
|
+
}
|
|
323
|
+
)
|
|
324
|
+
except Exception as e:
|
|
325
|
+
logger.error(f"Error create_code_context: {e}")
|
|
326
|
+
raise e
|
|
327
|
+
finally:
|
|
328
|
+
# Don't close session here, let context manager handle it
|
|
329
|
+
pass
|
|
330
|
+
|
|
331
|
+
async def destroy_context(self, context: Context) -> None:
|
|
332
|
+
"""
|
|
333
|
+
Destroys a context.
|
|
334
|
+
|
|
335
|
+
:param context: Context to destroy
|
|
336
|
+
"""
|
|
337
|
+
logger.debug(f"Destroying context {context.id}")
|
|
338
|
+
|
|
339
|
+
request_timeout = self._connection_config.request_timeout
|
|
340
|
+
|
|
341
|
+
# Ensure session exists
|
|
342
|
+
if not self._session or self._session.closed:
|
|
343
|
+
connector = aiohttp.TCPConnector(
|
|
344
|
+
limit=100,
|
|
345
|
+
limit_per_host=20,
|
|
346
|
+
keepalive_timeout=30,
|
|
347
|
+
enable_cleanup_closed=True,
|
|
348
|
+
ssl=False,
|
|
349
|
+
)
|
|
350
|
+
self._session = aiohttp.ClientSession(
|
|
351
|
+
connector=connector,
|
|
352
|
+
timeout=aiohttp.ClientTimeout(total=request_timeout),
|
|
353
|
+
)
|
|
354
|
+
|
|
355
|
+
# Create destroy context request
|
|
356
|
+
destroy_context_request = api_pb2.DestroyContextRequest(
|
|
357
|
+
context_id=context.id,
|
|
358
|
+
)
|
|
359
|
+
|
|
360
|
+
try:
|
|
361
|
+
client = api_pb2_connect.AsyncContextServiceClient(
|
|
362
|
+
base_url=self.envd_api_url,
|
|
363
|
+
http_client=self._session,
|
|
364
|
+
)
|
|
365
|
+
# headers = {
|
|
366
|
+
# "Authorization": "Bearer root",
|
|
367
|
+
# }
|
|
368
|
+
await client.destroy_context(destroy_context_request,extra_headers=self.connection_config.headers)
|
|
369
|
+
except Exception as e:
|
|
370
|
+
logger.warning(f"Failed to destroy context {context.id}: {e}")
|