e2b-code-interpreter 0.0.1a0__tar.gz → 0.0.1a2__tar.gz
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.
- {e2b_code_interpreter-0.0.1a0 → e2b_code_interpreter-0.0.1a2}/PKG-INFO +21 -16
- {e2b_code_interpreter-0.0.1a0 → e2b_code_interpreter-0.0.1a2}/README.md +19 -15
- e2b_code_interpreter-0.0.1a2/e2b_code_interpreter/__init__.py +2 -0
- {e2b_code_interpreter-0.0.1a0 → e2b_code_interpreter-0.0.1a2}/e2b_code_interpreter/main.py +6 -3
- {e2b_code_interpreter-0.0.1a0 → e2b_code_interpreter-0.0.1a2}/e2b_code_interpreter/messaging.py +22 -18
- {e2b_code_interpreter-0.0.1a0 → e2b_code_interpreter-0.0.1a2}/e2b_code_interpreter/models.py +7 -7
- {e2b_code_interpreter-0.0.1a0 → e2b_code_interpreter-0.0.1a2}/pyproject.toml +1 -1
- e2b_code_interpreter-0.0.1a0/e2b_code_interpreter/__init__.py +0 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: e2b-code-interpreter
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.1a2
|
|
4
4
|
Summary: E2B Code Interpreter - Stateful code execution
|
|
5
5
|
Home-page: https://e2b.dev/
|
|
6
6
|
License: Apache-2.0
|
|
@@ -13,6 +13,7 @@ Classifier: Programming Language :: Python :: 3.8
|
|
|
13
13
|
Classifier: Programming Language :: Python :: 3.9
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.10
|
|
15
15
|
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
17
|
Requires-Dist: e2b (>=0.14.11)
|
|
17
18
|
Requires-Dist: pydantic (>1,<3)
|
|
18
19
|
Requires-Dist: websocket-client (>=1.7.0,<2.0.0)
|
|
@@ -43,10 +44,10 @@ pip install e2b-code-interpreter
|
|
|
43
44
|
from e2b_code_interpreter import CodeInterpreter
|
|
44
45
|
|
|
45
46
|
with CodeInterpreter() as sandbox:
|
|
46
|
-
sandbox.exec_cell("x = 1")
|
|
47
|
+
sandbox.notebook.exec_cell("x = 1")
|
|
47
48
|
|
|
48
|
-
|
|
49
|
-
print(
|
|
49
|
+
execution = sandbox.notebook.exec_cell("x+=1; x")
|
|
50
|
+
print(execution.text) # outputs 2
|
|
50
51
|
|
|
51
52
|
```
|
|
52
53
|
|
|
@@ -73,21 +74,21 @@ plt.show()
|
|
|
73
74
|
|
|
74
75
|
with CodeInterpreter() as sandbox:
|
|
75
76
|
# you can install dependencies in "jupyter notebook style"
|
|
76
|
-
sandbox.exec_cell("!pip install matplotlib")
|
|
77
|
+
sandbox.notebook.exec_cell("!pip install matplotlib")
|
|
77
78
|
|
|
78
79
|
# plot random graph
|
|
79
|
-
|
|
80
|
+
execution = sandbox.notebook.exec_cell(code)
|
|
80
81
|
|
|
81
|
-
|
|
82
|
-
|
|
82
|
+
# there's your image
|
|
83
|
+
image = execution.results[0].png
|
|
83
84
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
85
|
+
# example how to show the image / prove it works
|
|
86
|
+
i = base64.b64decode(image)
|
|
87
|
+
i = io.BytesIO(i)
|
|
88
|
+
i = mpimg.imread(i, format='PNG')
|
|
88
89
|
|
|
89
|
-
|
|
90
|
-
|
|
90
|
+
plt.imshow(i, interpolation='nearest')
|
|
91
|
+
plt.show()
|
|
91
92
|
```
|
|
92
93
|
|
|
93
94
|
### Streaming code output
|
|
@@ -97,14 +98,18 @@ from e2b_code_interpreter import CodeInterpreter
|
|
|
97
98
|
|
|
98
99
|
code = """
|
|
99
100
|
import time
|
|
101
|
+
import pandas as pd
|
|
100
102
|
|
|
101
103
|
print("hello")
|
|
102
|
-
time.sleep(
|
|
104
|
+
time.sleep(3)
|
|
105
|
+
data = pd.DataFrame(data=[[1, 2], [3, 4]], columns=["A", "B"])
|
|
106
|
+
display(data.head(10))
|
|
107
|
+
time.sleep(3)
|
|
103
108
|
print("world")
|
|
104
109
|
"""
|
|
105
110
|
|
|
106
111
|
with CodeInterpreter() as sandbox:
|
|
107
|
-
sandbox.exec_cell(code, on_stdout=print, on_stderr=print)
|
|
112
|
+
sandbox.notebook.exec_cell(code, on_stdout=print, on_stderr=print, on_display_data=(lambda data: print(data.text)))
|
|
108
113
|
```
|
|
109
114
|
|
|
110
115
|
### Pre-installed Python packages inside the sandbox
|
|
@@ -21,10 +21,10 @@ pip install e2b-code-interpreter
|
|
|
21
21
|
from e2b_code_interpreter import CodeInterpreter
|
|
22
22
|
|
|
23
23
|
with CodeInterpreter() as sandbox:
|
|
24
|
-
sandbox.exec_cell("x = 1")
|
|
24
|
+
sandbox.notebook.exec_cell("x = 1")
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
print(
|
|
26
|
+
execution = sandbox.notebook.exec_cell("x+=1; x")
|
|
27
|
+
print(execution.text) # outputs 2
|
|
28
28
|
|
|
29
29
|
```
|
|
30
30
|
|
|
@@ -51,21 +51,21 @@ plt.show()
|
|
|
51
51
|
|
|
52
52
|
with CodeInterpreter() as sandbox:
|
|
53
53
|
# you can install dependencies in "jupyter notebook style"
|
|
54
|
-
sandbox.exec_cell("!pip install matplotlib")
|
|
54
|
+
sandbox.notebook.exec_cell("!pip install matplotlib")
|
|
55
55
|
|
|
56
56
|
# plot random graph
|
|
57
|
-
|
|
57
|
+
execution = sandbox.notebook.exec_cell(code)
|
|
58
58
|
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
# there's your image
|
|
60
|
+
image = execution.results[0].png
|
|
61
61
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
62
|
+
# example how to show the image / prove it works
|
|
63
|
+
i = base64.b64decode(image)
|
|
64
|
+
i = io.BytesIO(i)
|
|
65
|
+
i = mpimg.imread(i, format='PNG')
|
|
66
66
|
|
|
67
|
-
|
|
68
|
-
|
|
67
|
+
plt.imshow(i, interpolation='nearest')
|
|
68
|
+
plt.show()
|
|
69
69
|
```
|
|
70
70
|
|
|
71
71
|
### Streaming code output
|
|
@@ -75,14 +75,18 @@ from e2b_code_interpreter import CodeInterpreter
|
|
|
75
75
|
|
|
76
76
|
code = """
|
|
77
77
|
import time
|
|
78
|
+
import pandas as pd
|
|
78
79
|
|
|
79
80
|
print("hello")
|
|
80
|
-
time.sleep(
|
|
81
|
+
time.sleep(3)
|
|
82
|
+
data = pd.DataFrame(data=[[1, 2], [3, 4]], columns=["A", "B"])
|
|
83
|
+
display(data.head(10))
|
|
84
|
+
time.sleep(3)
|
|
81
85
|
print("world")
|
|
82
86
|
"""
|
|
83
87
|
|
|
84
88
|
with CodeInterpreter() as sandbox:
|
|
85
|
-
sandbox.exec_cell(code, on_stdout=print, on_stderr=print)
|
|
89
|
+
sandbox.notebook.exec_cell(code, on_stdout=print, on_stderr=print, on_display_data=(lambda data: print(data.text)))
|
|
86
90
|
```
|
|
87
91
|
|
|
88
92
|
### Pre-installed Python packages inside the sandbox
|
|
@@ -10,7 +10,7 @@ from e2b import EnvVars, ProcessMessage, Sandbox
|
|
|
10
10
|
from e2b.constants import TIMEOUT
|
|
11
11
|
|
|
12
12
|
from e2b_code_interpreter.messaging import JupyterKernelWebSocket
|
|
13
|
-
from e2b_code_interpreter.models import KernelException,
|
|
13
|
+
from e2b_code_interpreter.models import KernelException, Execution
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
logger = logging.getLogger(__name__)
|
|
@@ -68,7 +68,7 @@ class JupyterExtension:
|
|
|
68
68
|
on_stderr: Optional[Callable[[ProcessMessage], Any]] = None,
|
|
69
69
|
on_display_data: Optional[Callable[[Dict[str, Any]], Any]] = None,
|
|
70
70
|
timeout: Optional[float] = TIMEOUT,
|
|
71
|
-
) ->
|
|
71
|
+
) -> Execution:
|
|
72
72
|
"""
|
|
73
73
|
Execute code in a notebook cell.
|
|
74
74
|
|
|
@@ -93,7 +93,9 @@ class JupyterExtension:
|
|
|
93
93
|
logger.debug(f"Creating new websocket connection to kernel {kernel_id}")
|
|
94
94
|
ws = self._connect_to_kernel_ws(kernel_id, timeout=timeout)
|
|
95
95
|
|
|
96
|
-
session_id = ws.send_execution_message(
|
|
96
|
+
session_id = ws.send_execution_message(
|
|
97
|
+
code, on_stdout, on_stderr, on_display_data
|
|
98
|
+
)
|
|
97
99
|
logger.debug(
|
|
98
100
|
f"Sent execution message to kernel {kernel_id}, session_id: {session_id}"
|
|
99
101
|
)
|
|
@@ -282,6 +284,7 @@ class JupyterExtension:
|
|
|
282
284
|
if kernel_id is None and not self._sandbox.is_open:
|
|
283
285
|
return
|
|
284
286
|
|
|
287
|
+
kernel_id = kernel_id.strip()
|
|
285
288
|
logger.debug(f"Default kernel id: {kernel_id}")
|
|
286
289
|
self._connect_to_kernel_ws(kernel_id, timeout=timeout)
|
|
287
290
|
self._kernel_id_set.set_result(kernel_id)
|
{e2b_code_interpreter-0.0.1a0 → e2b_code_interpreter-0.0.1a2}/e2b_code_interpreter/messaging.py
RENAMED
|
@@ -14,7 +14,7 @@ from e2b.sandbox.websocket_client import WebSocket
|
|
|
14
14
|
from e2b.utils.future import DeferredFuture
|
|
15
15
|
from pydantic import ConfigDict, PrivateAttr, BaseModel
|
|
16
16
|
|
|
17
|
-
from e2b_code_interpreter.models import
|
|
17
|
+
from e2b_code_interpreter.models import Execution, Result, Error, MIMEType
|
|
18
18
|
|
|
19
19
|
logger = logging.getLogger(__name__)
|
|
20
20
|
|
|
@@ -36,8 +36,8 @@ class CellExecution:
|
|
|
36
36
|
on_stderr: Optional[Callable[[ProcessMessage], None]] = None,
|
|
37
37
|
on_display_data: Optional[Callable[[Dict[MIMEType, str]], None]] = None,
|
|
38
38
|
):
|
|
39
|
-
self.partial_result =
|
|
40
|
-
self.
|
|
39
|
+
self.partial_result = Execution()
|
|
40
|
+
self.execution = Future()
|
|
41
41
|
self.on_stdout = on_stdout
|
|
42
42
|
self.on_stderr = on_stderr
|
|
43
43
|
self.on_display_data = on_display_data
|
|
@@ -145,8 +145,10 @@ class JupyterKernelWebSocket(BaseModel):
|
|
|
145
145
|
self._queue_in.put(request)
|
|
146
146
|
return message_id
|
|
147
147
|
|
|
148
|
-
def get_result(
|
|
149
|
-
|
|
148
|
+
def get_result(
|
|
149
|
+
self, message_id: str, timeout: Optional[float] = TIMEOUT
|
|
150
|
+
) -> Execution:
|
|
151
|
+
result = self._cells[message_id].execution.result(timeout=timeout)
|
|
150
152
|
logger.debug(f"Got result for message: {message_id}")
|
|
151
153
|
del self._cells[message_id]
|
|
152
154
|
return result
|
|
@@ -167,11 +169,11 @@ class JupyterKernelWebSocket(BaseModel):
|
|
|
167
169
|
if not cell:
|
|
168
170
|
return
|
|
169
171
|
|
|
170
|
-
|
|
172
|
+
execution = cell.partial_result
|
|
171
173
|
|
|
172
174
|
if data["msg_type"] == "error":
|
|
173
175
|
logger.debug(f"Cell {parent_msg_ig} finished execution with error")
|
|
174
|
-
|
|
176
|
+
execution.error = Error(
|
|
175
177
|
name=data["content"]["ename"],
|
|
176
178
|
value=data["content"]["evalue"],
|
|
177
179
|
traceback_raw=data["content"]["traceback"],
|
|
@@ -179,7 +181,7 @@ class JupyterKernelWebSocket(BaseModel):
|
|
|
179
181
|
|
|
180
182
|
elif data["msg_type"] == "stream":
|
|
181
183
|
if data["content"]["name"] == "stdout":
|
|
182
|
-
|
|
184
|
+
execution.logs.stdout.append(data["content"]["text"])
|
|
183
185
|
if cell.on_stdout:
|
|
184
186
|
cell.on_stdout(
|
|
185
187
|
ProcessMessage(
|
|
@@ -189,7 +191,7 @@ class JupyterKernelWebSocket(BaseModel):
|
|
|
189
191
|
)
|
|
190
192
|
|
|
191
193
|
elif data["content"]["name"] == "stderr":
|
|
192
|
-
|
|
194
|
+
execution.logs.stderr.append(data["content"]["text"])
|
|
193
195
|
if cell.on_stderr:
|
|
194
196
|
cell.on_stderr(
|
|
195
197
|
ProcessMessage(
|
|
@@ -200,30 +202,33 @@ class JupyterKernelWebSocket(BaseModel):
|
|
|
200
202
|
)
|
|
201
203
|
|
|
202
204
|
elif data["msg_type"] in "display_data":
|
|
203
|
-
result
|
|
205
|
+
result = Result(is_main_result=False, data=data["content"]["data"])
|
|
206
|
+
execution.results.append(result)
|
|
204
207
|
if cell.on_display_data:
|
|
205
|
-
cell.on_display_data(
|
|
208
|
+
cell.on_display_data(result)
|
|
206
209
|
elif data["msg_type"] == "execute_result":
|
|
207
|
-
|
|
210
|
+
execution.results.append(
|
|
211
|
+
Result(is_main_result=True, data=data["content"]["data"])
|
|
212
|
+
)
|
|
208
213
|
elif data["msg_type"] == "status":
|
|
209
214
|
if data["content"]["execution_state"] == "idle":
|
|
210
215
|
if cell.input_accepted:
|
|
211
216
|
logger.debug(f"Cell {parent_msg_ig} finished execution")
|
|
212
|
-
cell.
|
|
217
|
+
cell.execution.set_result(execution)
|
|
213
218
|
|
|
214
219
|
elif data["content"]["execution_state"] == "error":
|
|
215
220
|
logger.debug(f"Cell {parent_msg_ig} finished execution with error")
|
|
216
|
-
|
|
221
|
+
execution.error = Error(
|
|
217
222
|
name=data["content"]["ename"],
|
|
218
223
|
value=data["content"]["evalue"],
|
|
219
224
|
traceback_raw=data["content"]["traceback"],
|
|
220
225
|
)
|
|
221
|
-
cell.
|
|
226
|
+
cell.execution.set_result(execution)
|
|
222
227
|
|
|
223
228
|
elif data["msg_type"] == "execute_reply":
|
|
224
229
|
if data["content"]["status"] == "error":
|
|
225
230
|
logger.debug(f"Cell {parent_msg_ig} finished execution with error")
|
|
226
|
-
|
|
231
|
+
execution.error = Error(
|
|
227
232
|
name=data["content"]["ename"],
|
|
228
233
|
value=data["content"]["evalue"],
|
|
229
234
|
traceback_raw=data["content"]["traceback"],
|
|
@@ -235,8 +240,7 @@ class JupyterKernelWebSocket(BaseModel):
|
|
|
235
240
|
logger.debug(f"Input accepted for {parent_msg_ig}")
|
|
236
241
|
cell.input_accepted = True
|
|
237
242
|
else:
|
|
238
|
-
logger.
|
|
239
|
-
print("[UNHANDLED MESSAGE TYPE]:", data["msg_type"])
|
|
243
|
+
logger.warning(f"[UNHANDLED MESSAGE TYPE]: {data['msg_type']}")
|
|
240
244
|
|
|
241
245
|
def close(self):
|
|
242
246
|
logger.debug("Closing WebSocket")
|
{e2b_code_interpreter-0.0.1a0 → e2b_code_interpreter-0.0.1a2}/e2b_code_interpreter/models.py
RENAMED
|
@@ -32,20 +32,20 @@ class MIMEType(str):
|
|
|
32
32
|
"""
|
|
33
33
|
|
|
34
34
|
|
|
35
|
-
class
|
|
35
|
+
class Result:
|
|
36
36
|
"""
|
|
37
37
|
Represents the data to be displayed as a result of executing a cell in a Jupyter notebook.
|
|
38
38
|
This is result returned by ipython kernel: https://ipython.readthedocs.io/en/stable/development/execution.html#execution-semantics
|
|
39
39
|
|
|
40
|
-
|
|
41
40
|
The result can contain multiple types of data, such as text, images, plots, etc. Each type of data is represented
|
|
42
41
|
as a string, and the result can contain multiple types of data. The text representation is always present, and
|
|
43
42
|
the other representations are optional.
|
|
44
43
|
|
|
45
44
|
The class also provides methods to display the data in a Jupyter notebook.
|
|
46
45
|
"""
|
|
46
|
+
|
|
47
47
|
text: str
|
|
48
|
-
"Text representation of the
|
|
48
|
+
"Text representation of the result. Always present."
|
|
49
49
|
html: Optional[str] = None
|
|
50
50
|
markdown: Optional[str] = None
|
|
51
51
|
svg: Optional[str] = None
|
|
@@ -180,7 +180,7 @@ class Logs(BaseModel):
|
|
|
180
180
|
"List of strings printed to stderr by prints, subprocesses, etc."
|
|
181
181
|
|
|
182
182
|
|
|
183
|
-
class
|
|
183
|
+
class Execution(BaseModel):
|
|
184
184
|
"""
|
|
185
185
|
Represents the result of a cell execution.
|
|
186
186
|
"""
|
|
@@ -188,8 +188,8 @@ class Result(BaseModel):
|
|
|
188
188
|
class Config:
|
|
189
189
|
arbitrary_types_allowed = True
|
|
190
190
|
|
|
191
|
-
|
|
192
|
-
"List of result of the cell (interactively interpreted last line), display calls
|
|
191
|
+
results: List[Result] = []
|
|
192
|
+
"List of the result of the cell (interactively interpreted last line), display calls (e.g. matplotlib plots)."
|
|
193
193
|
logs: Logs = Logs()
|
|
194
194
|
"Logs printed to stdout and stderr during execution."
|
|
195
195
|
error: Optional[Error] = None
|
|
@@ -202,7 +202,7 @@ class Result(BaseModel):
|
|
|
202
202
|
|
|
203
203
|
:return: The text representation of the result.
|
|
204
204
|
"""
|
|
205
|
-
for d in self.
|
|
205
|
+
for d in self.results:
|
|
206
206
|
if d.is_main_result:
|
|
207
207
|
return d.text
|
|
208
208
|
|