e2b-code-interpreter 2.8.0__tar.gz → 2.11.0__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-2.11.0/PKG-INFO +98 -0
- e2b_code_interpreter-2.11.0/README.md +82 -0
- {e2b_code_interpreter-2.8.0 → e2b_code_interpreter-2.11.0}/e2b_code_interpreter/__init__.py +1 -0
- {e2b_code_interpreter-2.8.0 → e2b_code_interpreter-2.11.0}/e2b_code_interpreter/charts.py +7 -5
- e2b_code_interpreter-2.11.0/e2b_code_interpreter/client.py +93 -0
- {e2b_code_interpreter-2.8.0 → e2b_code_interpreter-2.11.0}/e2b_code_interpreter/code_interpreter_async.py +64 -4
- {e2b_code_interpreter-2.8.0 → e2b_code_interpreter-2.11.0}/e2b_code_interpreter/code_interpreter_sync.py +81 -17
- {e2b_code_interpreter-2.8.0 → e2b_code_interpreter-2.11.0}/e2b_code_interpreter/exceptions.py +7 -0
- {e2b_code_interpreter-2.8.0 → e2b_code_interpreter-2.11.0}/e2b_code_interpreter/models.py +19 -9
- e2b_code_interpreter-2.11.0/pyproject.toml +47 -0
- e2b_code_interpreter-2.8.0/LICENSE +0 -9
- e2b_code_interpreter-2.8.0/PKG-INFO +0 -72
- e2b_code_interpreter-2.8.0/README.md +0 -49
- e2b_code_interpreter-2.8.0/pyproject.toml +0 -37
- {e2b_code_interpreter-2.8.0 → e2b_code_interpreter-2.11.0}/e2b_code_interpreter/constants.py +0 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: e2b-code-interpreter
|
|
3
|
+
Version: 2.11.0
|
|
4
|
+
Summary: E2B Code Interpreter - Stateful code execution
|
|
5
|
+
Author: e2b
|
|
6
|
+
Author-email: e2b <hello@e2b.dev>
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
Requires-Dist: httpx>=0.20.0,<1.0.0
|
|
9
|
+
Requires-Dist: attrs>=21.3.0
|
|
10
|
+
Requires-Dist: e2b>=2.55.1,<3.0.0
|
|
11
|
+
Requires-Python: >=3.11
|
|
12
|
+
Project-URL: Homepage, https://e2b.dev/?utm_source=pypi&utm_medium=referral&utm_campaign=package_homepage&utm_content=e2b-code-interpreter
|
|
13
|
+
Project-URL: Repository, https://github.com/e2b-dev/e2b/tree/main/packages/code-interpreter-python
|
|
14
|
+
Project-URL: Bug Tracker, https://github.com/e2b-dev/e2b/issues
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
|
|
17
|
+
<p align="center">
|
|
18
|
+
<picture>
|
|
19
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/e2b-dev/E2B/refs/heads/main/readme-assets/logo-white.png">
|
|
20
|
+
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/e2b-dev/E2B/refs/heads/main/readme-assets/logo-black.png">
|
|
21
|
+
<img alt="E2B Logo" src="https://raw.githubusercontent.com/e2b-dev/E2B/refs/heads/main/readme-assets/logo-black.png" width="200">
|
|
22
|
+
</picture>
|
|
23
|
+
</p>
|
|
24
|
+
|
|
25
|
+
<h4 align="center">
|
|
26
|
+
<a href="https://pypi.org/project/e2b/">
|
|
27
|
+
<img alt="Last 1 month downloads for the Python SDK" loading="lazy" width="200" height="20" decoding="async" data-nimg="1"
|
|
28
|
+
style="color:transparent;width:auto;height:100%" src="https://img.shields.io/pypi/dm/e2b?label=PyPI%20Downloads">
|
|
29
|
+
</a>
|
|
30
|
+
</h4>
|
|
31
|
+
|
|
32
|
+
<!---
|
|
33
|
+
<img width="100%" src="/readme-assets/preview.png" alt="Cover image">
|
|
34
|
+
--->
|
|
35
|
+
## What is E2B?
|
|
36
|
+
[E2B](https://e2b.dev/?utm_source=pypi&utm_medium=referral&utm_campaign=readme&utm_content=code-interpreter) is an open-source infrastructure that allows you run to AI-generated code in secure isolated sandboxes in the cloud. To start and control sandboxes, use our [JavaScript SDK](https://www.npmjs.com/package/@e2b/code-interpreter) or [Python SDK](https://pypi.org/project/e2b_code_interpreter).
|
|
37
|
+
|
|
38
|
+
Source: [packages/code-interpreter-python](https://github.com/e2b-dev/E2B/tree/main/packages/code-interpreter-python)
|
|
39
|
+
|
|
40
|
+
## Run your first Sandbox
|
|
41
|
+
|
|
42
|
+
### 1. Install SDK
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
pip install e2b-code-interpreter
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### 2. Get your E2B API key
|
|
49
|
+
1. Sign up to E2B [here](https://e2b.dev/?utm_source=pypi&utm_medium=referral&utm_campaign=readme&utm_content=code-interpreter).
|
|
50
|
+
2. Get your API key [here](https://e2b.dev/dashboard?tab=keys&utm_source=pypi&utm_medium=referral&utm_campaign=readme&utm_content=code-interpreter).
|
|
51
|
+
3. Set environment variable with your API key.
|
|
52
|
+
```
|
|
53
|
+
E2B_API_KEY=e2b_***
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### 3. Execute code with code interpreter inside Sandbox
|
|
57
|
+
|
|
58
|
+
```py
|
|
59
|
+
from e2b_code_interpreter import Sandbox
|
|
60
|
+
|
|
61
|
+
with Sandbox.create() as sandbox:
|
|
62
|
+
sandbox.run_code("x = 1")
|
|
63
|
+
execution = sandbox.run_code("x+=1; x")
|
|
64
|
+
print(execution.text) # outputs 2
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### 4. Bind the configuration to a client
|
|
68
|
+
|
|
69
|
+
The top-level `Sandbox` and `AsyncSandbox` exports read their configuration from the environment variables. To use an explicit configuration — e.g. several API keys or domains in one process — create an `E2B` client and use the resource classes it exposes:
|
|
70
|
+
|
|
71
|
+
```py
|
|
72
|
+
from e2b_code_interpreter import E2B
|
|
73
|
+
|
|
74
|
+
client = E2B(api_key="e2b_***", domain="e2b.dev")
|
|
75
|
+
|
|
76
|
+
with client.Sandbox.create() as sandbox:
|
|
77
|
+
execution = sandbox.run_code("x = 1; x += 1; x")
|
|
78
|
+
|
|
79
|
+
# The async variant is exposed as well.
|
|
80
|
+
async_sandbox = await client.AsyncSandbox.create()
|
|
81
|
+
|
|
82
|
+
# The core resources are bound to the client's configuration as well.
|
|
83
|
+
volume = client.Volume.create("my-volume")
|
|
84
|
+
exists = client.Template.exists("my-template")
|
|
85
|
+
secret = client.Secret.create("openai-api-key", "sk-***")
|
|
86
|
+
|
|
87
|
+
# The classes can be assigned and used like the top-level ones.
|
|
88
|
+
Sandbox = client.Sandbox
|
|
89
|
+
paginator = Sandbox.list()
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Per-call params still take precedence over the client's params, and clients are isolated from each other and from the env-configured top-level exports.
|
|
93
|
+
|
|
94
|
+
### 5. Check docs
|
|
95
|
+
Visit [E2B documentation](https://docs.e2b.dev/?utm_source=pypi&utm_medium=referral&utm_campaign=readme&utm_content=code-interpreter).
|
|
96
|
+
|
|
97
|
+
### 6. E2B cookbook
|
|
98
|
+
Visit our [Cookbook](https://github.com/e2b-dev/e2b-cookbook/tree/main) to get inspired by examples with different LLMs and AI frameworks.
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<picture>
|
|
3
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/e2b-dev/E2B/refs/heads/main/readme-assets/logo-white.png">
|
|
4
|
+
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/e2b-dev/E2B/refs/heads/main/readme-assets/logo-black.png">
|
|
5
|
+
<img alt="E2B Logo" src="https://raw.githubusercontent.com/e2b-dev/E2B/refs/heads/main/readme-assets/logo-black.png" width="200">
|
|
6
|
+
</picture>
|
|
7
|
+
</p>
|
|
8
|
+
|
|
9
|
+
<h4 align="center">
|
|
10
|
+
<a href="https://pypi.org/project/e2b/">
|
|
11
|
+
<img alt="Last 1 month downloads for the Python SDK" loading="lazy" width="200" height="20" decoding="async" data-nimg="1"
|
|
12
|
+
style="color:transparent;width:auto;height:100%" src="https://img.shields.io/pypi/dm/e2b?label=PyPI%20Downloads">
|
|
13
|
+
</a>
|
|
14
|
+
</h4>
|
|
15
|
+
|
|
16
|
+
<!---
|
|
17
|
+
<img width="100%" src="/readme-assets/preview.png" alt="Cover image">
|
|
18
|
+
--->
|
|
19
|
+
## What is E2B?
|
|
20
|
+
[E2B](https://e2b.dev/?utm_source=pypi&utm_medium=referral&utm_campaign=readme&utm_content=code-interpreter) is an open-source infrastructure that allows you run to AI-generated code in secure isolated sandboxes in the cloud. To start and control sandboxes, use our [JavaScript SDK](https://www.npmjs.com/package/@e2b/code-interpreter) or [Python SDK](https://pypi.org/project/e2b_code_interpreter).
|
|
21
|
+
|
|
22
|
+
Source: [packages/code-interpreter-python](https://github.com/e2b-dev/E2B/tree/main/packages/code-interpreter-python)
|
|
23
|
+
|
|
24
|
+
## Run your first Sandbox
|
|
25
|
+
|
|
26
|
+
### 1. Install SDK
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
pip install e2b-code-interpreter
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### 2. Get your E2B API key
|
|
33
|
+
1. Sign up to E2B [here](https://e2b.dev/?utm_source=pypi&utm_medium=referral&utm_campaign=readme&utm_content=code-interpreter).
|
|
34
|
+
2. Get your API key [here](https://e2b.dev/dashboard?tab=keys&utm_source=pypi&utm_medium=referral&utm_campaign=readme&utm_content=code-interpreter).
|
|
35
|
+
3. Set environment variable with your API key.
|
|
36
|
+
```
|
|
37
|
+
E2B_API_KEY=e2b_***
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### 3. Execute code with code interpreter inside Sandbox
|
|
41
|
+
|
|
42
|
+
```py
|
|
43
|
+
from e2b_code_interpreter import Sandbox
|
|
44
|
+
|
|
45
|
+
with Sandbox.create() as sandbox:
|
|
46
|
+
sandbox.run_code("x = 1")
|
|
47
|
+
execution = sandbox.run_code("x+=1; x")
|
|
48
|
+
print(execution.text) # outputs 2
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### 4. Bind the configuration to a client
|
|
52
|
+
|
|
53
|
+
The top-level `Sandbox` and `AsyncSandbox` exports read their configuration from the environment variables. To use an explicit configuration — e.g. several API keys or domains in one process — create an `E2B` client and use the resource classes it exposes:
|
|
54
|
+
|
|
55
|
+
```py
|
|
56
|
+
from e2b_code_interpreter import E2B
|
|
57
|
+
|
|
58
|
+
client = E2B(api_key="e2b_***", domain="e2b.dev")
|
|
59
|
+
|
|
60
|
+
with client.Sandbox.create() as sandbox:
|
|
61
|
+
execution = sandbox.run_code("x = 1; x += 1; x")
|
|
62
|
+
|
|
63
|
+
# The async variant is exposed as well.
|
|
64
|
+
async_sandbox = await client.AsyncSandbox.create()
|
|
65
|
+
|
|
66
|
+
# The core resources are bound to the client's configuration as well.
|
|
67
|
+
volume = client.Volume.create("my-volume")
|
|
68
|
+
exists = client.Template.exists("my-template")
|
|
69
|
+
secret = client.Secret.create("openai-api-key", "sk-***")
|
|
70
|
+
|
|
71
|
+
# The classes can be assigned and used like the top-level ones.
|
|
72
|
+
Sandbox = client.Sandbox
|
|
73
|
+
paginator = Sandbox.list()
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Per-call params still take precedence over the client's params, and clients are isolated from each other and from the env-configured top-level exports.
|
|
77
|
+
|
|
78
|
+
### 5. Check docs
|
|
79
|
+
Visit [E2B documentation](https://docs.e2b.dev/?utm_source=pypi&utm_medium=referral&utm_campaign=readme&utm_content=code-interpreter).
|
|
80
|
+
|
|
81
|
+
### 6. E2B cookbook
|
|
82
|
+
Visit our [Cookbook](https://github.com/e2b-dev/e2b-cookbook/tree/main) to get inspired by examples with different LLMs and AI frameworks.
|
|
@@ -194,17 +194,19 @@ class BoxAndWhiskerChart(Chart2D):
|
|
|
194
194
|
class SuperChart(Chart):
|
|
195
195
|
type = ChartType.SUPERCHART
|
|
196
196
|
|
|
197
|
-
elements: List[
|
|
198
|
-
Union[LineChart, ScatterChart, BarChart, PieChart, BoxAndWhiskerChart]
|
|
199
|
-
]
|
|
197
|
+
elements: List[Chart]
|
|
200
198
|
|
|
201
199
|
def __init__(self, **kwargs):
|
|
202
200
|
super().__init__(**kwargs)
|
|
203
|
-
self.elements = [
|
|
201
|
+
self.elements = []
|
|
202
|
+
for raw_chart in kwargs["elements"]:
|
|
203
|
+
chart = _deserialize_chart(raw_chart)
|
|
204
|
+
if chart is not None:
|
|
205
|
+
self.elements.append(chart)
|
|
204
206
|
|
|
205
207
|
|
|
206
208
|
ChartTypes = Union[
|
|
207
|
-
LineChart, ScatterChart, BarChart, PieChart, BoxAndWhiskerChart, SuperChart
|
|
209
|
+
Chart, LineChart, ScatterChart, BarChart, PieChart, BoxAndWhiskerChart, SuperChart
|
|
208
210
|
]
|
|
209
211
|
|
|
210
212
|
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
from typing import Dict, Type, TypeVar, cast
|
|
2
|
+
|
|
3
|
+
from e2b import ApiParams, E2BClientParams
|
|
4
|
+
from e2b import E2B as CoreE2B
|
|
5
|
+
from typing_extensions import Unpack
|
|
6
|
+
|
|
7
|
+
from e2b_code_interpreter.code_interpreter_async import AsyncSandbox
|
|
8
|
+
from e2b_code_interpreter.code_interpreter_sync import Sandbox
|
|
9
|
+
|
|
10
|
+
T = TypeVar("T")
|
|
11
|
+
|
|
12
|
+
__all__ = ["E2B", "E2BClientParams"]
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _bind(cls: Type[T], api_params: ApiParams) -> Type[T]:
|
|
16
|
+
"""Generate a subclass of ``cls`` carrying ``api_params`` as its bound params."""
|
|
17
|
+
return cast(
|
|
18
|
+
Type[T],
|
|
19
|
+
type(cls.__name__, (cls,), {"_bound_api_params": api_params}),
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class E2B:
|
|
24
|
+
"""
|
|
25
|
+
E2B client with an explicitly bound connection configuration.
|
|
26
|
+
|
|
27
|
+
The resource classes exposed by the client (`Sandbox`, `AsyncSandbox`,
|
|
28
|
+
`Volume`, `AsyncVolume`, `Template`, `AsyncTemplate`, `Secret`,
|
|
29
|
+
`AsyncSecret`) behave exactly like the top-level exports of the same name,
|
|
30
|
+
except the params passed to the client are used as the defaults instead of
|
|
31
|
+
the environment variables.
|
|
32
|
+
Per-call params still take precedence over the client's params.
|
|
33
|
+
|
|
34
|
+
Multiple clients are fully isolated from each other and from the top-level
|
|
35
|
+
env-configured exports.
|
|
36
|
+
|
|
37
|
+
Example:
|
|
38
|
+
```python
|
|
39
|
+
from e2b_code_interpreter import E2B
|
|
40
|
+
|
|
41
|
+
client = E2B(api_key="e2b_...", domain="e2b.dev")
|
|
42
|
+
|
|
43
|
+
sandbox = client.Sandbox.create()
|
|
44
|
+
execution = sandbox.run_code("x = 1; x += 1; x")
|
|
45
|
+
```
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
def __init__(self, **opts: Unpack[E2BClientParams]):
|
|
49
|
+
"""
|
|
50
|
+
Create a new client with the API params bound to it.
|
|
51
|
+
|
|
52
|
+
:param opts: API params used as the defaults for every call made
|
|
53
|
+
through this client's resource classes.
|
|
54
|
+
"""
|
|
55
|
+
# Params are copied so later mutations of the caller's dicts cannot
|
|
56
|
+
# change the bound configuration.
|
|
57
|
+
api_params = cast(ApiParams, dict(cast(Dict[str, object], opts)))
|
|
58
|
+
|
|
59
|
+
headers = api_params.get("headers")
|
|
60
|
+
if headers is not None:
|
|
61
|
+
api_params["headers"] = dict(headers)
|
|
62
|
+
|
|
63
|
+
api_headers = api_params.get("api_headers")
|
|
64
|
+
if api_headers is not None:
|
|
65
|
+
api_params["api_headers"] = dict(api_headers)
|
|
66
|
+
|
|
67
|
+
self.Sandbox = _bind(Sandbox, api_params)
|
|
68
|
+
"""Code Interpreter `Sandbox` class bound to this client's connection configuration."""
|
|
69
|
+
|
|
70
|
+
self.AsyncSandbox = _bind(AsyncSandbox, api_params)
|
|
71
|
+
"""Code Interpreter `AsyncSandbox` class bound to this client's connection configuration."""
|
|
72
|
+
|
|
73
|
+
# The resources that are not specific to the Code Interpreter are bound
|
|
74
|
+
# by the core client.
|
|
75
|
+
core = CoreE2B(**api_params)
|
|
76
|
+
|
|
77
|
+
self.Volume = core.Volume
|
|
78
|
+
"""`Volume` class bound to this client's connection configuration."""
|
|
79
|
+
|
|
80
|
+
self.AsyncVolume = core.AsyncVolume
|
|
81
|
+
"""`AsyncVolume` class bound to this client's connection configuration."""
|
|
82
|
+
|
|
83
|
+
self.Template = core.Template
|
|
84
|
+
"""`Template` class bound to this client's connection configuration."""
|
|
85
|
+
|
|
86
|
+
self.AsyncTemplate = core.AsyncTemplate
|
|
87
|
+
"""`AsyncTemplate` class bound to this client's connection configuration."""
|
|
88
|
+
|
|
89
|
+
self.Secret = core.Secret
|
|
90
|
+
"""`Secret` class bound to this client's connection configuration."""
|
|
91
|
+
|
|
92
|
+
self.AsyncSecret = core.AsyncSecret
|
|
93
|
+
"""`AsyncSecret` class bound to this client's connection configuration."""
|
|
@@ -29,6 +29,7 @@ from e2b_code_interpreter.models import (
|
|
|
29
29
|
from e2b_code_interpreter.exceptions import (
|
|
30
30
|
format_execution_timeout_error,
|
|
31
31
|
format_request_timeout_error,
|
|
32
|
+
format_sandbox_killed_error,
|
|
32
33
|
)
|
|
33
34
|
|
|
34
35
|
logger = logging.getLogger(__name__)
|
|
@@ -60,14 +61,16 @@ class AsyncSandbox(BaseAsyncSandbox):
|
|
|
60
61
|
|
|
61
62
|
@property
|
|
62
63
|
def _jupyter_url(self) -> str:
|
|
63
|
-
return
|
|
64
|
+
return self.connection_config.get_sandbox_url(
|
|
65
|
+
self.sandbox_id, self.sandbox_domain, port=JUPYTER_PORT
|
|
66
|
+
)
|
|
64
67
|
|
|
65
68
|
@property
|
|
66
69
|
def _client(self) -> AsyncClient:
|
|
67
70
|
# TODO: Remove later
|
|
68
71
|
# Use a dedicated HTTP/1.1 transport for Jupyter requests.
|
|
69
72
|
#
|
|
70
|
-
# The base SDK's shared transport now defaults to
|
|
73
|
+
# The base SDK's shared transport now defaults to HTTP/2. With
|
|
71
74
|
# HTTP/2, multiple requests are multiplexed over a single TCP
|
|
72
75
|
# connection, so when a client cancels a request (e.g. the caller
|
|
73
76
|
# disconnects from the streaming `/execute` endpoint) the server
|
|
@@ -80,9 +83,26 @@ class AsyncSandbox(BaseAsyncSandbox):
|
|
|
80
83
|
# cancelled reliably. The helper also caches the transport
|
|
81
84
|
# per-event-loop for async.
|
|
82
85
|
return AsyncClient(
|
|
83
|
-
transport=get_transport(self.connection_config,
|
|
86
|
+
transport=get_transport(self.connection_config, http_version="1.1"),
|
|
84
87
|
)
|
|
85
88
|
|
|
89
|
+
async def _handle_connection_error(self, err: Exception) -> None:
|
|
90
|
+
"""
|
|
91
|
+
Raises a descriptive exception if the connection error was caused by
|
|
92
|
+
the sandbox being killed mid-request. If the sandbox is still running
|
|
93
|
+
(or its state can't be determined), returns so the caller can re-raise
|
|
94
|
+
the original error.
|
|
95
|
+
"""
|
|
96
|
+
try:
|
|
97
|
+
running = await self.is_running()
|
|
98
|
+
except Exception:
|
|
99
|
+
# The state check itself failed, so we can't tell whether the
|
|
100
|
+
# sandbox was killed — let the caller re-raise the original error
|
|
101
|
+
# instead of wrongly claiming the sandbox is gone.
|
|
102
|
+
return
|
|
103
|
+
if not running:
|
|
104
|
+
raise format_sandbox_killed_error() from err
|
|
105
|
+
|
|
86
106
|
@overload
|
|
87
107
|
async def run_code(
|
|
88
108
|
self,
|
|
@@ -178,6 +198,8 @@ class AsyncSandbox(BaseAsyncSandbox):
|
|
|
178
198
|
try:
|
|
179
199
|
headers = {
|
|
180
200
|
"Content-Type": "application/json",
|
|
201
|
+
"E2b-Sandbox-Id": self.sandbox_id,
|
|
202
|
+
"E2b-Sandbox-Port": str(JUPYTER_PORT),
|
|
181
203
|
}
|
|
182
204
|
if self._envd_access_token:
|
|
183
205
|
headers["X-Access-Token"] = self._envd_access_token
|
|
@@ -194,7 +216,22 @@ class AsyncSandbox(BaseAsyncSandbox):
|
|
|
194
216
|
"env_vars": envs,
|
|
195
217
|
},
|
|
196
218
|
headers=headers,
|
|
197
|
-
timeout
|
|
219
|
+
# `timeout` bounds the execution, `request_timeout` only the
|
|
220
|
+
# connect. Every non-connect phase must carry `timeout`: the
|
|
221
|
+
# SDK's pyqwest-backed transport collapses the per-phase
|
|
222
|
+
# timeouts into a single whole-request deadline and takes the
|
|
223
|
+
# longest of them, so leaving `request_timeout` on the write
|
|
224
|
+
# and pool phases would raise the floor to
|
|
225
|
+
# `max(timeout, request_timeout)` and silently ignore any
|
|
226
|
+
# `timeout` shorter than it. This matches the JS SDK, which
|
|
227
|
+
# aborts the execution on a `timeout`-long timer.
|
|
228
|
+
# `timeout=0` disables the deadline entirely; the transport
|
|
229
|
+
# still bounds connect on its own.
|
|
230
|
+
timeout=(
|
|
231
|
+
httpx.Timeout(timeout, connect=request_timeout)
|
|
232
|
+
if timeout is not None
|
|
233
|
+
else httpx.Timeout(None)
|
|
234
|
+
),
|
|
198
235
|
) as response:
|
|
199
236
|
err = await aextract_exception(response)
|
|
200
237
|
if err:
|
|
@@ -217,6 +254,9 @@ class AsyncSandbox(BaseAsyncSandbox):
|
|
|
217
254
|
raise format_execution_timeout_error()
|
|
218
255
|
except httpx.TimeoutException:
|
|
219
256
|
raise format_request_timeout_error()
|
|
257
|
+
except (httpx.ReadError, httpx.RemoteProtocolError) as err:
|
|
258
|
+
await self._handle_connection_error(err)
|
|
259
|
+
raise
|
|
220
260
|
|
|
221
261
|
async def create_code_context(
|
|
222
262
|
self,
|
|
@@ -244,6 +284,8 @@ class AsyncSandbox(BaseAsyncSandbox):
|
|
|
244
284
|
try:
|
|
245
285
|
headers = {
|
|
246
286
|
"Content-Type": "application/json",
|
|
287
|
+
"E2b-Sandbox-Id": self.sandbox_id,
|
|
288
|
+
"E2b-Sandbox-Port": str(JUPYTER_PORT),
|
|
247
289
|
}
|
|
248
290
|
if self.traffic_access_token:
|
|
249
291
|
headers["E2B-Traffic-Access-Token"] = self.traffic_access_token
|
|
@@ -263,6 +305,9 @@ class AsyncSandbox(BaseAsyncSandbox):
|
|
|
263
305
|
return Context.from_json(data)
|
|
264
306
|
except httpx.TimeoutException:
|
|
265
307
|
raise format_request_timeout_error()
|
|
308
|
+
except (httpx.ReadError, httpx.RemoteProtocolError) as err:
|
|
309
|
+
await self._handle_connection_error(err)
|
|
310
|
+
raise
|
|
266
311
|
|
|
267
312
|
async def remove_code_context(
|
|
268
313
|
self,
|
|
@@ -280,6 +325,8 @@ class AsyncSandbox(BaseAsyncSandbox):
|
|
|
280
325
|
try:
|
|
281
326
|
headers = {
|
|
282
327
|
"Content-Type": "application/json",
|
|
328
|
+
"E2b-Sandbox-Id": self.sandbox_id,
|
|
329
|
+
"E2b-Sandbox-Port": str(JUPYTER_PORT),
|
|
283
330
|
}
|
|
284
331
|
if self.traffic_access_token:
|
|
285
332
|
headers["E2B-Traffic-Access-Token"] = self.traffic_access_token
|
|
@@ -295,6 +342,9 @@ class AsyncSandbox(BaseAsyncSandbox):
|
|
|
295
342
|
raise err
|
|
296
343
|
except httpx.TimeoutException:
|
|
297
344
|
raise format_request_timeout_error()
|
|
345
|
+
except (httpx.ReadError, httpx.RemoteProtocolError) as err:
|
|
346
|
+
await self._handle_connection_error(err)
|
|
347
|
+
raise
|
|
298
348
|
|
|
299
349
|
async def list_code_contexts(self) -> List[Context]:
|
|
300
350
|
"""
|
|
@@ -305,6 +355,8 @@ class AsyncSandbox(BaseAsyncSandbox):
|
|
|
305
355
|
try:
|
|
306
356
|
headers = {
|
|
307
357
|
"Content-Type": "application/json",
|
|
358
|
+
"E2b-Sandbox-Id": self.sandbox_id,
|
|
359
|
+
"E2b-Sandbox-Port": str(JUPYTER_PORT),
|
|
308
360
|
}
|
|
309
361
|
if self.traffic_access_token:
|
|
310
362
|
headers["E2B-Traffic-Access-Token"] = self.traffic_access_token
|
|
@@ -323,6 +375,9 @@ class AsyncSandbox(BaseAsyncSandbox):
|
|
|
323
375
|
return [Context.from_json(context_data) for context_data in data]
|
|
324
376
|
except httpx.TimeoutException:
|
|
325
377
|
raise format_request_timeout_error()
|
|
378
|
+
except (httpx.ReadError, httpx.RemoteProtocolError) as err:
|
|
379
|
+
await self._handle_connection_error(err)
|
|
380
|
+
raise
|
|
326
381
|
|
|
327
382
|
async def restart_code_context(
|
|
328
383
|
self,
|
|
@@ -339,6 +394,8 @@ class AsyncSandbox(BaseAsyncSandbox):
|
|
|
339
394
|
try:
|
|
340
395
|
headers = {
|
|
341
396
|
"Content-Type": "application/json",
|
|
397
|
+
"E2b-Sandbox-Id": self.sandbox_id,
|
|
398
|
+
"E2b-Sandbox-Port": str(JUPYTER_PORT),
|
|
342
399
|
}
|
|
343
400
|
if self.traffic_access_token:
|
|
344
401
|
headers["E2B-Traffic-Access-Token"] = self.traffic_access_token
|
|
@@ -354,3 +411,6 @@ class AsyncSandbox(BaseAsyncSandbox):
|
|
|
354
411
|
raise err
|
|
355
412
|
except httpx.TimeoutException:
|
|
356
413
|
raise format_request_timeout_error()
|
|
414
|
+
except (httpx.ReadError, httpx.RemoteProtocolError) as err:
|
|
415
|
+
await self._handle_connection_error(err)
|
|
416
|
+
raise
|
|
@@ -25,6 +25,7 @@ from e2b_code_interpreter.models import (
|
|
|
25
25
|
from e2b_code_interpreter.exceptions import (
|
|
26
26
|
format_execution_timeout_error,
|
|
27
27
|
format_request_timeout_error,
|
|
28
|
+
format_sandbox_killed_error,
|
|
28
29
|
)
|
|
29
30
|
|
|
30
31
|
logger = logging.getLogger(__name__)
|
|
@@ -57,14 +58,16 @@ class Sandbox(BaseSandbox):
|
|
|
57
58
|
|
|
58
59
|
@property
|
|
59
60
|
def _jupyter_url(self) -> str:
|
|
60
|
-
return
|
|
61
|
+
return self.connection_config.get_sandbox_url(
|
|
62
|
+
self.sandbox_id, self.sandbox_domain, port=JUPYTER_PORT
|
|
63
|
+
)
|
|
61
64
|
|
|
62
65
|
@property
|
|
63
66
|
def _client(self) -> Client:
|
|
64
67
|
# TODO: Remove later
|
|
65
68
|
# Use a dedicated HTTP/1.1 transport for Jupyter requests.
|
|
66
69
|
#
|
|
67
|
-
# The base SDK's shared transport now defaults to
|
|
70
|
+
# The base SDK's shared transport now defaults to HTTP/2. With
|
|
68
71
|
# HTTP/2, multiple requests are multiplexed over a single TCP
|
|
69
72
|
# connection, so when a client cancels a request (e.g. the caller
|
|
70
73
|
# disconnects from the streaming `/execute` endpoint) the server
|
|
@@ -75,7 +78,26 @@ class Sandbox(BaseSandbox):
|
|
|
75
78
|
# connection and request, so client disconnects propagate to the
|
|
76
79
|
# server as a TCP close and long-running executions can be
|
|
77
80
|
# cancelled reliably.
|
|
78
|
-
return Client(
|
|
81
|
+
return Client(
|
|
82
|
+
transport=get_transport(self.connection_config, http_version="1.1")
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
def _handle_connection_error(self, err: Exception) -> None:
|
|
86
|
+
"""
|
|
87
|
+
Raises a descriptive exception if the connection error was caused by
|
|
88
|
+
the sandbox being killed mid-request. If the sandbox is still running
|
|
89
|
+
(or its state can't be determined), returns so the caller can re-raise
|
|
90
|
+
the original error.
|
|
91
|
+
"""
|
|
92
|
+
try:
|
|
93
|
+
running = self.is_running()
|
|
94
|
+
except Exception:
|
|
95
|
+
# The state check itself failed, so we can't tell whether the
|
|
96
|
+
# sandbox was killed — let the caller re-raise the original error
|
|
97
|
+
# instead of wrongly claiming the sandbox is gone.
|
|
98
|
+
return
|
|
99
|
+
if not running:
|
|
100
|
+
raise format_sandbox_killed_error() from err
|
|
79
101
|
|
|
80
102
|
@overload
|
|
81
103
|
def run_code(
|
|
@@ -171,7 +193,11 @@ class Sandbox(BaseSandbox):
|
|
|
171
193
|
context_id = context.id if context else None
|
|
172
194
|
|
|
173
195
|
try:
|
|
174
|
-
headers: Dict[str, str] = {
|
|
196
|
+
headers: Dict[str, str] = {
|
|
197
|
+
"Content-Type": "application/json",
|
|
198
|
+
"E2b-Sandbox-Id": self.sandbox_id,
|
|
199
|
+
"E2b-Sandbox-Port": str(JUPYTER_PORT),
|
|
200
|
+
}
|
|
175
201
|
if self._envd_access_token:
|
|
176
202
|
headers["X-Access-Token"] = self._envd_access_token
|
|
177
203
|
if self.traffic_access_token:
|
|
@@ -187,7 +213,22 @@ class Sandbox(BaseSandbox):
|
|
|
187
213
|
"env_vars": envs,
|
|
188
214
|
},
|
|
189
215
|
headers=headers,
|
|
190
|
-
timeout
|
|
216
|
+
# `timeout` bounds the execution, `request_timeout` only the
|
|
217
|
+
# connect. Every non-connect phase must carry `timeout`: the
|
|
218
|
+
# SDK's pyqwest-backed transport collapses the per-phase
|
|
219
|
+
# timeouts into a single whole-request deadline and takes the
|
|
220
|
+
# longest of them, so leaving `request_timeout` on the write
|
|
221
|
+
# and pool phases would raise the floor to
|
|
222
|
+
# `max(timeout, request_timeout)` and silently ignore any
|
|
223
|
+
# `timeout` shorter than it. This matches the JS SDK, which
|
|
224
|
+
# aborts the execution on a `timeout`-long timer.
|
|
225
|
+
# `timeout=0` disables the deadline entirely; the transport
|
|
226
|
+
# still bounds connect on its own.
|
|
227
|
+
timeout=(
|
|
228
|
+
httpx.Timeout(timeout, connect=request_timeout)
|
|
229
|
+
if timeout is not None
|
|
230
|
+
else httpx.Timeout(None)
|
|
231
|
+
),
|
|
191
232
|
) as response:
|
|
192
233
|
err = extract_exception(response)
|
|
193
234
|
if err:
|
|
@@ -210,6 +251,9 @@ class Sandbox(BaseSandbox):
|
|
|
210
251
|
raise format_execution_timeout_error()
|
|
211
252
|
except httpx.TimeoutException:
|
|
212
253
|
raise format_request_timeout_error()
|
|
254
|
+
except (httpx.ReadError, httpx.RemoteProtocolError) as err:
|
|
255
|
+
self._handle_connection_error(err)
|
|
256
|
+
raise
|
|
213
257
|
|
|
214
258
|
def create_code_context(
|
|
215
259
|
self,
|
|
@@ -235,9 +279,11 @@ class Sandbox(BaseSandbox):
|
|
|
235
279
|
data["cwd"] = cwd
|
|
236
280
|
|
|
237
281
|
try:
|
|
238
|
-
headers: Dict[str, str] = {
|
|
239
|
-
|
|
240
|
-
|
|
282
|
+
headers: Dict[str, str] = {
|
|
283
|
+
"Content-Type": "application/json",
|
|
284
|
+
"E2b-Sandbox-Id": self.sandbox_id,
|
|
285
|
+
"E2b-Sandbox-Port": str(JUPYTER_PORT),
|
|
286
|
+
}
|
|
241
287
|
if self.traffic_access_token:
|
|
242
288
|
headers["E2B-Traffic-Access-Token"] = self.traffic_access_token
|
|
243
289
|
|
|
@@ -256,6 +302,9 @@ class Sandbox(BaseSandbox):
|
|
|
256
302
|
return Context.from_json(data)
|
|
257
303
|
except httpx.TimeoutException:
|
|
258
304
|
raise format_request_timeout_error()
|
|
305
|
+
except (httpx.ReadError, httpx.RemoteProtocolError) as err:
|
|
306
|
+
self._handle_connection_error(err)
|
|
307
|
+
raise
|
|
259
308
|
|
|
260
309
|
def remove_code_context(
|
|
261
310
|
self,
|
|
@@ -271,9 +320,11 @@ class Sandbox(BaseSandbox):
|
|
|
271
320
|
context_id = context.id if isinstance(context, Context) else context
|
|
272
321
|
|
|
273
322
|
try:
|
|
274
|
-
headers: Dict[str, str] = {
|
|
275
|
-
|
|
276
|
-
|
|
323
|
+
headers: Dict[str, str] = {
|
|
324
|
+
"Content-Type": "application/json",
|
|
325
|
+
"E2b-Sandbox-Id": self.sandbox_id,
|
|
326
|
+
"E2b-Sandbox-Port": str(JUPYTER_PORT),
|
|
327
|
+
}
|
|
277
328
|
if self.traffic_access_token:
|
|
278
329
|
headers["E2B-Traffic-Access-Token"] = self.traffic_access_token
|
|
279
330
|
|
|
@@ -288,6 +339,9 @@ class Sandbox(BaseSandbox):
|
|
|
288
339
|
raise err
|
|
289
340
|
except httpx.TimeoutException:
|
|
290
341
|
raise format_request_timeout_error()
|
|
342
|
+
except (httpx.ReadError, httpx.RemoteProtocolError) as err:
|
|
343
|
+
self._handle_connection_error(err)
|
|
344
|
+
raise
|
|
291
345
|
|
|
292
346
|
def list_code_contexts(self) -> List[Context]:
|
|
293
347
|
"""
|
|
@@ -296,9 +350,11 @@ class Sandbox(BaseSandbox):
|
|
|
296
350
|
:return: List of contexts.
|
|
297
351
|
"""
|
|
298
352
|
try:
|
|
299
|
-
headers: Dict[str, str] = {
|
|
300
|
-
|
|
301
|
-
|
|
353
|
+
headers: Dict[str, str] = {
|
|
354
|
+
"Content-Type": "application/json",
|
|
355
|
+
"E2b-Sandbox-Id": self.sandbox_id,
|
|
356
|
+
"E2b-Sandbox-Port": str(JUPYTER_PORT),
|
|
357
|
+
}
|
|
302
358
|
if self.traffic_access_token:
|
|
303
359
|
headers["E2B-Traffic-Access-Token"] = self.traffic_access_token
|
|
304
360
|
|
|
@@ -316,6 +372,9 @@ class Sandbox(BaseSandbox):
|
|
|
316
372
|
return [Context.from_json(context_data) for context_data in data]
|
|
317
373
|
except httpx.TimeoutException:
|
|
318
374
|
raise format_request_timeout_error()
|
|
375
|
+
except (httpx.ReadError, httpx.RemoteProtocolError) as err:
|
|
376
|
+
self._handle_connection_error(err)
|
|
377
|
+
raise
|
|
319
378
|
|
|
320
379
|
def restart_code_context(
|
|
321
380
|
self,
|
|
@@ -331,9 +390,11 @@ class Sandbox(BaseSandbox):
|
|
|
331
390
|
context_id = context.id if isinstance(context, Context) else context
|
|
332
391
|
|
|
333
392
|
try:
|
|
334
|
-
headers: Dict[str, str] = {
|
|
335
|
-
|
|
336
|
-
|
|
393
|
+
headers: Dict[str, str] = {
|
|
394
|
+
"Content-Type": "application/json",
|
|
395
|
+
"E2b-Sandbox-Id": self.sandbox_id,
|
|
396
|
+
"E2b-Sandbox-Port": str(JUPYTER_PORT),
|
|
397
|
+
}
|
|
337
398
|
if self.traffic_access_token:
|
|
338
399
|
headers["E2B-Traffic-Access-Token"] = self.traffic_access_token
|
|
339
400
|
|
|
@@ -348,3 +409,6 @@ class Sandbox(BaseSandbox):
|
|
|
348
409
|
raise err
|
|
349
410
|
except httpx.TimeoutException:
|
|
350
411
|
raise format_request_timeout_error()
|
|
412
|
+
except (httpx.ReadError, httpx.RemoteProtocolError) as err:
|
|
413
|
+
self._handle_connection_error(err)
|
|
414
|
+
raise
|
{e2b_code_interpreter-2.8.0 → e2b_code_interpreter-2.11.0}/e2b_code_interpreter/exceptions.py
RENAMED
|
@@ -11,3 +11,10 @@ def format_execution_timeout_error() -> Exception:
|
|
|
11
11
|
return TimeoutException(
|
|
12
12
|
"Execution timed out — the 'timeout' option can be used to increase this timeout",
|
|
13
13
|
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def format_sandbox_killed_error() -> Exception:
|
|
17
|
+
return TimeoutException(
|
|
18
|
+
"The sandbox was killed while the request was in progress. This can happen when the sandbox times out or is killed manually. "
|
|
19
|
+
"You can modify the sandbox timeout by passing 'timeout' when starting the sandbox or calling '.set_timeout' on the sandbox with the desired timeout",
|
|
20
|
+
)
|
|
@@ -207,7 +207,7 @@ class Result:
|
|
|
207
207
|
|
|
208
208
|
return formats
|
|
209
209
|
|
|
210
|
-
def __str__(self) ->
|
|
210
|
+
def __str__(self) -> str:
|
|
211
211
|
"""
|
|
212
212
|
Returns the text representation of the data.
|
|
213
213
|
|
|
@@ -305,7 +305,12 @@ class Logs:
|
|
|
305
305
|
stderr: List[str] = field(default_factory=list)
|
|
306
306
|
"""List of strings printed to stderr by prints, subprocesses, etc."""
|
|
307
307
|
|
|
308
|
-
def __init__(
|
|
308
|
+
def __init__(
|
|
309
|
+
self,
|
|
310
|
+
stdout: Optional[List[str]] = None,
|
|
311
|
+
stderr: Optional[List[str]] = None,
|
|
312
|
+
**kwargs,
|
|
313
|
+
):
|
|
309
314
|
self.stdout = stdout or []
|
|
310
315
|
self.stderr = stderr or []
|
|
311
316
|
|
|
@@ -329,7 +334,9 @@ def serialize_results(results: List[Result]) -> List[Dict[str, str]]:
|
|
|
329
334
|
serialized_dict = {}
|
|
330
335
|
for key in result.formats():
|
|
331
336
|
if key == "chart":
|
|
332
|
-
|
|
337
|
+
chart = result.chart
|
|
338
|
+
if chart is not None:
|
|
339
|
+
serialized_dict[key] = chart.to_dict()
|
|
333
340
|
else:
|
|
334
341
|
serialized_dict[key] = result[key]
|
|
335
342
|
|
|
@@ -356,8 +363,8 @@ class Execution:
|
|
|
356
363
|
|
|
357
364
|
def __init__(
|
|
358
365
|
self,
|
|
359
|
-
results: List[Result] = None,
|
|
360
|
-
logs: Logs = None,
|
|
366
|
+
results: Optional[List[Result]] = None,
|
|
367
|
+
logs: Optional[Logs] = None,
|
|
361
368
|
error: Optional[ExecutionError] = None,
|
|
362
369
|
execution_count: Optional[int] = None,
|
|
363
370
|
**kwargs,
|
|
@@ -420,7 +427,10 @@ def format_exception(res: Response):
|
|
|
420
427
|
f"{res.text}: This error is likely due to sandbox timeout. You can modify the sandbox timeout by passing 'timeout' when starting the sandbox or calling '.set_timeout' on the sandbox with the desired timeout."
|
|
421
428
|
)
|
|
422
429
|
else:
|
|
423
|
-
|
|
430
|
+
body = res.text.strip()
|
|
431
|
+
return SandboxException(
|
|
432
|
+
f"{res.status_code} {res.reason_phrase}{f': {body}' if body else ''}"
|
|
433
|
+
)
|
|
424
434
|
|
|
425
435
|
|
|
426
436
|
def parse_output(
|
|
@@ -510,7 +520,7 @@ class Context:
|
|
|
510
520
|
@classmethod
|
|
511
521
|
def from_json(cls, data: Dict[str, str]):
|
|
512
522
|
return cls(
|
|
513
|
-
context_id=data
|
|
514
|
-
language=data
|
|
515
|
-
cwd=data
|
|
523
|
+
context_id=data["id"],
|
|
524
|
+
language=data["language"],
|
|
525
|
+
cwd=data["cwd"],
|
|
516
526
|
)
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "e2b-code-interpreter"
|
|
3
|
+
version = "2.11.0"
|
|
4
|
+
description = "E2B Code Interpreter - Stateful code execution"
|
|
5
|
+
authors = [{ name = "e2b", email = "hello@e2b.dev" }]
|
|
6
|
+
license = "MIT"
|
|
7
|
+
readme = "README.md"
|
|
8
|
+
requires-python = ">=3.11"
|
|
9
|
+
dependencies = [
|
|
10
|
+
"httpx>=0.20.0,<1.0.0",
|
|
11
|
+
"attrs>=21.3.0",
|
|
12
|
+
"e2b>=2.55.1,<3.0.0",
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
[project.urls]
|
|
16
|
+
Homepage = "https://e2b.dev/?utm_source=pypi&utm_medium=referral&utm_campaign=package_homepage&utm_content=e2b-code-interpreter"
|
|
17
|
+
Repository = "https://github.com/e2b-dev/e2b/tree/main/packages/code-interpreter-python"
|
|
18
|
+
"Bug Tracker" = "https://github.com/e2b-dev/e2b/issues"
|
|
19
|
+
|
|
20
|
+
[dependency-groups]
|
|
21
|
+
dev = [
|
|
22
|
+
"pytest>=9.0.3,<10",
|
|
23
|
+
"python-dotenv>=1.0.0,<2",
|
|
24
|
+
"pytest-dotenv>=0.5.2,<0.6",
|
|
25
|
+
"pytest-asyncio>=1.3.0,<2",
|
|
26
|
+
"pytest-xdist>=3.6.1,<4",
|
|
27
|
+
"matplotlib>=3.8.0,<4",
|
|
28
|
+
"ruff>=0.11.12,<0.12",
|
|
29
|
+
"ty>=0.0.15,<0.0.16",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
[build-system]
|
|
33
|
+
requires = ["uv_build>=0.10.0,<0.11.0"]
|
|
34
|
+
build-backend = "uv_build"
|
|
35
|
+
|
|
36
|
+
[tool.uv.build-backend]
|
|
37
|
+
module-name = ["e2b_code_interpreter"]
|
|
38
|
+
module-root = ""
|
|
39
|
+
|
|
40
|
+
[tool.uv.sources]
|
|
41
|
+
e2b = { workspace = true }
|
|
42
|
+
|
|
43
|
+
[tool.uv.workspace]
|
|
44
|
+
members = ["../python-sdk"]
|
|
45
|
+
|
|
46
|
+
[tool.ruff.lint]
|
|
47
|
+
ignore = ["F401", "F403"]
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2025 FOUNDRYLABS, INC.
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
-
|
|
7
|
-
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
-
|
|
9
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: e2b-code-interpreter
|
|
3
|
-
Version: 2.8.0
|
|
4
|
-
Summary: E2B Code Interpreter - Stateful code execution
|
|
5
|
-
Home-page: https://e2b.dev/
|
|
6
|
-
License: MIT
|
|
7
|
-
Author: e2b
|
|
8
|
-
Author-email: hello@e2b.dev
|
|
9
|
-
Requires-Python: >=3.10,<4.0
|
|
10
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
-
Classifier: Programming Language :: Python :: 3
|
|
12
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
-
Requires-Dist: attrs (>=21.3.0)
|
|
17
|
-
Requires-Dist: e2b (>=2.26.0,<3.0.0)
|
|
18
|
-
Requires-Dist: httpx (>=0.20.0,<1.0.0)
|
|
19
|
-
Project-URL: Bug Tracker, https://github.com/e2b-dev/code-interpreter/issues
|
|
20
|
-
Project-URL: Repository, https://github.com/e2b-dev/code-interpreter/tree/main/python
|
|
21
|
-
Description-Content-Type: text/markdown
|
|
22
|
-
|
|
23
|
-
<p align="center">
|
|
24
|
-
<img width="100" src="https://raw.githubusercontent.com/e2b-dev/E2B/refs/heads/main/readme-assets/logo-circle.png" alt="e2b logo">
|
|
25
|
-
</p>
|
|
26
|
-
|
|
27
|
-
<h4 align="center">
|
|
28
|
-
<a href="https://pypi.org/project/e2b/">
|
|
29
|
-
<img alt="Last 1 month downloads for the Python SDK" loading="lazy" width="200" height="20" decoding="async" data-nimg="1"
|
|
30
|
-
style="color:transparent;width:auto;height:100%" src="https://img.shields.io/pypi/dm/e2b?label=PyPI%20Downloads">
|
|
31
|
-
</a>
|
|
32
|
-
</h4>
|
|
33
|
-
|
|
34
|
-
<!---
|
|
35
|
-
<img width="100%" src="/readme-assets/preview.png" alt="Cover image">
|
|
36
|
-
--->
|
|
37
|
-
## What is E2B?
|
|
38
|
-
[E2B](https://www.e2b.dev/) is an open-source infrastructure that allows you run to AI-generated code in secure isolated sandboxes in the cloud. To start and control sandboxes, use our [JavaScript SDK](https://www.npmjs.com/package/@e2b/code-interpreter) or [Python SDK](https://pypi.org/project/e2b_code_interpreter).
|
|
39
|
-
|
|
40
|
-
## Run your first Sandbox
|
|
41
|
-
|
|
42
|
-
### 1. Install SDK
|
|
43
|
-
|
|
44
|
-
```
|
|
45
|
-
pip install e2b-code-interpreter
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
### 2. Get your E2B API key
|
|
49
|
-
1. Sign up to E2B [here](https://e2b.dev).
|
|
50
|
-
2. Get your API key [here](https://e2b.dev/dashboard?tab=keys).
|
|
51
|
-
3. Set environment variable with your API key.
|
|
52
|
-
```
|
|
53
|
-
E2B_API_KEY=e2b_***
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
### 3. Execute code with code interpreter inside Sandbox
|
|
57
|
-
|
|
58
|
-
```py
|
|
59
|
-
from e2b_code_interpreter import Sandbox
|
|
60
|
-
|
|
61
|
-
with Sandbox.create() as sandbox:
|
|
62
|
-
sandbox.run_code("x = 1")
|
|
63
|
-
execution = sandbox.run_code("x+=1; x")
|
|
64
|
-
print(execution.text) # outputs 2
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
### 4. Check docs
|
|
68
|
-
Visit [E2B documentation](https://e2b.dev/docs).
|
|
69
|
-
|
|
70
|
-
### 5. E2B cookbook
|
|
71
|
-
Visit our [Cookbook](https://github.com/e2b-dev/e2b-cookbook/tree/main) to get inspired by examples with different LLMs and AI frameworks.
|
|
72
|
-
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
<p align="center">
|
|
2
|
-
<img width="100" src="https://raw.githubusercontent.com/e2b-dev/E2B/refs/heads/main/readme-assets/logo-circle.png" alt="e2b logo">
|
|
3
|
-
</p>
|
|
4
|
-
|
|
5
|
-
<h4 align="center">
|
|
6
|
-
<a href="https://pypi.org/project/e2b/">
|
|
7
|
-
<img alt="Last 1 month downloads for the Python SDK" loading="lazy" width="200" height="20" decoding="async" data-nimg="1"
|
|
8
|
-
style="color:transparent;width:auto;height:100%" src="https://img.shields.io/pypi/dm/e2b?label=PyPI%20Downloads">
|
|
9
|
-
</a>
|
|
10
|
-
</h4>
|
|
11
|
-
|
|
12
|
-
<!---
|
|
13
|
-
<img width="100%" src="/readme-assets/preview.png" alt="Cover image">
|
|
14
|
-
--->
|
|
15
|
-
## What is E2B?
|
|
16
|
-
[E2B](https://www.e2b.dev/) is an open-source infrastructure that allows you run to AI-generated code in secure isolated sandboxes in the cloud. To start and control sandboxes, use our [JavaScript SDK](https://www.npmjs.com/package/@e2b/code-interpreter) or [Python SDK](https://pypi.org/project/e2b_code_interpreter).
|
|
17
|
-
|
|
18
|
-
## Run your first Sandbox
|
|
19
|
-
|
|
20
|
-
### 1. Install SDK
|
|
21
|
-
|
|
22
|
-
```
|
|
23
|
-
pip install e2b-code-interpreter
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
### 2. Get your E2B API key
|
|
27
|
-
1. Sign up to E2B [here](https://e2b.dev).
|
|
28
|
-
2. Get your API key [here](https://e2b.dev/dashboard?tab=keys).
|
|
29
|
-
3. Set environment variable with your API key.
|
|
30
|
-
```
|
|
31
|
-
E2B_API_KEY=e2b_***
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
### 3. Execute code with code interpreter inside Sandbox
|
|
35
|
-
|
|
36
|
-
```py
|
|
37
|
-
from e2b_code_interpreter import Sandbox
|
|
38
|
-
|
|
39
|
-
with Sandbox.create() as sandbox:
|
|
40
|
-
sandbox.run_code("x = 1")
|
|
41
|
-
execution = sandbox.run_code("x+=1; x")
|
|
42
|
-
print(execution.text) # outputs 2
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
### 4. Check docs
|
|
46
|
-
Visit [E2B documentation](https://e2b.dev/docs).
|
|
47
|
-
|
|
48
|
-
### 5. E2B cookbook
|
|
49
|
-
Visit our [Cookbook](https://github.com/e2b-dev/e2b-cookbook/tree/main) to get inspired by examples with different LLMs and AI frameworks.
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
[tool.poetry]
|
|
2
|
-
name = "e2b-code-interpreter"
|
|
3
|
-
version = "2.8.0"
|
|
4
|
-
description = "E2B Code Interpreter - Stateful code execution"
|
|
5
|
-
authors = ["e2b <hello@e2b.dev>"]
|
|
6
|
-
license = "MIT"
|
|
7
|
-
readme = "README.md"
|
|
8
|
-
homepage = "https://e2b.dev/"
|
|
9
|
-
repository = "https://github.com/e2b-dev/code-interpreter/tree/main/python"
|
|
10
|
-
packages = [{ include = "e2b_code_interpreter" }]
|
|
11
|
-
|
|
12
|
-
[tool.poetry.dependencies]
|
|
13
|
-
python = "^3.10"
|
|
14
|
-
|
|
15
|
-
httpx = ">=0.20.0, <1.0.0"
|
|
16
|
-
attrs = ">=21.3.0"
|
|
17
|
-
e2b = "^2.26.0"
|
|
18
|
-
|
|
19
|
-
[tool.poetry.group.dev.dependencies]
|
|
20
|
-
pytest = "^9.0.3"
|
|
21
|
-
python-dotenv = "^1.0.0"
|
|
22
|
-
pytest-dotenv = "^0.5.2"
|
|
23
|
-
pytest-asyncio = "^1.3.0"
|
|
24
|
-
pytest-xdist = "^3.6.1"
|
|
25
|
-
matplotlib = "^3.8.0"
|
|
26
|
-
ruff = "^0.11.12"
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
[build-system]
|
|
30
|
-
requires = ["poetry-core"]
|
|
31
|
-
build-backend = "poetry.core.masonry.api"
|
|
32
|
-
|
|
33
|
-
[tool.poetry.urls]
|
|
34
|
-
"Bug Tracker" = "https://github.com/e2b-dev/code-interpreter/issues"
|
|
35
|
-
|
|
36
|
-
[tool.ruff.lint]
|
|
37
|
-
ignore = ["F401", "F403"]
|
{e2b_code_interpreter-2.8.0 → e2b_code_interpreter-2.11.0}/e2b_code_interpreter/constants.py
RENAMED
|
File without changes
|