e2b-code-interpreter 2.8.0__tar.gz → 2.9.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.8.0 → e2b_code_interpreter-2.9.0}/PKG-INFO +1 -1
- {e2b_code_interpreter-2.8.0 → e2b_code_interpreter-2.9.0}/e2b_code_interpreter/code_interpreter_async.py +48 -0
- {e2b_code_interpreter-2.8.0 → e2b_code_interpreter-2.9.0}/e2b_code_interpreter/code_interpreter_sync.py +63 -13
- {e2b_code_interpreter-2.8.0 → e2b_code_interpreter-2.9.0}/e2b_code_interpreter/exceptions.py +7 -0
- {e2b_code_interpreter-2.8.0 → e2b_code_interpreter-2.9.0}/pyproject.toml +1 -1
- {e2b_code_interpreter-2.8.0 → e2b_code_interpreter-2.9.0}/LICENSE +0 -0
- {e2b_code_interpreter-2.8.0 → e2b_code_interpreter-2.9.0}/README.md +0 -0
- {e2b_code_interpreter-2.8.0 → e2b_code_interpreter-2.9.0}/e2b_code_interpreter/__init__.py +0 -0
- {e2b_code_interpreter-2.8.0 → e2b_code_interpreter-2.9.0}/e2b_code_interpreter/charts.py +0 -0
- {e2b_code_interpreter-2.8.0 → e2b_code_interpreter-2.9.0}/e2b_code_interpreter/constants.py +0 -0
- {e2b_code_interpreter-2.8.0 → e2b_code_interpreter-2.9.0}/e2b_code_interpreter/models.py +0 -0
|
@@ -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,6 +61,11 @@ class AsyncSandbox(BaseAsyncSandbox):
|
|
|
60
61
|
|
|
61
62
|
@property
|
|
62
63
|
def _jupyter_url(self) -> str:
|
|
64
|
+
# Honors the `sandbox_url` option and the `E2B_SANDBOX_URL` environment
|
|
65
|
+
# variable, same as the base SDK does for envd requests.
|
|
66
|
+
sandbox_url = self.connection_config._sandbox_url
|
|
67
|
+
if sandbox_url:
|
|
68
|
+
return sandbox_url
|
|
63
69
|
return f"{'http' if self.connection_config.debug else 'https'}://{self.get_host(JUPYTER_PORT)}"
|
|
64
70
|
|
|
65
71
|
@property
|
|
@@ -83,6 +89,23 @@ class AsyncSandbox(BaseAsyncSandbox):
|
|
|
83
89
|
transport=get_transport(self.connection_config, http2=False),
|
|
84
90
|
)
|
|
85
91
|
|
|
92
|
+
async def _handle_connection_error(self, err: Exception) -> None:
|
|
93
|
+
"""
|
|
94
|
+
Raises a descriptive exception if the connection error was caused by
|
|
95
|
+
the sandbox being killed mid-request. If the sandbox is still running
|
|
96
|
+
(or its state can't be determined), returns so the caller can re-raise
|
|
97
|
+
the original error.
|
|
98
|
+
"""
|
|
99
|
+
try:
|
|
100
|
+
running = await self.is_running()
|
|
101
|
+
except Exception:
|
|
102
|
+
# The state check itself failed, so we can't tell whether the
|
|
103
|
+
# sandbox was killed — let the caller re-raise the original error
|
|
104
|
+
# instead of wrongly claiming the sandbox is gone.
|
|
105
|
+
return
|
|
106
|
+
if not running:
|
|
107
|
+
raise format_sandbox_killed_error() from err
|
|
108
|
+
|
|
86
109
|
@overload
|
|
87
110
|
async def run_code(
|
|
88
111
|
self,
|
|
@@ -178,6 +201,8 @@ class AsyncSandbox(BaseAsyncSandbox):
|
|
|
178
201
|
try:
|
|
179
202
|
headers = {
|
|
180
203
|
"Content-Type": "application/json",
|
|
204
|
+
"E2b-Sandbox-Id": self.sandbox_id,
|
|
205
|
+
"E2b-Sandbox-Port": str(JUPYTER_PORT),
|
|
181
206
|
}
|
|
182
207
|
if self._envd_access_token:
|
|
183
208
|
headers["X-Access-Token"] = self._envd_access_token
|
|
@@ -217,6 +242,9 @@ class AsyncSandbox(BaseAsyncSandbox):
|
|
|
217
242
|
raise format_execution_timeout_error()
|
|
218
243
|
except httpx.TimeoutException:
|
|
219
244
|
raise format_request_timeout_error()
|
|
245
|
+
except (httpx.ReadError, httpx.RemoteProtocolError) as err:
|
|
246
|
+
await self._handle_connection_error(err)
|
|
247
|
+
raise
|
|
220
248
|
|
|
221
249
|
async def create_code_context(
|
|
222
250
|
self,
|
|
@@ -244,6 +272,8 @@ class AsyncSandbox(BaseAsyncSandbox):
|
|
|
244
272
|
try:
|
|
245
273
|
headers = {
|
|
246
274
|
"Content-Type": "application/json",
|
|
275
|
+
"E2b-Sandbox-Id": self.sandbox_id,
|
|
276
|
+
"E2b-Sandbox-Port": str(JUPYTER_PORT),
|
|
247
277
|
}
|
|
248
278
|
if self.traffic_access_token:
|
|
249
279
|
headers["E2B-Traffic-Access-Token"] = self.traffic_access_token
|
|
@@ -263,6 +293,9 @@ class AsyncSandbox(BaseAsyncSandbox):
|
|
|
263
293
|
return Context.from_json(data)
|
|
264
294
|
except httpx.TimeoutException:
|
|
265
295
|
raise format_request_timeout_error()
|
|
296
|
+
except (httpx.ReadError, httpx.RemoteProtocolError) as err:
|
|
297
|
+
await self._handle_connection_error(err)
|
|
298
|
+
raise
|
|
266
299
|
|
|
267
300
|
async def remove_code_context(
|
|
268
301
|
self,
|
|
@@ -280,6 +313,8 @@ class AsyncSandbox(BaseAsyncSandbox):
|
|
|
280
313
|
try:
|
|
281
314
|
headers = {
|
|
282
315
|
"Content-Type": "application/json",
|
|
316
|
+
"E2b-Sandbox-Id": self.sandbox_id,
|
|
317
|
+
"E2b-Sandbox-Port": str(JUPYTER_PORT),
|
|
283
318
|
}
|
|
284
319
|
if self.traffic_access_token:
|
|
285
320
|
headers["E2B-Traffic-Access-Token"] = self.traffic_access_token
|
|
@@ -295,6 +330,9 @@ class AsyncSandbox(BaseAsyncSandbox):
|
|
|
295
330
|
raise err
|
|
296
331
|
except httpx.TimeoutException:
|
|
297
332
|
raise format_request_timeout_error()
|
|
333
|
+
except (httpx.ReadError, httpx.RemoteProtocolError) as err:
|
|
334
|
+
await self._handle_connection_error(err)
|
|
335
|
+
raise
|
|
298
336
|
|
|
299
337
|
async def list_code_contexts(self) -> List[Context]:
|
|
300
338
|
"""
|
|
@@ -305,6 +343,8 @@ class AsyncSandbox(BaseAsyncSandbox):
|
|
|
305
343
|
try:
|
|
306
344
|
headers = {
|
|
307
345
|
"Content-Type": "application/json",
|
|
346
|
+
"E2b-Sandbox-Id": self.sandbox_id,
|
|
347
|
+
"E2b-Sandbox-Port": str(JUPYTER_PORT),
|
|
308
348
|
}
|
|
309
349
|
if self.traffic_access_token:
|
|
310
350
|
headers["E2B-Traffic-Access-Token"] = self.traffic_access_token
|
|
@@ -323,6 +363,9 @@ class AsyncSandbox(BaseAsyncSandbox):
|
|
|
323
363
|
return [Context.from_json(context_data) for context_data in data]
|
|
324
364
|
except httpx.TimeoutException:
|
|
325
365
|
raise format_request_timeout_error()
|
|
366
|
+
except (httpx.ReadError, httpx.RemoteProtocolError) as err:
|
|
367
|
+
await self._handle_connection_error(err)
|
|
368
|
+
raise
|
|
326
369
|
|
|
327
370
|
async def restart_code_context(
|
|
328
371
|
self,
|
|
@@ -339,6 +382,8 @@ class AsyncSandbox(BaseAsyncSandbox):
|
|
|
339
382
|
try:
|
|
340
383
|
headers = {
|
|
341
384
|
"Content-Type": "application/json",
|
|
385
|
+
"E2b-Sandbox-Id": self.sandbox_id,
|
|
386
|
+
"E2b-Sandbox-Port": str(JUPYTER_PORT),
|
|
342
387
|
}
|
|
343
388
|
if self.traffic_access_token:
|
|
344
389
|
headers["E2B-Traffic-Access-Token"] = self.traffic_access_token
|
|
@@ -354,3 +399,6 @@ class AsyncSandbox(BaseAsyncSandbox):
|
|
|
354
399
|
raise err
|
|
355
400
|
except httpx.TimeoutException:
|
|
356
401
|
raise format_request_timeout_error()
|
|
402
|
+
except (httpx.ReadError, httpx.RemoteProtocolError) as err:
|
|
403
|
+
await self._handle_connection_error(err)
|
|
404
|
+
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,6 +58,11 @@ class Sandbox(BaseSandbox):
|
|
|
57
58
|
|
|
58
59
|
@property
|
|
59
60
|
def _jupyter_url(self) -> str:
|
|
61
|
+
# Honors the `sandbox_url` option and the `E2B_SANDBOX_URL` environment
|
|
62
|
+
# variable, same as the base SDK does for envd requests.
|
|
63
|
+
sandbox_url = self.connection_config._sandbox_url
|
|
64
|
+
if sandbox_url:
|
|
65
|
+
return sandbox_url
|
|
60
66
|
return f"{'http' if self.connection_config.debug else 'https'}://{self.get_host(JUPYTER_PORT)}"
|
|
61
67
|
|
|
62
68
|
@property
|
|
@@ -77,6 +83,23 @@ class Sandbox(BaseSandbox):
|
|
|
77
83
|
# cancelled reliably.
|
|
78
84
|
return Client(transport=get_transport(self.connection_config, http2=False))
|
|
79
85
|
|
|
86
|
+
def _handle_connection_error(self, err: Exception) -> None:
|
|
87
|
+
"""
|
|
88
|
+
Raises a descriptive exception if the connection error was caused by
|
|
89
|
+
the sandbox being killed mid-request. If the sandbox is still running
|
|
90
|
+
(or its state can't be determined), returns so the caller can re-raise
|
|
91
|
+
the original error.
|
|
92
|
+
"""
|
|
93
|
+
try:
|
|
94
|
+
running = self.is_running()
|
|
95
|
+
except Exception:
|
|
96
|
+
# The state check itself failed, so we can't tell whether the
|
|
97
|
+
# sandbox was killed — let the caller re-raise the original error
|
|
98
|
+
# instead of wrongly claiming the sandbox is gone.
|
|
99
|
+
return
|
|
100
|
+
if not running:
|
|
101
|
+
raise format_sandbox_killed_error() from err
|
|
102
|
+
|
|
80
103
|
@overload
|
|
81
104
|
def run_code(
|
|
82
105
|
self,
|
|
@@ -171,7 +194,11 @@ class Sandbox(BaseSandbox):
|
|
|
171
194
|
context_id = context.id if context else None
|
|
172
195
|
|
|
173
196
|
try:
|
|
174
|
-
headers: Dict[str, str] = {
|
|
197
|
+
headers: Dict[str, str] = {
|
|
198
|
+
"Content-Type": "application/json",
|
|
199
|
+
"E2b-Sandbox-Id": self.sandbox_id,
|
|
200
|
+
"E2b-Sandbox-Port": str(JUPYTER_PORT),
|
|
201
|
+
}
|
|
175
202
|
if self._envd_access_token:
|
|
176
203
|
headers["X-Access-Token"] = self._envd_access_token
|
|
177
204
|
if self.traffic_access_token:
|
|
@@ -210,6 +237,9 @@ class Sandbox(BaseSandbox):
|
|
|
210
237
|
raise format_execution_timeout_error()
|
|
211
238
|
except httpx.TimeoutException:
|
|
212
239
|
raise format_request_timeout_error()
|
|
240
|
+
except (httpx.ReadError, httpx.RemoteProtocolError) as err:
|
|
241
|
+
self._handle_connection_error(err)
|
|
242
|
+
raise
|
|
213
243
|
|
|
214
244
|
def create_code_context(
|
|
215
245
|
self,
|
|
@@ -235,9 +265,11 @@ class Sandbox(BaseSandbox):
|
|
|
235
265
|
data["cwd"] = cwd
|
|
236
266
|
|
|
237
267
|
try:
|
|
238
|
-
headers: Dict[str, str] = {
|
|
239
|
-
|
|
240
|
-
|
|
268
|
+
headers: Dict[str, str] = {
|
|
269
|
+
"Content-Type": "application/json",
|
|
270
|
+
"E2b-Sandbox-Id": self.sandbox_id,
|
|
271
|
+
"E2b-Sandbox-Port": str(JUPYTER_PORT),
|
|
272
|
+
}
|
|
241
273
|
if self.traffic_access_token:
|
|
242
274
|
headers["E2B-Traffic-Access-Token"] = self.traffic_access_token
|
|
243
275
|
|
|
@@ -256,6 +288,9 @@ class Sandbox(BaseSandbox):
|
|
|
256
288
|
return Context.from_json(data)
|
|
257
289
|
except httpx.TimeoutException:
|
|
258
290
|
raise format_request_timeout_error()
|
|
291
|
+
except (httpx.ReadError, httpx.RemoteProtocolError) as err:
|
|
292
|
+
self._handle_connection_error(err)
|
|
293
|
+
raise
|
|
259
294
|
|
|
260
295
|
def remove_code_context(
|
|
261
296
|
self,
|
|
@@ -271,9 +306,11 @@ class Sandbox(BaseSandbox):
|
|
|
271
306
|
context_id = context.id if isinstance(context, Context) else context
|
|
272
307
|
|
|
273
308
|
try:
|
|
274
|
-
headers: Dict[str, str] = {
|
|
275
|
-
|
|
276
|
-
|
|
309
|
+
headers: Dict[str, str] = {
|
|
310
|
+
"Content-Type": "application/json",
|
|
311
|
+
"E2b-Sandbox-Id": self.sandbox_id,
|
|
312
|
+
"E2b-Sandbox-Port": str(JUPYTER_PORT),
|
|
313
|
+
}
|
|
277
314
|
if self.traffic_access_token:
|
|
278
315
|
headers["E2B-Traffic-Access-Token"] = self.traffic_access_token
|
|
279
316
|
|
|
@@ -288,6 +325,9 @@ class Sandbox(BaseSandbox):
|
|
|
288
325
|
raise err
|
|
289
326
|
except httpx.TimeoutException:
|
|
290
327
|
raise format_request_timeout_error()
|
|
328
|
+
except (httpx.ReadError, httpx.RemoteProtocolError) as err:
|
|
329
|
+
self._handle_connection_error(err)
|
|
330
|
+
raise
|
|
291
331
|
|
|
292
332
|
def list_code_contexts(self) -> List[Context]:
|
|
293
333
|
"""
|
|
@@ -296,9 +336,11 @@ class Sandbox(BaseSandbox):
|
|
|
296
336
|
:return: List of contexts.
|
|
297
337
|
"""
|
|
298
338
|
try:
|
|
299
|
-
headers: Dict[str, str] = {
|
|
300
|
-
|
|
301
|
-
|
|
339
|
+
headers: Dict[str, str] = {
|
|
340
|
+
"Content-Type": "application/json",
|
|
341
|
+
"E2b-Sandbox-Id": self.sandbox_id,
|
|
342
|
+
"E2b-Sandbox-Port": str(JUPYTER_PORT),
|
|
343
|
+
}
|
|
302
344
|
if self.traffic_access_token:
|
|
303
345
|
headers["E2B-Traffic-Access-Token"] = self.traffic_access_token
|
|
304
346
|
|
|
@@ -316,6 +358,9 @@ class Sandbox(BaseSandbox):
|
|
|
316
358
|
return [Context.from_json(context_data) for context_data in data]
|
|
317
359
|
except httpx.TimeoutException:
|
|
318
360
|
raise format_request_timeout_error()
|
|
361
|
+
except (httpx.ReadError, httpx.RemoteProtocolError) as err:
|
|
362
|
+
self._handle_connection_error(err)
|
|
363
|
+
raise
|
|
319
364
|
|
|
320
365
|
def restart_code_context(
|
|
321
366
|
self,
|
|
@@ -331,9 +376,11 @@ class Sandbox(BaseSandbox):
|
|
|
331
376
|
context_id = context.id if isinstance(context, Context) else context
|
|
332
377
|
|
|
333
378
|
try:
|
|
334
|
-
headers: Dict[str, str] = {
|
|
335
|
-
|
|
336
|
-
|
|
379
|
+
headers: Dict[str, str] = {
|
|
380
|
+
"Content-Type": "application/json",
|
|
381
|
+
"E2b-Sandbox-Id": self.sandbox_id,
|
|
382
|
+
"E2b-Sandbox-Port": str(JUPYTER_PORT),
|
|
383
|
+
}
|
|
337
384
|
if self.traffic_access_token:
|
|
338
385
|
headers["E2B-Traffic-Access-Token"] = self.traffic_access_token
|
|
339
386
|
|
|
@@ -348,3 +395,6 @@ class Sandbox(BaseSandbox):
|
|
|
348
395
|
raise err
|
|
349
396
|
except httpx.TimeoutException:
|
|
350
397
|
raise format_request_timeout_error()
|
|
398
|
+
except (httpx.ReadError, httpx.RemoteProtocolError) as err:
|
|
399
|
+
self._handle_connection_error(err)
|
|
400
|
+
raise
|
{e2b_code_interpreter-2.8.0 → e2b_code_interpreter-2.9.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
|
+
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|