e2b-code-interpreter 2.9.1__tar.gz → 2.10.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.
@@ -0,0 +1,98 @@
1
+ Metadata-Version: 2.4
2
+ Name: e2b-code-interpreter
3
+ Version: 2.10.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.44.0,<3.0.0
11
+ Requires-Python: >=3.10
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.
@@ -1,4 +1,5 @@
1
1
  from e2b import *
2
+ from .client import E2B, E2BClientParams
2
3
  from .code_interpreter_sync import Sandbox
3
4
  from .code_interpreter_async import AsyncSandbox
4
5
  from .models import (
@@ -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 = [_deserialize_chart(g) for g in kwargs["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."""
@@ -1,7 +1,7 @@
1
1
  import logging
2
2
  import httpx
3
3
 
4
- from typing import Optional, Dict, overload, Union, List
4
+ from typing import cast, Optional, Dict, overload, Union, List
5
5
  from httpx import AsyncClient
6
6
 
7
7
  from e2b import (
@@ -63,11 +63,23 @@ class AsyncSandbox(BaseAsyncSandbox):
63
63
  def _jupyter_url(self) -> str:
64
64
  # Honors the `sandbox_url` option and the `E2B_SANDBOX_URL` environment
65
65
  # variable, same as the base SDK does for envd requests.
66
- sandbox_url = self.connection_config._sandbox_url
66
+ sandbox_url = cast(Optional[str], self.connection_config._sandbox_url)
67
67
  if sandbox_url:
68
68
  return sandbox_url
69
69
  return f"{'http' if self.connection_config.debug else 'https'}://{self.get_host(JUPYTER_PORT)}"
70
70
 
71
+ def _jupyter_request_url(self, path: str) -> str:
72
+ url = f"{self._jupyter_url}{path}"
73
+ source = getattr(self.connection_config, "request_source", None)
74
+ if not source:
75
+ return url
76
+ separator = "&" if "?" in url else "?"
77
+ return f"{url}{separator}source={source}"
78
+
79
+ @property
80
+ def _include_diagnostics(self) -> bool:
81
+ return getattr(self.connection_config, "request_source", None) == "ci"
82
+
71
83
  @property
72
84
  def _client(self) -> AsyncClient:
73
85
  # TODO: Remove later
@@ -211,7 +223,7 @@ class AsyncSandbox(BaseAsyncSandbox):
211
223
 
212
224
  async with self._client.stream(
213
225
  "POST",
214
- f"{self._jupyter_url}/execute",
226
+ self._jupyter_request_url("/execute"),
215
227
  json={
216
228
  "code": code,
217
229
  "context_id": context_id,
@@ -236,7 +248,7 @@ class AsyncSandbox(BaseAsyncSandbox):
236
248
  else httpx.Timeout(None)
237
249
  ),
238
250
  ) as response:
239
- err = await aextract_exception(response)
251
+ err = await aextract_exception(response, self._include_diagnostics)
240
252
  if err:
241
253
  raise err
242
254
 
@@ -294,13 +306,13 @@ class AsyncSandbox(BaseAsyncSandbox):
294
306
  headers["E2B-Traffic-Access-Token"] = self.traffic_access_token
295
307
 
296
308
  response = await self._client.post(
297
- f"{self._jupyter_url}/contexts",
309
+ self._jupyter_request_url("/contexts"),
298
310
  headers=headers,
299
311
  json=data,
300
312
  timeout=request_timeout or self.connection_config.request_timeout,
301
313
  )
302
314
 
303
- err = await aextract_exception(response)
315
+ err = await aextract_exception(response, self._include_diagnostics)
304
316
  if err:
305
317
  raise err
306
318
 
@@ -335,12 +347,12 @@ class AsyncSandbox(BaseAsyncSandbox):
335
347
  headers["E2B-Traffic-Access-Token"] = self.traffic_access_token
336
348
 
337
349
  response = await self._client.delete(
338
- f"{self._jupyter_url}/contexts/{context_id}",
350
+ self._jupyter_request_url(f"/contexts/{context_id}"),
339
351
  headers=headers,
340
352
  timeout=self.connection_config.request_timeout,
341
353
  )
342
354
 
343
- err = await aextract_exception(response)
355
+ err = await aextract_exception(response, self._include_diagnostics)
344
356
  if err:
345
357
  raise err
346
358
  except httpx.TimeoutException:
@@ -365,12 +377,12 @@ class AsyncSandbox(BaseAsyncSandbox):
365
377
  headers["E2B-Traffic-Access-Token"] = self.traffic_access_token
366
378
 
367
379
  response = await self._client.get(
368
- f"{self._jupyter_url}/contexts",
380
+ self._jupyter_request_url("/contexts"),
369
381
  headers=headers,
370
382
  timeout=self.connection_config.request_timeout,
371
383
  )
372
384
 
373
- err = await aextract_exception(response)
385
+ err = await aextract_exception(response, self._include_diagnostics)
374
386
  if err:
375
387
  raise err
376
388
 
@@ -404,12 +416,12 @@ class AsyncSandbox(BaseAsyncSandbox):
404
416
  headers["E2B-Traffic-Access-Token"] = self.traffic_access_token
405
417
 
406
418
  response = await self._client.post(
407
- f"{self._jupyter_url}/contexts/{context_id}/restart",
419
+ self._jupyter_request_url(f"/contexts/{context_id}/restart"),
408
420
  headers=headers,
409
421
  timeout=self.connection_config.request_timeout,
410
422
  )
411
423
 
412
- err = await aextract_exception(response)
424
+ err = await aextract_exception(response, self._include_diagnostics)
413
425
  if err:
414
426
  raise err
415
427
  except httpx.TimeoutException:
@@ -1,7 +1,7 @@
1
1
  import logging
2
2
  import httpx
3
3
 
4
- from typing import Optional, Dict, overload, Union, List
4
+ from typing import cast, Optional, Dict, overload, Union, List
5
5
  from httpx import Client
6
6
  from e2b import Sandbox as BaseSandbox, InvalidArgumentException
7
7
  from e2b.api.client_sync import get_transport
@@ -60,11 +60,23 @@ class Sandbox(BaseSandbox):
60
60
  def _jupyter_url(self) -> str:
61
61
  # Honors the `sandbox_url` option and the `E2B_SANDBOX_URL` environment
62
62
  # variable, same as the base SDK does for envd requests.
63
- sandbox_url = self.connection_config._sandbox_url
63
+ sandbox_url = cast(Optional[str], self.connection_config._sandbox_url)
64
64
  if sandbox_url:
65
65
  return sandbox_url
66
66
  return f"{'http' if self.connection_config.debug else 'https'}://{self.get_host(JUPYTER_PORT)}"
67
67
 
68
+ def _jupyter_request_url(self, path: str) -> str:
69
+ url = f"{self._jupyter_url}{path}"
70
+ source = getattr(self.connection_config, "request_source", None)
71
+ if not source:
72
+ return url
73
+ separator = "&" if "?" in url else "?"
74
+ return f"{url}{separator}source={source}"
75
+
76
+ @property
77
+ def _include_diagnostics(self) -> bool:
78
+ return getattr(self.connection_config, "request_source", None) == "ci"
79
+
68
80
  @property
69
81
  def _client(self) -> Client:
70
82
  # TODO: Remove later
@@ -206,7 +218,7 @@ class Sandbox(BaseSandbox):
206
218
 
207
219
  with self._client.stream(
208
220
  "POST",
209
- f"{self._jupyter_url}/execute",
221
+ self._jupyter_request_url("/execute"),
210
222
  json={
211
223
  "code": code,
212
224
  "context_id": context_id,
@@ -231,7 +243,7 @@ class Sandbox(BaseSandbox):
231
243
  else httpx.Timeout(None)
232
244
  ),
233
245
  ) as response:
234
- err = extract_exception(response)
246
+ err = extract_exception(response, self._include_diagnostics)
235
247
  if err:
236
248
  raise err
237
249
 
@@ -289,13 +301,13 @@ class Sandbox(BaseSandbox):
289
301
  headers["E2B-Traffic-Access-Token"] = self.traffic_access_token
290
302
 
291
303
  response = self._client.post(
292
- f"{self._jupyter_url}/contexts",
304
+ self._jupyter_request_url("/contexts"),
293
305
  json=data,
294
306
  headers=headers,
295
307
  timeout=request_timeout or self.connection_config.request_timeout,
296
308
  )
297
309
 
298
- err = extract_exception(response)
310
+ err = extract_exception(response, self._include_diagnostics)
299
311
  if err:
300
312
  raise err
301
313
 
@@ -330,12 +342,12 @@ class Sandbox(BaseSandbox):
330
342
  headers["E2B-Traffic-Access-Token"] = self.traffic_access_token
331
343
 
332
344
  response = self._client.delete(
333
- f"{self._jupyter_url}/contexts/{context_id}",
345
+ self._jupyter_request_url(f"/contexts/{context_id}"),
334
346
  headers=headers,
335
347
  timeout=self.connection_config.request_timeout,
336
348
  )
337
349
 
338
- err = extract_exception(response)
350
+ err = extract_exception(response, self._include_diagnostics)
339
351
  if err:
340
352
  raise err
341
353
  except httpx.TimeoutException:
@@ -360,12 +372,12 @@ class Sandbox(BaseSandbox):
360
372
  headers["E2B-Traffic-Access-Token"] = self.traffic_access_token
361
373
 
362
374
  response = self._client.get(
363
- f"{self._jupyter_url}/contexts",
375
+ self._jupyter_request_url("/contexts"),
364
376
  headers=headers,
365
377
  timeout=self.connection_config.request_timeout,
366
378
  )
367
379
 
368
- err = extract_exception(response)
380
+ err = extract_exception(response, self._include_diagnostics)
369
381
  if err:
370
382
  raise err
371
383
 
@@ -400,12 +412,12 @@ class Sandbox(BaseSandbox):
400
412
  headers["E2B-Traffic-Access-Token"] = self.traffic_access_token
401
413
 
402
414
  response = self._client.post(
403
- f"{self._jupyter_url}/contexts/{context_id}/restart",
415
+ self._jupyter_request_url(f"/contexts/{context_id}/restart"),
404
416
  headers=headers,
405
417
  timeout=self.connection_config.request_timeout,
406
418
  )
407
419
 
408
- err = extract_exception(response)
420
+ err = extract_exception(response, self._include_diagnostics)
409
421
  if err:
410
422
  raise err
411
423
  except httpx.TimeoutException:
@@ -207,7 +207,7 @@ class Result:
207
207
 
208
208
  return formats
209
209
 
210
- def __str__(self) -> Optional[str]:
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__(self, stdout: List[str] = None, stderr: List[str] = None, **kwargs):
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
- serialized_dict[key] = result.chart.to_dict()
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,
@@ -393,34 +400,41 @@ class Execution:
393
400
  return json.dumps(data)
394
401
 
395
402
 
396
- async def aextract_exception(res: Response):
403
+ async def aextract_exception(res: Response, include_diagnostics: bool = False):
397
404
  if res.is_success:
398
405
  return None
399
406
 
400
407
  await res.aread()
401
- return extract_exception(res)
408
+ return extract_exception(res, include_diagnostics)
402
409
 
403
410
 
404
- def extract_exception(res: Response):
411
+ def extract_exception(res: Response, include_diagnostics: bool = False):
405
412
  if res.is_success:
406
413
  return None
407
414
 
408
415
  res.read()
409
- return format_exception(res)
416
+ return format_exception(res, include_diagnostics)
410
417
 
411
418
 
412
- def format_exception(res: Response):
419
+ def format_exception(res: Response, include_diagnostics: bool = False):
413
420
  if res.is_success:
414
421
  return None
415
422
 
423
+ body = res.text
424
+ trace_id = res.headers.get("X-E2B-Trace-ID") if include_diagnostics else None
425
+ trace_suffix = f" (trace_id={trace_id})" if trace_id else ""
426
+
416
427
  if res.status_code == 404:
417
- return NotFoundException(res.text)
428
+ return NotFoundException(f"{body}{trace_suffix}")
418
429
  elif res.status_code == 502:
419
430
  return TimeoutException(
420
- 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."
431
+ f"{body}: 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.{trace_suffix}"
421
432
  )
422
433
  else:
423
- return SandboxException(f"{res.status_code}: {res.text}")
434
+ body_separator = "" if trace_suffix and not body else " "
435
+ return SandboxException(
436
+ f"{res.status_code}:{body_separator}{body}{trace_suffix}"
437
+ )
424
438
 
425
439
 
426
440
  def parse_output(
@@ -510,7 +524,7 @@ class Context:
510
524
  @classmethod
511
525
  def from_json(cls, data: Dict[str, str]):
512
526
  return cls(
513
- context_id=data.get("id"),
514
- language=data.get("language"),
515
- cwd=data.get("cwd"),
527
+ context_id=data["id"],
528
+ language=data["language"],
529
+ cwd=data["cwd"],
516
530
  )
@@ -0,0 +1,47 @@
1
+ [project]
2
+ name = "e2b-code-interpreter"
3
+ version = "2.10.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.10"
9
+ dependencies = [
10
+ "httpx>=0.20.0,<1.0.0",
11
+ "attrs>=21.3.0",
12
+ "e2b>=2.44.0,<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.3
2
- Name: e2b-code-interpreter
3
- Version: 2.9.1
4
- Summary: E2B Code Interpreter - Stateful code execution
5
- License: MIT
6
- Author: e2b
7
- Author-email: hello@e2b.dev
8
- Requires-Python: >=3.10,<4.0
9
- Classifier: License :: OSI Approved :: MIT License
10
- Classifier: Programming Language :: Python :: 3
11
- Classifier: Programming Language :: Python :: 3.10
12
- Classifier: Programming Language :: Python :: 3.11
13
- Classifier: Programming Language :: Python :: 3.12
14
- Classifier: Programming Language :: Python :: 3.13
15
- Requires-Dist: attrs (>=21.3.0)
16
- Requires-Dist: e2b (>=2.39.1,<3.0.0)
17
- Requires-Dist: httpx (>=0.20.0,<1.0.0)
18
- Project-URL: Bug Tracker, https://github.com/e2b-dev/code-interpreter/issues
19
- Project-URL: Homepage, https://e2b.dev/
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.9.1"
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.39.1"
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"]