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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: e2b-code-interpreter
3
- Version: 0.0.11a4
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: e2b (==0.17.2a24)
18
- Requires-Dist: pydantic
19
- Requires-Dist: requests (>=2.32.3,<3.0.0)
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
+ )
@@ -0,0 +1,3 @@
1
+ DEFAULT_TEMPLATE = "ci-no-ws"
2
+ JUPYTER_PORT = 49999
3
+ DEFAULT_KERNEL_ID = "default"