-
Notifications
You must be signed in to change notification settings - Fork 204
Expand file tree
/
Copy pathcode_interpreter_sync.py
More file actions
358 lines (297 loc) · 11.9 KB
/
code_interpreter_sync.py
File metadata and controls
358 lines (297 loc) · 11.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
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
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
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
268
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
import logging
import httpx
from typing import Optional, Dict, overload, Literal, Union, List
from httpx import Client
from e2b import Sandbox as BaseSandbox, InvalidArgumentException
from e2b_code_interpreter.constants import (
DEFAULT_TEMPLATE,
JUPYTER_PORT,
DEFAULT_TIMEOUT,
)
from e2b_code_interpreter.models import (
ExecutionError,
Execution,
Context,
Result,
extract_exception,
parse_output,
OutputHandler,
OutputMessage,
)
from e2b_code_interpreter.exceptions import (
format_execution_timeout_error,
format_request_timeout_error,
)
logger = logging.getLogger(__name__)
class Sandbox(BaseSandbox):
"""
E2B cloud sandbox is a secure and isolated cloud environment.
The sandbox allows you to:
- Access Linux OS
- Create, list, and delete files and directories
- Run commands
- Run isolated code
- Access the internet
Check docs [here](https://e2b.dev/docs).
Use the `Sandbox.create()` to create a new sandbox.
Example:
```python
from e2b_code_interpreter import Sandbox
sandbox = Sandbox.create()
```
"""
default_template = DEFAULT_TEMPLATE
@property
def _jupyter_url(self) -> str:
return f"{'http' if self.connection_config.debug else 'https'}://{self.get_host(JUPYTER_PORT)}"
@property
def _client(self) -> Client:
return Client(transport=self._transport)
@overload
def run_code(
self,
code: str,
language: Union[Literal["python"], None] = None,
on_stdout: Optional[OutputHandler[OutputMessage]] = None,
on_stderr: Optional[OutputHandler[OutputMessage]] = None,
on_result: Optional[OutputHandler[Result]] = None,
on_error: Optional[OutputHandler[ExecutionError]] = None,
envs: Optional[Dict[str, str]] = None,
timeout: Optional[float] = None,
request_timeout: Optional[float] = None,
) -> Execution:
"""
Runs the code as Python.
Specify the `language` or `context` option to run the code as a different language or in a different `Context`.
You can reference previously defined variables, imports, and functions in the code.
:param code: Code to execute
:param language: Language to use for code execution. If not defined, the default Python context is used.
:param on_stdout: Callback for stdout messages
:param on_stderr: Callback for stderr messages
:param on_result: Callback for the `Result` object
:param on_error: Callback for the `ExecutionError` object
:param envs: Custom environment variables
:param timeout: Timeout for the code execution in **seconds**
:param request_timeout: Timeout for the request in **seconds**
:return: `Execution` result object
"""
...
@overload
def run_code(
self,
code: str,
language: Optional[str] = None,
on_stdout: Optional[OutputHandler[OutputMessage]] = None,
on_stderr: Optional[OutputHandler[OutputMessage]] = None,
on_result: Optional[OutputHandler[Result]] = None,
on_error: Optional[OutputHandler[ExecutionError]] = None,
envs: Optional[Dict[str, str]] = None,
timeout: Optional[float] = None,
request_timeout: Optional[float] = None,
) -> Execution:
"""
Runs the code for the specified language.
Specify the `language` or `context` option to run the code as a different language or in a different `Context`.
If no language is specified, Python is used.
You can reference previously defined variables, imports, and functions in the code.
:param code: Code to execute
:param language: Language to use for code execution. If not defined, the default Python context is used.
:param on_stdout: Callback for stdout messages
:param on_stderr: Callback for stderr messages
:param on_result: Callback for the `Result` object
:param on_error: Callback for the `ExecutionError` object
:param envs: Custom environment variables
:param timeout: Timeout for the code execution in **seconds**
:param request_timeout: Timeout for the request in **seconds**
:return: `Execution` result object
"""
...
@overload
def run_code(
self,
code: str,
context: Optional[Context] = None,
on_stdout: Optional[OutputHandler[OutputMessage]] = None,
on_stderr: Optional[OutputHandler[OutputMessage]] = None,
on_result: Optional[OutputHandler[Result]] = None,
on_error: Optional[OutputHandler[ExecutionError]] = None,
envs: Optional[Dict[str, str]] = None,
timeout: Optional[float] = None,
request_timeout: Optional[float] = None,
) -> Execution:
"""
Runs the code in the specified context, if not specified, the default context is used.
Specify the `language` or `context` option to run the code as a different language or in a different `Context`.
You can reference previously defined variables, imports, and functions in the code.
:param code: Code to execute
: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.
:param on_stdout: Callback for stdout messages
:param on_stderr: Callback for stderr messages
:param on_result: Callback for the `Result` object
:param on_error: Callback for the `ExecutionError` object
:param envs: Custom environment variables
:param timeout: Timeout for the code execution in **seconds**
:param request_timeout: Timeout for the request in **seconds**
:return: `Execution` result object
"""
...
def run_code(
self,
code: str,
language: Optional[str] = None,
context: Optional[Context] = None,
on_stdout: Optional[OutputHandler[OutputMessage]] = None,
on_stderr: Optional[OutputHandler[OutputMessage]] = None,
on_result: Optional[OutputHandler[Result]] = None,
on_error: Optional[OutputHandler[ExecutionError]] = None,
envs: Optional[Dict[str, str]] = None,
timeout: Optional[float] = None,
request_timeout: Optional[float] = None,
) -> Execution:
logger.debug(f"Executing code {code}")
if language and context:
raise InvalidArgumentException(
"You can provide context or language, but not both at the same time."
)
timeout = None if timeout == 0 else (timeout or DEFAULT_TIMEOUT)
request_timeout = request_timeout or self.connection_config.request_timeout
context_id = context.id if context else None
headers: Dict[str, str] = {}
if self._envd_access_token:
headers = {"X-Access-Token": self._envd_access_token}
try:
with self._client.stream(
"POST",
f"{self._jupyter_url}/execute",
json={
"code": code,
"context_id": context_id,
"language": language,
"env_vars": envs,
},
headers=headers,
timeout=(request_timeout, timeout, request_timeout, request_timeout),
) as response:
err = extract_exception(response)
if err:
raise err
execution = Execution()
for line in response.iter_lines():
parse_output(
execution,
line,
on_stdout=on_stdout,
on_stderr=on_stderr,
on_result=on_result,
on_error=on_error,
)
return execution
except httpx.ReadTimeout:
raise format_execution_timeout_error()
except httpx.TimeoutException:
raise format_request_timeout_error()
def create_code_context(
self,
cwd: Optional[str] = None,
language: Optional[str] = None,
request_timeout: Optional[float] = None,
) -> Context:
"""
Creates a new context to run code in.
:param cwd: Set the current working directory for the context, defaults to `/home/user`
:param language: Language of the context. If not specified, defaults to Python
:param request_timeout: Timeout for the request in **milliseconds**
:return: Context object
"""
logger.debug(f"Creating new {language} context")
data = {}
if language:
data["language"] = language
if cwd:
data["cwd"] = cwd
headers: Dict[str, str] = {}
if self._envd_access_token:
headers = {"X-Access-Token": self._envd_access_token}
try:
response = self._client.post(
f"{self._jupyter_url}/contexts",
json=data,
headers=headers,
timeout=request_timeout or self.connection_config.request_timeout,
)
err = extract_exception(response)
if err:
raise err
data = response.json()
return Context.from_json(data)
except httpx.TimeoutException:
raise format_request_timeout_error()
def remove_code_context(
self,
context: Union[Context, str],
) -> None:
"""
Removes a context.
:param context: Context to remove. Can be a Context object or a context ID string.
:return: None
"""
context_id = context.id if isinstance(context, Context) else context
headers: Dict[str, str] = {}
if self._envd_access_token:
headers = {"X-Access-Token": self._envd_access_token}
try:
response = self._client.delete(
f"{self._jupyter_url}/contexts/{context_id}",
headers=headers,
timeout=self.connection_config.request_timeout,
)
err = extract_exception(response)
if err:
raise err
except httpx.TimeoutException:
raise format_request_timeout_error()
def list_code_contexts(self) -> List[Context]:
"""
List all contexts.
:return: List of contexts.
"""
headers: Dict[str, str] = {}
if self._envd_access_token:
headers = {"X-Access-Token": self._envd_access_token}
try:
response = self._client.get(
f"{self._jupyter_url}/contexts",
headers=headers,
timeout=self.connection_config.request_timeout,
)
err = extract_exception(response)
if err:
raise err
data = response.json()
return [Context.from_json(context_data) for context_data in data]
except httpx.TimeoutException:
raise format_request_timeout_error()
def restart_code_context(
self,
context: Union[Context, str],
) -> None:
"""
Restart a context.
:param context: Context to restart. Can be a Context object or a context ID string.
:return: None
"""
context_id = context.id if isinstance(context, Context) else context
headers: Dict[str, str] = {}
if self._envd_access_token:
headers = {"X-Access-Token": self._envd_access_token}
try:
response = self._client.post(
f"{self._jupyter_url}/contexts/{context_id}/restart",
headers=headers,
timeout=self.connection_config.request_timeout,
)
err = extract_exception(response)
if err:
raise err
except httpx.TimeoutException:
raise format_request_timeout_error()