e2b-code-interpreter 2.9.2__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.
@@ -1,34 +1,16 @@
1
- Metadata-Version: 2.3
2
- Name: e2b-code-interpreter
3
- Version: 2.9.2
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/?utm_source=pypi&utm_medium=referral&utm_campaign=package_homepage&utm_content=e2b-code-interpreter
20
- Project-URL: Repository, https://github.com/e2b-dev/code-interpreter/tree/main/python
21
- Description-Content-Type: text/markdown
22
-
23
1
  <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">
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>
25
7
  </p>
26
8
 
27
9
  <h4 align="center">
28
10
  <a href="https://pypi.org/project/e2b/">
29
11
  <img alt="Last 1 month downloads for the Python SDK" loading="lazy" width="200" height="20" decoding="async" data-nimg="1"
30
12
  style="color:transparent;width:auto;height:100%" src="https://img.shields.io/pypi/dm/e2b?label=PyPI%20Downloads">
31
- </a>
13
+ </a>
32
14
  </h4>
33
15
 
34
16
  <!---
@@ -37,6 +19,8 @@ Description-Content-Type: text/markdown
37
19
  ## What is E2B?
38
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).
39
21
 
22
+ Source: [packages/code-interpreter-python](https://github.com/e2b-dev/E2B/tree/main/packages/code-interpreter-python)
23
+
40
24
  ## Run your first Sandbox
41
25
 
42
26
  ### 1. Install SDK
@@ -51,7 +35,7 @@ pip install e2b-code-interpreter
51
35
  3. Set environment variable with your API key.
52
36
  ```
53
37
  E2B_API_KEY=e2b_***
54
- ```
38
+ ```
55
39
 
56
40
  ### 3. Execute code with code interpreter inside Sandbox
57
41
 
@@ -64,9 +48,35 @@ with Sandbox.create() as sandbox:
64
48
  print(execution.text) # outputs 2
65
49
  ```
66
50
 
67
- ### 4. Check docs
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
68
79
  Visit [E2B documentation](https://docs.e2b.dev/?utm_source=pypi&utm_medium=referral&utm_campaign=readme&utm_content=code-interpreter).
69
80
 
70
- ### 5. E2B cookbook
81
+ ### 6. E2B cookbook
71
82
  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,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 (
@@ -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."""
@@ -68,6 +68,18 @@ class AsyncSandbox(BaseAsyncSandbox):
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:
@@ -65,6 +65,18 @@ class Sandbox(BaseSandbox):
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:
@@ -400,34 +400,41 @@ class Execution:
400
400
  return json.dumps(data)
401
401
 
402
402
 
403
- async def aextract_exception(res: Response):
403
+ async def aextract_exception(res: Response, include_diagnostics: bool = False):
404
404
  if res.is_success:
405
405
  return None
406
406
 
407
407
  await res.aread()
408
- return extract_exception(res)
408
+ return extract_exception(res, include_diagnostics)
409
409
 
410
410
 
411
- def extract_exception(res: Response):
411
+ def extract_exception(res: Response, include_diagnostics: bool = False):
412
412
  if res.is_success:
413
413
  return None
414
414
 
415
415
  res.read()
416
- return format_exception(res)
416
+ return format_exception(res, include_diagnostics)
417
417
 
418
418
 
419
- def format_exception(res: Response):
419
+ def format_exception(res: Response, include_diagnostics: bool = False):
420
420
  if res.is_success:
421
421
  return None
422
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
+
423
427
  if res.status_code == 404:
424
- return NotFoundException(res.text)
428
+ return NotFoundException(f"{body}{trace_suffix}")
425
429
  elif res.status_code == 502:
426
430
  return TimeoutException(
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."
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}"
428
432
  )
429
433
  else:
430
- 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
+ )
431
438
 
432
439
 
433
440
  def parse_output(
@@ -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,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://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).
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/?utm_source=pypi&utm_medium=referral&utm_campaign=readme&utm_content=code-interpreter).
28
- 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).
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://docs.e2b.dev/?utm_source=pypi&utm_medium=referral&utm_campaign=readme&utm_content=code-interpreter).
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.2"
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/?utm_source=pypi&utm_medium=referral&utm_campaign=package_homepage&utm_content=e2b-code-interpreter"
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"]