e2b-code-interpreter 0.0.11a4__tar.gz → 0.0.11a5__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.11a4 → e2b_code_interpreter-0.0.11a5}/PKG-INFO +4 -6
- e2b_code_interpreter-0.0.11a5/e2b_code_interpreter/__init__.py +13 -0
- e2b_code_interpreter-0.0.11a5/e2b_code_interpreter/code_interpreter_async.py +188 -0
- e2b_code_interpreter-0.0.11a5/e2b_code_interpreter/code_interpreter_sync.py +205 -0
- e2b_code_interpreter-0.0.11a5/e2b_code_interpreter/constants.py +3 -0
- {e2b_code_interpreter-0.0.11a4 → e2b_code_interpreter-0.0.11a5}/e2b_code_interpreter/models.py +155 -74
- {e2b_code_interpreter-0.0.11a4 → e2b_code_interpreter-0.0.11a5}/pyproject.toml +6 -6
- e2b_code_interpreter-0.0.11a4/e2b_code_interpreter/__init__.py +0 -5
- e2b_code_interpreter-0.0.11a4/e2b_code_interpreter/constants.py +0 -1
- e2b_code_interpreter-0.0.11a4/e2b_code_interpreter/future.py +0 -46
- e2b_code_interpreter-0.0.11a4/e2b_code_interpreter/main.py +0 -340
- e2b_code_interpreter-0.0.11a4/e2b_code_interpreter/messaging.py +0 -273
- e2b_code_interpreter-0.0.11a4/e2b_code_interpreter/websocket_client.py +0 -163
- {e2b_code_interpreter-0.0.11a4 → e2b_code_interpreter-0.0.11a5}/README.md +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: e2b-code-interpreter
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.11a5
|
|
4
4
|
Summary: E2B Code Interpreter - Stateful code execution
|
|
5
5
|
Home-page: https://e2b.dev/
|
|
6
6
|
License: Apache-2.0
|
|
@@ -14,11 +14,9 @@ Classifier: Programming Language :: Python :: 3.9
|
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.10
|
|
15
15
|
Classifier: Programming Language :: Python :: 3.11
|
|
16
16
|
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
-
Requires-Dist:
|
|
18
|
-
Requires-Dist:
|
|
19
|
-
Requires-Dist:
|
|
20
|
-
Requires-Dist: websocket-client (>=1.7.0,<2.0.0)
|
|
21
|
-
Requires-Dist: websockets (>=12.0,<13.0)
|
|
17
|
+
Requires-Dist: attrs (>=21.3.0)
|
|
18
|
+
Requires-Dist: e2b (==0.17.2a31)
|
|
19
|
+
Requires-Dist: httpx (>=0.20.0,<0.28.0)
|
|
22
20
|
Project-URL: Bug Tracker, https://github.com/e2b-dev/code-interpreter/issues
|
|
23
21
|
Project-URL: Repository, https://github.com/e2b-dev/e2b-code-interpreter/tree/python
|
|
24
22
|
Description-Content-Type: text/markdown
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from e2b import *
|
|
2
|
+
|
|
3
|
+
from .code_interpreter_sync import CodeInterpreter
|
|
4
|
+
from .code_interpreter_async import AsyncCodeInterpreter
|
|
5
|
+
from .models import (
|
|
6
|
+
Execution,
|
|
7
|
+
ExecutionError,
|
|
8
|
+
Result,
|
|
9
|
+
MIMEType,
|
|
10
|
+
Logs,
|
|
11
|
+
OutputHandler,
|
|
12
|
+
OutputMessage,
|
|
13
|
+
)
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
from typing import Optional, List
|
|
4
|
+
from httpx import AsyncHTTPTransport, AsyncClient
|
|
5
|
+
|
|
6
|
+
from e2b import AsyncSandbox, ConnectionConfig
|
|
7
|
+
|
|
8
|
+
from e2b_code_interpreter.constants import (
|
|
9
|
+
DEFAULT_KERNEL_ID,
|
|
10
|
+
DEFAULT_TEMPLATE,
|
|
11
|
+
JUPYTER_PORT,
|
|
12
|
+
)
|
|
13
|
+
from e2b_code_interpreter.models import (
|
|
14
|
+
Execution,
|
|
15
|
+
Kernel,
|
|
16
|
+
Result,
|
|
17
|
+
aextract_exception,
|
|
18
|
+
parse_output,
|
|
19
|
+
OutputHandler,
|
|
20
|
+
OutputMessage,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
logger = logging.getLogger(__name__)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class JupyterExtension:
|
|
27
|
+
_exec_timeout = 300
|
|
28
|
+
|
|
29
|
+
@property
|
|
30
|
+
def _client(self) -> AsyncClient:
|
|
31
|
+
return AsyncClient(transport=self._transport)
|
|
32
|
+
|
|
33
|
+
def __init__(
|
|
34
|
+
self,
|
|
35
|
+
url: str,
|
|
36
|
+
transport: AsyncHTTPTransport,
|
|
37
|
+
connection_config: ConnectionConfig,
|
|
38
|
+
):
|
|
39
|
+
self._url = url
|
|
40
|
+
self._transport = transport
|
|
41
|
+
self._connection_config = connection_config
|
|
42
|
+
|
|
43
|
+
async def exec_cell(
|
|
44
|
+
self,
|
|
45
|
+
code: str,
|
|
46
|
+
kernel_id: Optional[str] = None,
|
|
47
|
+
on_stdout: Optional[OutputHandler[OutputMessage]] = None,
|
|
48
|
+
on_stderr: Optional[OutputHandler[OutputMessage]] = None,
|
|
49
|
+
on_result: Optional[OutputHandler[Result]] = None,
|
|
50
|
+
timeout: Optional[float] = None,
|
|
51
|
+
request_timeout: Optional[float] = None,
|
|
52
|
+
) -> Execution:
|
|
53
|
+
logger.debug(f"Executing code {code}")
|
|
54
|
+
|
|
55
|
+
timeout = None if timeout == 0 else (timeout or self._exec_timeout)
|
|
56
|
+
request_timeout = request_timeout or self._connection_config.request_timeout
|
|
57
|
+
|
|
58
|
+
async with self._client.stream(
|
|
59
|
+
"POST",
|
|
60
|
+
f"{self._url}/execute",
|
|
61
|
+
json={
|
|
62
|
+
"code": code,
|
|
63
|
+
"context_id": kernel_id,
|
|
64
|
+
},
|
|
65
|
+
timeout=(request_timeout, timeout, request_timeout, request_timeout),
|
|
66
|
+
) as response:
|
|
67
|
+
|
|
68
|
+
err = await aextract_exception(response)
|
|
69
|
+
if err:
|
|
70
|
+
raise err
|
|
71
|
+
|
|
72
|
+
execution = Execution()
|
|
73
|
+
|
|
74
|
+
async for line in response.aiter_lines():
|
|
75
|
+
parse_output(
|
|
76
|
+
execution,
|
|
77
|
+
line,
|
|
78
|
+
on_stdout=on_stdout,
|
|
79
|
+
on_stderr=on_stderr,
|
|
80
|
+
on_result=on_result,
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
return execution
|
|
84
|
+
|
|
85
|
+
async def create_kernel(
|
|
86
|
+
self,
|
|
87
|
+
cwd: Optional[str] = None,
|
|
88
|
+
kernel_name: Optional[str] = None,
|
|
89
|
+
request_timeout: Optional[float] = None,
|
|
90
|
+
) -> str:
|
|
91
|
+
logger.debug(f"Creating new kernel: {kernel_name}")
|
|
92
|
+
|
|
93
|
+
data = {}
|
|
94
|
+
if kernel_name:
|
|
95
|
+
data["name"] = kernel_name
|
|
96
|
+
if cwd:
|
|
97
|
+
data["cwd"] = cwd
|
|
98
|
+
|
|
99
|
+
response = await self._client.post(
|
|
100
|
+
f"{self._url}/contexts",
|
|
101
|
+
json=data,
|
|
102
|
+
timeout=request_timeout or self._connection_config.request_timeout,
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
err = await aextract_exception(response)
|
|
106
|
+
if err:
|
|
107
|
+
raise err
|
|
108
|
+
|
|
109
|
+
data = response.json()
|
|
110
|
+
return data["id"]
|
|
111
|
+
|
|
112
|
+
async def shutdown_kernel(
|
|
113
|
+
self,
|
|
114
|
+
kernel_id: Optional[str] = None,
|
|
115
|
+
request_timeout: Optional[float] = None,
|
|
116
|
+
) -> None:
|
|
117
|
+
logger.debug(f"Shutting down a kernel with id {kernel_id}")
|
|
118
|
+
|
|
119
|
+
kernel_id = kernel_id or DEFAULT_KERNEL_ID
|
|
120
|
+
response = await self._client.delete(
|
|
121
|
+
url=f"{self._url}/contexts/{kernel_id}",
|
|
122
|
+
timeout=request_timeout or self._connection_config.request_timeout,
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
err = await aextract_exception(response)
|
|
126
|
+
if err:
|
|
127
|
+
raise err
|
|
128
|
+
|
|
129
|
+
async def restart_kernel(
|
|
130
|
+
self,
|
|
131
|
+
kernel_id: Optional[str] = None,
|
|
132
|
+
request_timeout: Optional[float] = None,
|
|
133
|
+
) -> None:
|
|
134
|
+
logger.debug(f"Restarting kernel: {kernel_id}")
|
|
135
|
+
|
|
136
|
+
kernel_id = kernel_id or DEFAULT_KERNEL_ID
|
|
137
|
+
response = await self._client.post(
|
|
138
|
+
f"{self._url}/contexts/{kernel_id}/restart",
|
|
139
|
+
timeout=request_timeout or self._connection_config.request_timeout,
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
err = await aextract_exception(response)
|
|
143
|
+
if err:
|
|
144
|
+
raise err
|
|
145
|
+
|
|
146
|
+
async def list_kernels(
|
|
147
|
+
self,
|
|
148
|
+
request_timeout: Optional[float] = None,
|
|
149
|
+
) -> List[Kernel]:
|
|
150
|
+
"""
|
|
151
|
+
Lists all available Jupyter kernels.
|
|
152
|
+
|
|
153
|
+
This method fetches a list of all currently available Jupyter kernels from the server. It can be used
|
|
154
|
+
to retrieve the IDs of all kernels that are currently running or available for connection.
|
|
155
|
+
|
|
156
|
+
:param timeout: The timeout for the kernel list request.
|
|
157
|
+
:return: List of kernel ids
|
|
158
|
+
"""
|
|
159
|
+
response = await self._client.get(
|
|
160
|
+
f"{self._url}/contexts",
|
|
161
|
+
timeout=request_timeout or self._connection_config.request_timeout,
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
err = await aextract_exception(response)
|
|
165
|
+
if err:
|
|
166
|
+
raise err
|
|
167
|
+
|
|
168
|
+
return [Kernel(k["id"], k["name"]) for k in response.json()]
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
class AsyncCodeInterpreter(AsyncSandbox):
|
|
172
|
+
default_template = DEFAULT_TEMPLATE
|
|
173
|
+
_jupyter_port = JUPYTER_PORT
|
|
174
|
+
|
|
175
|
+
@property
|
|
176
|
+
def notebook(self) -> JupyterExtension:
|
|
177
|
+
return self._notebook
|
|
178
|
+
|
|
179
|
+
def __init__(self, sandbox_id: str, connection_config: ConnectionConfig):
|
|
180
|
+
super().__init__(sandbox_id, connection_config)
|
|
181
|
+
|
|
182
|
+
jupyter_url = f"{'http' if self.connection_config.debug else 'https'}://{self.get_host(self._jupyter_port)}"
|
|
183
|
+
|
|
184
|
+
self._notebook = JupyterExtension(
|
|
185
|
+
jupyter_url,
|
|
186
|
+
self._transport,
|
|
187
|
+
self.connection_config,
|
|
188
|
+
)
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
from typing import Optional, Dict, List
|
|
4
|
+
from httpx import HTTPTransport, Client
|
|
5
|
+
from e2b import Sandbox, ConnectionConfig
|
|
6
|
+
|
|
7
|
+
from e2b_code_interpreter.constants import (
|
|
8
|
+
DEFAULT_KERNEL_ID,
|
|
9
|
+
DEFAULT_TEMPLATE,
|
|
10
|
+
JUPYTER_PORT,
|
|
11
|
+
)
|
|
12
|
+
from e2b_code_interpreter.models import (
|
|
13
|
+
Execution,
|
|
14
|
+
Kernel,
|
|
15
|
+
Result,
|
|
16
|
+
extract_exception,
|
|
17
|
+
parse_output,
|
|
18
|
+
OutputHandler,
|
|
19
|
+
OutputMessage,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
logger = logging.getLogger(__name__)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class JupyterExtension:
|
|
26
|
+
_exec_timeout = 300
|
|
27
|
+
|
|
28
|
+
@property
|
|
29
|
+
def _client(self) -> Client:
|
|
30
|
+
return Client(transport=self._transport)
|
|
31
|
+
|
|
32
|
+
def __init__(
|
|
33
|
+
self,
|
|
34
|
+
url: str,
|
|
35
|
+
transport: HTTPTransport,
|
|
36
|
+
connection_config: ConnectionConfig,
|
|
37
|
+
):
|
|
38
|
+
self._url = url
|
|
39
|
+
self._transport = transport
|
|
40
|
+
self._connection_config = connection_config
|
|
41
|
+
|
|
42
|
+
def exec_cell(
|
|
43
|
+
self,
|
|
44
|
+
code: str,
|
|
45
|
+
kernel_id: Optional[str] = None,
|
|
46
|
+
language: Optional[str] = None,
|
|
47
|
+
on_stdout: Optional[OutputHandler[OutputMessage]] = None,
|
|
48
|
+
on_stderr: Optional[OutputHandler[OutputMessage]] = None,
|
|
49
|
+
on_result: Optional[OutputHandler[Result]] = None,
|
|
50
|
+
timeout: Optional[float] = None,
|
|
51
|
+
request_timeout: Optional[float] = None,
|
|
52
|
+
) -> Execution:
|
|
53
|
+
logger.debug(f"Executing code {code} for language {language}")
|
|
54
|
+
|
|
55
|
+
timeout = None if timeout == 0 else (timeout or self._exec_timeout)
|
|
56
|
+
request_timeout = request_timeout or self._connection_config.request_timeout
|
|
57
|
+
|
|
58
|
+
with self._client.stream(
|
|
59
|
+
"POST",
|
|
60
|
+
f"{self._url}/execute",
|
|
61
|
+
json={
|
|
62
|
+
"code": code,
|
|
63
|
+
"context_id": kernel_id,
|
|
64
|
+
},
|
|
65
|
+
timeout=(request_timeout, timeout, request_timeout, request_timeout),
|
|
66
|
+
) as response:
|
|
67
|
+
err = extract_exception(response)
|
|
68
|
+
if err:
|
|
69
|
+
raise err
|
|
70
|
+
|
|
71
|
+
execution = Execution()
|
|
72
|
+
|
|
73
|
+
for line in response.iter_lines():
|
|
74
|
+
parse_output(
|
|
75
|
+
execution,
|
|
76
|
+
line,
|
|
77
|
+
on_stdout=on_stdout,
|
|
78
|
+
on_stderr=on_stderr,
|
|
79
|
+
on_result=on_result,
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
return execution
|
|
83
|
+
|
|
84
|
+
def create_kernel(
|
|
85
|
+
self,
|
|
86
|
+
cwd: Optional[str] = None,
|
|
87
|
+
kernel_name: Optional[str] = None,
|
|
88
|
+
request_timeout: Optional[float] = None,
|
|
89
|
+
) -> str:
|
|
90
|
+
logger.debug(f"Creating new kernel: {kernel_name}")
|
|
91
|
+
|
|
92
|
+
data = {}
|
|
93
|
+
if kernel_name:
|
|
94
|
+
data['name'] = kernel_name
|
|
95
|
+
if cwd:
|
|
96
|
+
data['cwd'] = cwd
|
|
97
|
+
|
|
98
|
+
response = self._client.post(
|
|
99
|
+
f"{self._url}/contexts",
|
|
100
|
+
json=data,
|
|
101
|
+
timeout=request_timeout or self._connection_config.request_timeout,
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
err = extract_exception(response)
|
|
105
|
+
if err:
|
|
106
|
+
raise err
|
|
107
|
+
|
|
108
|
+
data = response.json()
|
|
109
|
+
return data["id"]
|
|
110
|
+
|
|
111
|
+
def shutdown_kernel(
|
|
112
|
+
self,
|
|
113
|
+
kernel_id: Optional[str] = None,
|
|
114
|
+
request_timeout: Optional[float] = None,
|
|
115
|
+
) -> None:
|
|
116
|
+
logger.debug(f"Shutting down a kernel with id {kernel_id}")
|
|
117
|
+
|
|
118
|
+
kernel_id = kernel_id or DEFAULT_KERNEL_ID
|
|
119
|
+
response = self._client.delete(
|
|
120
|
+
url=f"{self._url}/contexts/{kernel_id}",
|
|
121
|
+
timeout=request_timeout or self._connection_config.request_timeout,
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
err = extract_exception(response)
|
|
125
|
+
if err:
|
|
126
|
+
raise err
|
|
127
|
+
|
|
128
|
+
def restart_kernel(
|
|
129
|
+
self,
|
|
130
|
+
kernel_id: Optional[str] = None,
|
|
131
|
+
request_timeout: Optional[float] = None,
|
|
132
|
+
) -> None:
|
|
133
|
+
logger.debug(f"Creating new kernel for language: {kernel_id}")
|
|
134
|
+
|
|
135
|
+
kernel_id = kernel_id or DEFAULT_KERNEL_ID
|
|
136
|
+
response = self._client.post(
|
|
137
|
+
f"{self._url}/contexts/{kernel_id}/restart",
|
|
138
|
+
timeout=request_timeout or self._connection_config.request_timeout,
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
err = extract_exception(response)
|
|
142
|
+
if err:
|
|
143
|
+
raise err
|
|
144
|
+
|
|
145
|
+
def list_kernels(
|
|
146
|
+
self,
|
|
147
|
+
request_timeout: Optional[float] = None,
|
|
148
|
+
) -> List[Kernel]:
|
|
149
|
+
"""
|
|
150
|
+
Lists all available Jupyter kernels.
|
|
151
|
+
|
|
152
|
+
This method fetches a list of all currently available Jupyter kernels from the server. It can be used
|
|
153
|
+
to retrieve the IDs of all kernels that are currently running or available for connection.
|
|
154
|
+
|
|
155
|
+
:param timeout: The timeout for the kernel list request.
|
|
156
|
+
:return: List of kernel ids
|
|
157
|
+
"""
|
|
158
|
+
response = self._client.get(
|
|
159
|
+
f"{self._url}/contexts",
|
|
160
|
+
timeout=request_timeout or self._connection_config.request_timeout,
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
err = extract_exception(response)
|
|
164
|
+
if err:
|
|
165
|
+
raise err
|
|
166
|
+
|
|
167
|
+
return [Kernel(kernel_id=k["id"], name=k["name"]) for k in response.json()]
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
class CodeInterpreter(Sandbox):
|
|
171
|
+
default_template = DEFAULT_TEMPLATE
|
|
172
|
+
_jupyter_port = JUPYTER_PORT
|
|
173
|
+
|
|
174
|
+
@property
|
|
175
|
+
def notebook(self) -> JupyterExtension:
|
|
176
|
+
return self._notebook
|
|
177
|
+
|
|
178
|
+
def __init__(
|
|
179
|
+
self,
|
|
180
|
+
template: Optional[str] = None,
|
|
181
|
+
timeout: Optional[int] = None,
|
|
182
|
+
metadata: Optional[Dict[str, str]] = None,
|
|
183
|
+
api_key: Optional[str] = None,
|
|
184
|
+
domain: Optional[str] = None,
|
|
185
|
+
debug: Optional[bool] = None,
|
|
186
|
+
sandbox_id: Optional[str] = None,
|
|
187
|
+
request_timeout: Optional[float] = None,
|
|
188
|
+
):
|
|
189
|
+
super().__init__(
|
|
190
|
+
template=template,
|
|
191
|
+
timeout=timeout,
|
|
192
|
+
metadata=metadata,
|
|
193
|
+
api_key=api_key,
|
|
194
|
+
domain=domain,
|
|
195
|
+
debug=debug,
|
|
196
|
+
sandbox_id=sandbox_id,
|
|
197
|
+
request_timeout=request_timeout,
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
jupyter_url = f"{'http' if self.connection_config.debug else 'https'}://{self.get_host(self._jupyter_port)}"
|
|
201
|
+
self._notebook = JupyterExtension(
|
|
202
|
+
jupyter_url,
|
|
203
|
+
self._transport,
|
|
204
|
+
self.connection_config,
|
|
205
|
+
)
|