├── js ├── .gitignore ├── .eslintrc.cjs ├── src │ ├── consts.ts │ ├── index.ts │ └── utils.ts ├── tests │ ├── data.test.ts │ ├── reconnect.test.ts │ ├── bash.test.ts │ ├── basic.test.ts │ ├── statefulness.test.ts │ ├── executionCount.test.ts │ ├── runtimes │ │ ├── bun │ │ │ └── run.test.ts │ │ └── deno │ │ │ └── run.test.ts │ ├── displayData.test.ts │ ├── kernels.test.ts │ ├── charts │ │ ├── unknown.test.ts │ │ ├── scales.test.ts │ │ ├── pie.test.ts │ │ ├── bar.test.ts │ │ ├── boxAndWhisker.test.ts │ │ ├── log.test.ts │ │ ├── superchart.test.ts │ │ ├── scatter.test.ts │ │ └── line.test.ts │ ├── streaming.test.ts │ ├── defaultKernels.test.ts │ ├── callbacks.test.ts │ ├── images │ │ └── bar.test.ts │ ├── env_vars │ │ ├── bash.test.ts │ │ ├── r.test.ts │ │ ├── js.test.ts │ │ ├── java.test.ts │ │ └── python.test.ts │ └── setup.ts ├── tsup.config.js ├── tsconfig.json ├── vitest.config.mts ├── typedoc.json ├── example.mts ├── LICENSE ├── scripts │ ├── generate_sdk_ref.sh │ └── CustomMarkdownTheme.js ├── README.md └── package.json ├── template ├── server │ ├── api │ │ └── models │ │ │ ├── __init__.py │ │ │ ├── env_vars.py │ │ │ ├── context.py │ │ │ ├── create_context.py │ │ │ ├── logs.py │ │ │ ├── error.py │ │ │ ├── execution_request.py │ │ │ └── output.py │ ├── consts.py │ ├── errors.py │ ├── requirements.txt │ ├── utils │ │ └── locks.py │ ├── envs.py │ ├── stream.py │ └── contexts.py ├── matplotlibrc ├── requirements-dev.txt ├── build_docker.py ├── package.json ├── deno.json ├── build_ci.py ├── build_prod.py ├── build_test.py ├── startup_scripts │ └── 0003_images.py ├── start-up.sh ├── requirements.txt ├── README.md └── jupyter_server_config.py ├── chart_data_extractor ├── e2b_charts │ ├── utils │ │ ├── __init__.py │ │ ├── filtering.py │ │ └── rounding.py │ ├── __init__.py │ └── charts │ │ ├── __init__.py │ │ ├── pie.py │ │ └── base.py ├── README.md ├── tests │ ├── charts │ │ ├── test_blank.py │ │ ├── test_categorical_scale.py │ │ ├── test_datetime_scale.py │ │ ├── test_unknown.py │ │ ├── test_bar.py │ │ ├── test_pie.py │ │ ├── test_scatter.py │ │ ├── test_log_graph.py │ │ ├── test_box_and_whiskers.py │ │ ├── test_supergraph.py │ │ └── test_line.py │ └── utils │ │ ├── test_is_grid_line.py │ │ └── test_detect_scale.py ├── package.json ├── pyproject.toml └── LICENSE ├── .prettierrc ├── pnpm-workspace.yaml ├── readme-assets ├── logo-circle.png ├── e2b-code-interpreter-dark.png └── e2b-code-interpreter-light.png ├── python ├── e2b_code_interpreter │ ├── constants.py │ ├── __init__.py │ └── exceptions.py ├── pytest.ini ├── tests │ ├── sync │ │ ├── test_bash.py │ │ ├── test_statefulness.py │ │ ├── test_reconnect.py │ │ ├── test_execution_count.py │ │ ├── test_custom_repr_object.py │ │ ├── test_data.py │ │ ├── test_basic.py │ │ ├── test_display_data.py │ │ ├── test_kernels.py │ │ ├── test_streaming.py │ │ ├── test_callbacks.py │ │ ├── env_vars │ │ │ ├── test_bash.py │ │ │ ├── test_js.py │ │ │ ├── test_java.py │ │ │ ├── test_python.py │ │ │ └── test_r.py │ │ └── test_default_kernels.py │ ├── async │ │ ├── test_async_bash.py │ │ ├── test_async_statefulness.py │ │ ├── test_async_reconnect.py │ │ ├── test_async_execution_count.py │ │ ├── test_async_custom_repr_object.py │ │ ├── test_async_data.py │ │ ├── test_async_basic.py │ │ ├── test_async_display_data.py │ │ ├── test_async_kernels.py │ │ ├── test_async_streaming.py │ │ ├── test_async_default_kernels.py │ │ ├── env_vars │ │ │ ├── test_bash.py │ │ │ ├── test_js.py │ │ │ ├── test_java.py │ │ │ ├── test_python.py │ │ │ └── test_r.py │ │ └── test_async_callbacks.py │ ├── charts │ │ ├── test_json.py │ │ ├── test_unknown.py │ │ ├── test_bar.py │ │ ├── test_scale.py │ │ ├── test_pie.py │ │ ├── test_scatter.py │ │ ├── test_log_chart.py │ │ ├── test_box_and_whiskers.py │ │ ├── test_superchart.py │ │ └── test_line.py │ ├── images │ │ └── test_images.py │ └── conftest.py ├── package.json ├── example.py ├── pyproject.toml ├── LICENSE ├── scripts │ └── generate_sdk_ref.sh ├── async_example.py └── README.md ├── .prettierignore ├── CODEOWNERS ├── .npmrc ├── .changeset ├── README.md └── config.json ├── Makefile ├── sdk-reference └── code-interpreter-js-sdk │ ├── v1.0.4 │ ├── consts │ │ └── page.mdx │ └── index │ │ └── page.mdx │ ├── v1.1.0 │ ├── consts │ │ └── page.mdx │ └── index │ │ └── page.mdx │ ├── v1.1.1 │ ├── consts │ │ └── page.mdx │ └── index │ │ └── page.mdx │ ├── v1.2.0 │ ├── consts │ │ └── page.mdx │ └── index │ │ └── page.mdx │ ├── v1.5.0 │ ├── consts │ │ └── page.mdx │ └── index │ │ └── page.mdx │ ├── v1.5.1 │ ├── consts │ │ └── page.mdx │ └── index │ │ └── page.mdx │ ├── v2.0.0 │ ├── consts │ │ └── page.mdx │ └── index │ │ └── page.mdx │ ├── v2.0.1 │ ├── consts │ │ └── page.mdx │ └── index │ │ └── page.mdx │ ├── v2.1.0 │ ├── consts │ │ └── page.mdx │ └── index │ │ └── page.mdx │ ├── v2.2.0 │ ├── consts │ │ └── page.mdx │ └── index │ │ └── page.mdx │ ├── v2.3.0 │ ├── consts │ │ └── page.mdx │ └── index │ │ └── page.mdx │ ├── v2.3.1 │ ├── consts │ │ └── page.mdx │ └── index │ │ └── page.mdx │ ├── v2.3.2 │ ├── consts │ │ └── page.mdx │ └── index │ │ └── page.mdx │ └── v2.3.3 │ ├── consts │ └── page.mdx │ └── index │ └── page.mdx ├── .github ├── scripts │ ├── is_release.sh │ ├── is_new_sdk_ref.sh │ └── is_release_for_package.sh └── workflows │ ├── cleanup_build_template.yml │ ├── charts_tests.yml │ ├── python_tests.yml │ ├── lint.yml │ ├── performance_tests.yml │ ├── build_test_template.yml │ ├── pull_request.yml │ └── js_tests.yml ├── .eslintrc.cjs └── package.json /js/.gitignore: -------------------------------------------------------------------------------- 1 | deno.lock 2 | -------------------------------------------------------------------------------- /template/server/api/models/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /template/matplotlibrc: -------------------------------------------------------------------------------- 1 | font.family: sans-serif, Noto Sans CJK JP 2 | -------------------------------------------------------------------------------- /template/requirements-dev.txt: -------------------------------------------------------------------------------- 1 | e2b==2.6.4 2 | python-dotenv==1.2.1 -------------------------------------------------------------------------------- /template/server/consts.py: -------------------------------------------------------------------------------- 1 | JUPYTER_BASE_URL = "http://localhost:8888" 2 | -------------------------------------------------------------------------------- /template/server/errors.py: -------------------------------------------------------------------------------- 1 | class ExecutionError(Exception): 2 | pass 3 | -------------------------------------------------------------------------------- /chart_data_extractor/e2b_charts/utils/__init__.py: -------------------------------------------------------------------------------- 1 | from .filtering import is_grid_line 2 | -------------------------------------------------------------------------------- /js/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: '../.eslintrc.cjs', 4 | } 5 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "semi": false, 4 | "trailingComma": "es5" 5 | } 6 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - js 3 | - python 4 | - chart_data_extractor 5 | - template 6 | -------------------------------------------------------------------------------- /chart_data_extractor/e2b_charts/__init__.py: -------------------------------------------------------------------------------- 1 | from .main import chart_figure_to_chart, chart_figure_to_dict 2 | -------------------------------------------------------------------------------- /js/src/consts.ts: -------------------------------------------------------------------------------- 1 | export const DEFAULT_TIMEOUT_MS = 60_000 // 1 minute 2 | export const JUPYTER_PORT = 49999 3 | -------------------------------------------------------------------------------- /readme-assets/logo-circle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e2b-dev/code-interpreter/HEAD/readme-assets/logo-circle.png -------------------------------------------------------------------------------- /python/e2b_code_interpreter/constants.py: -------------------------------------------------------------------------------- 1 | DEFAULT_TEMPLATE = "code-interpreter-v1" 2 | JUPYTER_PORT = 49999 3 | DEFAULT_TIMEOUT = 300 4 | -------------------------------------------------------------------------------- /template/server/api/models/env_vars.py: -------------------------------------------------------------------------------- 1 | from typing import Dict 2 | from pydantic import StrictStr 3 | 4 | EnvVars = Dict[StrictStr, str] 5 | -------------------------------------------------------------------------------- /readme-assets/e2b-code-interpreter-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e2b-dev/code-interpreter/HEAD/readme-assets/e2b-code-interpreter-dark.png -------------------------------------------------------------------------------- /readme-assets/e2b-code-interpreter-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e2b-dev/code-interpreter/HEAD/readme-assets/e2b-code-interpreter-light.png -------------------------------------------------------------------------------- /template/server/requirements.txt: -------------------------------------------------------------------------------- 1 | fastapi==0.111.0 2 | httpx==0.27.0 3 | websockets==12.0 4 | uvicorn[standard]==0.30.1 5 | requests==2.32.4 6 | pydantic==2.9.1 7 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | /.next/ 2 | 3 | # imporatant to keep // $HighlightLine comments at the end of the line 4 | apps/web/src/code/ 5 | 6 | 7 | **/*.mdx 8 | **/code/**/* 9 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | # These owners will be the default owners for everything in 2 | # the repo. Unless a later match takes precedence. 3 | * @jakubno @ValentaTomas @mishushakov 4 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | enable-pre-post-scripts=true 2 | auto-install-peers=true 3 | exclude-links-from-lockfile=true 4 | prefer-workspace-packages=false 5 | link-workspace-packages=false 6 | engine-strict=true 7 | -------------------------------------------------------------------------------- /chart_data_extractor/README.md: -------------------------------------------------------------------------------- 1 | # Extracting Data for Code Interpreter SDK 2 | 3 | This package is a utility used to extract data in the Code Interpreter SDK from, e.g., DataFrames and matplotlib plots. 4 | -------------------------------------------------------------------------------- /.changeset/README.md: -------------------------------------------------------------------------------- 1 | # Changesets 2 | 3 | To add changeset run: 4 | 5 | ```bash 6 | npx changeset 7 | ``` 8 | 9 | in the root of the project. This will create a new changeset in the `.changeset` folder. -------------------------------------------------------------------------------- /python/pytest.ini: -------------------------------------------------------------------------------- 1 | # content of pytest.ini 2 | [pytest] 3 | markers = 4 | skip_debug: skip test if E2B_DEBUG is set. 5 | asyncio_mode=auto 6 | 7 | addopts = "--import-mode=importlib" "--numprocesses=2" 8 | -------------------------------------------------------------------------------- /template/build_docker.py: -------------------------------------------------------------------------------- 1 | from template import make_template 2 | from e2b import Template 3 | 4 | tmp = make_template(kernels=["python", "javascript"], is_docker=True) 5 | print(Template.to_dockerfile(tmp)) 6 | -------------------------------------------------------------------------------- /chart_data_extractor/e2b_charts/charts/__init__.py: -------------------------------------------------------------------------------- 1 | from .base import ChartType, Chart 2 | from .bars import BarChart, BoxAndWhiskerChart 3 | from .pie import PieChart 4 | from .planar import ScatterChart, LineChart 5 | -------------------------------------------------------------------------------- /template/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@e2b/code-interpreter-template", 3 | "private": true, 4 | "version": "0.2.1", 5 | "scripts": { 6 | "lint": "ruff check .", 7 | "format": "ruff format ." 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /python/tests/sync/test_bash.py: -------------------------------------------------------------------------------- 1 | from e2b_code_interpreter.code_interpreter_sync import Sandbox 2 | 3 | 4 | def test_bash(sandbox: Sandbox): 5 | result = sandbox.run_code("!pwd") 6 | assert "".join(result.logs.stdout).strip() == "/home/user" 7 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | start-template-server: 2 | docker run --rm -e E2B_LOCAL=true -p 49999:49999 -it $$(python template/build_docker.py | docker build -q ./template -f -) 3 | 4 | kill-template-server: 5 | docker kill $(shell docker ps --filter expose=49999 --format {{.ID}}) 6 | -------------------------------------------------------------------------------- /sdk-reference/code-interpreter-js-sdk/v1.0.4/consts/page.mdx: -------------------------------------------------------------------------------- 1 | ### DEFAULT\_TIMEOUT\_MS 2 | 3 | ```ts 4 | const DEFAULT_TIMEOUT_MS: 60000 = 60_000; 5 | ``` 6 | 7 | *** 8 | 9 | ### JUPYTER\_PORT 10 | 11 | ```ts 12 | const JUPYTER_PORT: 49999 = 49999; 13 | ``` 14 | -------------------------------------------------------------------------------- /sdk-reference/code-interpreter-js-sdk/v1.1.0/consts/page.mdx: -------------------------------------------------------------------------------- 1 | ### DEFAULT\_TIMEOUT\_MS 2 | 3 | ```ts 4 | const DEFAULT_TIMEOUT_MS: 60000 = 60_000; 5 | ``` 6 | 7 | *** 8 | 9 | ### JUPYTER\_PORT 10 | 11 | ```ts 12 | const JUPYTER_PORT: 49999 = 49999; 13 | ``` 14 | -------------------------------------------------------------------------------- /sdk-reference/code-interpreter-js-sdk/v1.1.1/consts/page.mdx: -------------------------------------------------------------------------------- 1 | ### DEFAULT\_TIMEOUT\_MS 2 | 3 | ```ts 4 | const DEFAULT_TIMEOUT_MS: 60000 = 60_000; 5 | ``` 6 | 7 | *** 8 | 9 | ### JUPYTER\_PORT 10 | 11 | ```ts 12 | const JUPYTER_PORT: 49999 = 49999; 13 | ``` 14 | -------------------------------------------------------------------------------- /sdk-reference/code-interpreter-js-sdk/v1.2.0/consts/page.mdx: -------------------------------------------------------------------------------- 1 | ### DEFAULT\_TIMEOUT\_MS 2 | 3 | ```ts 4 | const DEFAULT_TIMEOUT_MS: 60000 = 60_000; 5 | ``` 6 | 7 | *** 8 | 9 | ### JUPYTER\_PORT 10 | 11 | ```ts 12 | const JUPYTER_PORT: 49999 = 49999; 13 | ``` 14 | -------------------------------------------------------------------------------- /sdk-reference/code-interpreter-js-sdk/v1.5.0/consts/page.mdx: -------------------------------------------------------------------------------- 1 | ### DEFAULT\_TIMEOUT\_MS 2 | 3 | ```ts 4 | const DEFAULT_TIMEOUT_MS: 60000 = 60_000; 5 | ``` 6 | 7 | *** 8 | 9 | ### JUPYTER\_PORT 10 | 11 | ```ts 12 | const JUPYTER_PORT: 49999 = 49999; 13 | ``` 14 | -------------------------------------------------------------------------------- /sdk-reference/code-interpreter-js-sdk/v1.5.1/consts/page.mdx: -------------------------------------------------------------------------------- 1 | ### DEFAULT\_TIMEOUT\_MS 2 | 3 | ```ts 4 | const DEFAULT_TIMEOUT_MS: 60000 = 60_000; 5 | ``` 6 | 7 | *** 8 | 9 | ### JUPYTER\_PORT 10 | 11 | ```ts 12 | const JUPYTER_PORT: 49999 = 49999; 13 | ``` 14 | -------------------------------------------------------------------------------- /sdk-reference/code-interpreter-js-sdk/v2.0.0/consts/page.mdx: -------------------------------------------------------------------------------- 1 | ### DEFAULT\_TIMEOUT\_MS 2 | 3 | ```ts 4 | const DEFAULT_TIMEOUT_MS: 60000 = 60_000; 5 | ``` 6 | 7 | *** 8 | 9 | ### JUPYTER\_PORT 10 | 11 | ```ts 12 | const JUPYTER_PORT: 49999 = 49999; 13 | ``` 14 | -------------------------------------------------------------------------------- /sdk-reference/code-interpreter-js-sdk/v2.0.1/consts/page.mdx: -------------------------------------------------------------------------------- 1 | ### DEFAULT\_TIMEOUT\_MS 2 | 3 | ```ts 4 | const DEFAULT_TIMEOUT_MS: 60000 = 60_000; 5 | ``` 6 | 7 | *** 8 | 9 | ### JUPYTER\_PORT 10 | 11 | ```ts 12 | const JUPYTER_PORT: 49999 = 49999; 13 | ``` 14 | -------------------------------------------------------------------------------- /sdk-reference/code-interpreter-js-sdk/v2.1.0/consts/page.mdx: -------------------------------------------------------------------------------- 1 | ### DEFAULT\_TIMEOUT\_MS 2 | 3 | ```ts 4 | const DEFAULT_TIMEOUT_MS: 60000 = 60_000; 5 | ``` 6 | 7 | *** 8 | 9 | ### JUPYTER\_PORT 10 | 11 | ```ts 12 | const JUPYTER_PORT: 49999 = 49999; 13 | ``` 14 | -------------------------------------------------------------------------------- /sdk-reference/code-interpreter-js-sdk/v2.2.0/consts/page.mdx: -------------------------------------------------------------------------------- 1 | ### DEFAULT\_TIMEOUT\_MS 2 | 3 | ```ts 4 | const DEFAULT_TIMEOUT_MS: 60000 = 60_000; 5 | ``` 6 | 7 | *** 8 | 9 | ### JUPYTER\_PORT 10 | 11 | ```ts 12 | const JUPYTER_PORT: 49999 = 49999; 13 | ``` 14 | -------------------------------------------------------------------------------- /sdk-reference/code-interpreter-js-sdk/v2.3.0/consts/page.mdx: -------------------------------------------------------------------------------- 1 | ### DEFAULT\_TIMEOUT\_MS 2 | 3 | ```ts 4 | const DEFAULT_TIMEOUT_MS: 60000 = 60_000; 5 | ``` 6 | 7 | *** 8 | 9 | ### JUPYTER\_PORT 10 | 11 | ```ts 12 | const JUPYTER_PORT: 49999 = 49999; 13 | ``` 14 | -------------------------------------------------------------------------------- /sdk-reference/code-interpreter-js-sdk/v2.3.1/consts/page.mdx: -------------------------------------------------------------------------------- 1 | ### DEFAULT\_TIMEOUT\_MS 2 | 3 | ```ts 4 | const DEFAULT_TIMEOUT_MS: 60000 = 60_000; 5 | ``` 6 | 7 | *** 8 | 9 | ### JUPYTER\_PORT 10 | 11 | ```ts 12 | const JUPYTER_PORT: 49999 = 49999; 13 | ``` 14 | -------------------------------------------------------------------------------- /sdk-reference/code-interpreter-js-sdk/v2.3.2/consts/page.mdx: -------------------------------------------------------------------------------- 1 | ### DEFAULT\_TIMEOUT\_MS 2 | 3 | ```ts 4 | const DEFAULT_TIMEOUT_MS: 60000 = 60_000; 5 | ``` 6 | 7 | *** 8 | 9 | ### JUPYTER\_PORT 10 | 11 | ```ts 12 | const JUPYTER_PORT: 49999 = 49999; 13 | ``` 14 | -------------------------------------------------------------------------------- /sdk-reference/code-interpreter-js-sdk/v2.3.3/consts/page.mdx: -------------------------------------------------------------------------------- 1 | ### DEFAULT\_TIMEOUT\_MS 2 | 3 | ```ts 4 | const DEFAULT_TIMEOUT_MS: 60000 = 60_000; 5 | ``` 6 | 7 | *** 8 | 9 | ### JUPYTER\_PORT 10 | 11 | ```ts 12 | const JUPYTER_PORT: 49999 = 49999; 13 | ``` 14 | -------------------------------------------------------------------------------- /template/deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "argv": [ 3 | "/usr/bin/deno", 4 | "jupyter", 5 | "--kernel", 6 | "--conn", 7 | "{connection_file}" 8 | ], 9 | "display_name": "Deno", 10 | "env": { 11 | "NO_COLOR": "1" 12 | }, 13 | "language": "typescript" 14 | } 15 | -------------------------------------------------------------------------------- /.github/scripts/is_release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # This script checks if the current commit contains changesets. 4 | 5 | set -eu 6 | 7 | CHANGES=$(node -e "require('@changesets/read').default(process.cwd()).then(result => console.log(!!result.length))") 8 | 9 | echo "${CHANGES}" 10 | -------------------------------------------------------------------------------- /chart_data_extractor/tests/charts/test_blank.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | 3 | from e2b_charts import chart_figure_to_chart 4 | 5 | 6 | def test_blank_chart(): 7 | figure, _ = plt.subplots() 8 | chart = chart_figure_to_chart(figure) 9 | assert chart is None 10 | -------------------------------------------------------------------------------- /python/tests/async/test_async_bash.py: -------------------------------------------------------------------------------- 1 | from e2b_code_interpreter.code_interpreter_async import AsyncSandbox 2 | 3 | 4 | async def test_bash(async_sandbox: AsyncSandbox): 5 | result = await async_sandbox.run_code("!pwd") 6 | assert "".join(result.logs.stdout).strip() == "/home/user" 7 | -------------------------------------------------------------------------------- /python/tests/sync/test_statefulness.py: -------------------------------------------------------------------------------- 1 | from e2b_code_interpreter.code_interpreter_sync import Sandbox 2 | 3 | 4 | def test_stateful(sandbox: Sandbox): 5 | sandbox.run_code("test_stateful = 1") 6 | 7 | result = sandbox.run_code("test_stateful+=1; test_stateful") 8 | assert result.text == "2" 9 | -------------------------------------------------------------------------------- /template/build_ci.py: -------------------------------------------------------------------------------- 1 | import os 2 | from e2b import Template, default_build_logger 3 | from template import make_template 4 | 5 | Template.build( 6 | make_template(), 7 | alias=os.environ["E2B_TESTS_TEMPLATE"], 8 | cpu_count=2, 9 | memory_mb=2048, 10 | on_build_logs=default_build_logger(), 11 | ) 12 | -------------------------------------------------------------------------------- /python/tests/sync/test_reconnect.py: -------------------------------------------------------------------------------- 1 | from e2b_code_interpreter.code_interpreter_sync import Sandbox 2 | 3 | 4 | def test_reconnect(sandbox: Sandbox): 5 | sandbox_id = sandbox.sandbox_id 6 | 7 | sandbox2 = Sandbox.connect(sandbox_id) 8 | result = sandbox2.run_code("x =1; x") 9 | assert result.text == "1" 10 | -------------------------------------------------------------------------------- /python/e2b_code_interpreter/__init__.py: -------------------------------------------------------------------------------- 1 | from e2b import * 2 | from .code_interpreter_sync import Sandbox 3 | from .code_interpreter_async import AsyncSandbox 4 | from .models import ( 5 | Context, 6 | Execution, 7 | ExecutionError, 8 | Result, 9 | MIMEType, 10 | Logs, 11 | OutputHandler, 12 | OutputMessage, 13 | ) 14 | -------------------------------------------------------------------------------- /python/tests/sync/test_execution_count.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from e2b_code_interpreter.code_interpreter_sync import Sandbox 4 | 5 | 6 | @pytest.mark.skip_debug() 7 | def test_execution_count(sandbox: Sandbox): 8 | sandbox.run_code("echo 'E2B is awesome!'") 9 | result = sandbox.run_code("!pwd") 10 | assert result.execution_count == 2 11 | -------------------------------------------------------------------------------- /template/build_prod.py: -------------------------------------------------------------------------------- 1 | from dotenv import load_dotenv 2 | from e2b import Template, default_build_logger 3 | from template import make_template 4 | 5 | load_dotenv() 6 | 7 | Template.build( 8 | make_template(), 9 | alias="code-interpreter-v1", 10 | cpu_count=2, 11 | memory_mb=2048, 12 | on_build_logs=default_build_logger(), 13 | ) 14 | -------------------------------------------------------------------------------- /.github/scripts/is_new_sdk_ref.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euo pipefail 4 | 5 | # This script checks for diffs in the js/ and python/ directory. 6 | # If there are diffs, it means we need to generate new SDK references. 7 | if git diff --name-only HEAD^ | grep -q '^js/\|^python/'; then 8 | echo "true" 9 | else 10 | echo "false" 11 | fi 12 | -------------------------------------------------------------------------------- /python/tests/async/test_async_statefulness.py: -------------------------------------------------------------------------------- 1 | from e2b_code_interpreter.code_interpreter_async import AsyncSandbox 2 | 3 | 4 | async def test_stateful(async_sandbox: AsyncSandbox): 5 | await async_sandbox.run_code("async_test_stateful = 1") 6 | 7 | result = await async_sandbox.run_code("async_test_stateful+=1; async_test_stateful") 8 | assert result.text == "2" 9 | -------------------------------------------------------------------------------- /js/tests/data.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'vitest' 2 | 3 | import { sandboxTest } from './setup' 4 | 5 | sandboxTest('get data', async ({ sandbox }) => { 6 | const execution = await sandbox.runCode(` 7 | import pandas as pd 8 | pd.DataFrame({"a": [1, 2, 3]}) 9 | `) 10 | 11 | const result = execution.results[0] 12 | expect(result.data).toBeDefined() 13 | }) 14 | -------------------------------------------------------------------------------- /js/tests/reconnect.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'vitest' 2 | 3 | import { Sandbox } from '../src' 4 | import { sandboxTest } from './setup' 5 | 6 | sandboxTest('reconnect', async ({ sandbox }) => { 7 | sandbox = await Sandbox.connect(sandbox.sandboxId) 8 | 9 | const result = await sandbox.runCode('x =1; x') 10 | 11 | expect(result.text).toEqual('1') 12 | }) 13 | -------------------------------------------------------------------------------- /python/tests/async/test_async_reconnect.py: -------------------------------------------------------------------------------- 1 | from e2b_code_interpreter.code_interpreter_async import AsyncSandbox 2 | 3 | 4 | async def test_reconnect(async_sandbox: AsyncSandbox): 5 | sandbox_id = async_sandbox.sandbox_id 6 | 7 | sandbox2 = await AsyncSandbox.connect(sandbox_id) 8 | result = await sandbox2.run_code("x =1; x") 9 | assert result.text == "1" 10 | -------------------------------------------------------------------------------- /python/tests/sync/test_custom_repr_object.py: -------------------------------------------------------------------------------- 1 | from e2b_code_interpreter.code_interpreter_sync import Sandbox 2 | 3 | code = """ 4 | from IPython.display import display 5 | 6 | display({'text/latex': r'\text{CustomReprObject}'}, raw=True) 7 | """ 8 | 9 | 10 | def test_bash(sandbox: Sandbox): 11 | execution = sandbox.run_code(code) 12 | assert execution.results[0].formats() == ["latex"] 13 | -------------------------------------------------------------------------------- /template/build_test.py: -------------------------------------------------------------------------------- 1 | from dotenv import load_dotenv 2 | from e2b import Template, default_build_logger 3 | from template import make_template 4 | 5 | load_dotenv() 6 | 7 | Template.build( 8 | make_template(kernels=["python", "javascript"]), 9 | alias="code-interpreter-dev", 10 | cpu_count=2, 11 | memory_mb=2048, 12 | on_build_logs=default_build_logger(min_level="debug"), 13 | ) 14 | -------------------------------------------------------------------------------- /js/tsup.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'tsup' 2 | 3 | export default defineConfig({ 4 | minify: false, 5 | target: ['es2017'], 6 | sourcemap: true, 7 | dts: true, 8 | format: ['esm', 'cjs'], 9 | clean: true, 10 | entry: { 11 | index: './src/index.ts', 12 | }, 13 | esbuildOptions: (options) => { 14 | options.legalComments = 'none' 15 | return options 16 | }, 17 | }) 18 | -------------------------------------------------------------------------------- /python/tests/async/test_async_execution_count.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from e2b_code_interpreter.code_interpreter_async import AsyncSandbox 4 | 5 | 6 | @pytest.mark.skip_debug() 7 | async def test_execution_count(async_sandbox: AsyncSandbox): 8 | await async_sandbox.run_code("echo 'E2B is awesome!'") 9 | result = await async_sandbox.run_code("!pwd") 10 | assert result.execution_count == 2 11 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@2.3.1/schema.json", 3 | "changelog": "@changesets/cli/changelog", 4 | "commit": false, 5 | "fixed": [], 6 | "ignore": [], 7 | "linked": [], 8 | "access": "public", 9 | "baseBranch": "main", 10 | "updateInternalDependencies": "patch", 11 | "privatePackages": { 12 | "version": true, 13 | "tag": true 14 | } 15 | } -------------------------------------------------------------------------------- /template/server/api/models/context.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, StrictStr 2 | from pydantic import Field 3 | 4 | 5 | class Context(BaseModel): 6 | id: StrictStr = Field(description="Context ID") 7 | language: StrictStr = Field(description="Language of the context") 8 | cwd: StrictStr = Field(description="Current working directory of the context") 9 | 10 | def __hash__(self): 11 | return hash(self.id) 12 | -------------------------------------------------------------------------------- /chart_data_extractor/e2b_charts/utils/filtering.py: -------------------------------------------------------------------------------- 1 | from matplotlib.lines import Line2D 2 | 3 | 4 | def is_grid_line(line: Line2D) -> bool: 5 | x_data = line.get_xdata() 6 | if len(x_data) != 2: 7 | return False 8 | 9 | y_data = line.get_ydata() 10 | if len(y_data) != 2: 11 | return False 12 | 13 | if x_data[0] == x_data[1] or y_data[0] == y_data[1]: 14 | return True 15 | 16 | return False 17 | -------------------------------------------------------------------------------- /python/tests/async/test_async_custom_repr_object.py: -------------------------------------------------------------------------------- 1 | from e2b_code_interpreter.code_interpreter_async import AsyncSandbox 2 | 3 | code = """ 4 | from IPython.display import display 5 | 6 | display({'text/latex': r'\text{CustomReprObject}'}, raw=True) 7 | """ 8 | 9 | 10 | async def test_bash(async_sandbox: AsyncSandbox): 11 | execution = await async_sandbox.run_code(code) 12 | assert execution.results[0].formats() == ["latex"] 13 | -------------------------------------------------------------------------------- /js/tests/bash.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'vitest' 2 | 3 | import { isDebug, sandboxTest } from './setup' 4 | 5 | // Skip this test if we are running in debug mode — the pwd and user in the testing docker container are not the same as in the actual sandbox. 6 | sandboxTest.skipIf(isDebug)('bash', async ({ sandbox }) => { 7 | const result = await sandbox.runCode('!pwd') 8 | 9 | expect(result.logs.stdout.join().trim()).toEqual('/home/user') 10 | }) 11 | -------------------------------------------------------------------------------- /template/server/api/models/create_context.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, StrictStr 2 | from pydantic import Field 3 | from typing import Optional 4 | 5 | 6 | class CreateContext(BaseModel): 7 | cwd: Optional[StrictStr] = Field( 8 | default="/home/user", 9 | description="Current working directory", 10 | ) 11 | language: Optional[StrictStr] = Field( 12 | default="python", description="Language of the context" 13 | ) 14 | -------------------------------------------------------------------------------- /js/tests/basic.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'vitest' 2 | import { isDebug, sandboxTest, secureSandboxTest } from './setup' 3 | 4 | sandboxTest('basic', async ({ sandbox }) => { 5 | const result = await sandbox.runCode('x =1; x') 6 | 7 | expect(result.text).toEqual('1') 8 | }) 9 | 10 | secureSandboxTest.skipIf(isDebug)('secure access', async ({ sandbox }) => { 11 | const result = await sandbox.runCode('x =1; x') 12 | 13 | expect(result.text).toEqual('1') 14 | }) 15 | -------------------------------------------------------------------------------- /js/tests/statefulness.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'vitest' 2 | 3 | import { isDebug, sandboxTest } from './setup' 4 | 5 | // Skip this test if we are running in debug mode — the execution is persisted between all tests so the result is not reset. 6 | sandboxTest.skipIf(isDebug)('statefulness', async ({ sandbox }) => { 7 | await sandbox.runCode('x = 1') 8 | 9 | const result = await sandbox.runCode('x += 1; x') 10 | 11 | expect(result.text).toEqual('2') 12 | }) 13 | -------------------------------------------------------------------------------- /js/tests/executionCount.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'vitest' 2 | 3 | import { isDebug, sandboxTest } from './setup' 4 | 5 | // Skip this test if we are running in debug mode — we don't create new sandbox for each test so the execution number is not reset. 6 | sandboxTest.skipIf(isDebug)('execution count', async ({ sandbox }) => { 7 | await sandbox.runCode('!pwd') 8 | const result = await sandbox.runCode('!pwd') 9 | 10 | expect(result.executionCount).toEqual(2) 11 | }) 12 | -------------------------------------------------------------------------------- /python/e2b_code_interpreter/exceptions.py: -------------------------------------------------------------------------------- 1 | from e2b import TimeoutException 2 | 3 | 4 | def format_request_timeout_error() -> Exception: 5 | return TimeoutException( 6 | "Request timed out — the 'request_timeout' option can be used to increase this timeout", 7 | ) 8 | 9 | 10 | def format_execution_timeout_error() -> Exception: 11 | return TimeoutException( 12 | "Execution timed out — the 'timeout' option can be used to increase this timeout", 13 | ) 14 | -------------------------------------------------------------------------------- /python/tests/sync/test_data.py: -------------------------------------------------------------------------------- 1 | from e2b_code_interpreter.code_interpreter_sync import Sandbox 2 | 3 | 4 | def test_data(sandbox: Sandbox): 5 | # plot random chart 6 | result = sandbox.run_code( 7 | """ 8 | import pandas as pd 9 | pd.DataFrame({"a": [1, 2, 3]}) 10 | """ 11 | ) 12 | 13 | # there's your image 14 | data = result.results[0] 15 | assert data.data 16 | assert "a" in data.data 17 | assert len(data.data["a"]) == 3 18 | -------------------------------------------------------------------------------- /js/tests/runtimes/bun/run.test.ts: -------------------------------------------------------------------------------- 1 | import { expect, test } from 'bun:test' 2 | 3 | import { Sandbox } from '../../../src' 4 | 5 | test( 6 | 'Bun test', 7 | async () => { 8 | const sbx = await Sandbox.create({ timeoutMs: 5_000 }) 9 | 10 | try { 11 | const result = await sbx.runCode('print("Hello, World!")') 12 | expect(result.logs.stdout.join('')).toEqual('Hello, World!\n') 13 | } finally { 14 | await sbx.kill() 15 | } 16 | }, 17 | { timeout: 30_000 } 18 | ) 19 | -------------------------------------------------------------------------------- /python/tests/async/test_async_data.py: -------------------------------------------------------------------------------- 1 | from e2b_code_interpreter.code_interpreter_async import AsyncSandbox 2 | 3 | 4 | async def test_data(async_sandbox: AsyncSandbox): 5 | # plot random chart 6 | result = await async_sandbox.run_code( 7 | """ 8 | import pandas as pd 9 | pd.DataFrame({"a": [1, 2, 3]}) 10 | """ 11 | ) 12 | 13 | # there's your image 14 | data = result.results[0] 15 | assert data.data 16 | assert "a" in data.data 17 | assert len(data.data["a"]) == 3 18 | -------------------------------------------------------------------------------- /template/server/utils/locks.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | 3 | 4 | class LockedMap(dict): 5 | def __init__(self): 6 | super().__init__() 7 | self._map_lock = asyncio.Lock() 8 | self._locks = {} 9 | 10 | async def get_lock(self, key): 11 | await self._map_lock.acquire() 12 | if key not in self._locks: 13 | self._locks[key] = asyncio.Lock() 14 | 15 | lock = self._locks[key] 16 | print(f"Lock acquired for {key}") 17 | self._map_lock.release() 18 | return lock 19 | -------------------------------------------------------------------------------- /chart_data_extractor/e2b_charts/utils/rounding.py: -------------------------------------------------------------------------------- 1 | from decimal import Decimal, localcontext 2 | 3 | 4 | def dynamic_round(number): 5 | # Convert to Decimal for precise control 6 | decimal_number = Decimal(str(number)) 7 | 8 | # Dynamically determine precision based on magnitude 9 | precision = max(1, 8 - decimal_number.adjusted()) # 8 digits of precision 10 | 11 | with localcontext() as ctx: 12 | ctx.prec = precision # Set the dynamic precision 13 | return +decimal_number # The + operator applies rounding 14 | -------------------------------------------------------------------------------- /template/server/api/models/logs.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | 3 | 4 | from typing import Optional 5 | from pydantic import BaseModel, StrictStr 6 | 7 | from api.models.output import OutputType 8 | 9 | 10 | class Stdout(BaseModel): 11 | type: OutputType = OutputType.STDOUT 12 | text: Optional[StrictStr] = None 13 | timestamp: Optional[datetime.datetime] = None 14 | 15 | 16 | class Stderr(BaseModel): 17 | type: OutputType = OutputType.STDERR 18 | text: Optional[StrictStr] = None 19 | timestamp: Optional[datetime.datetime] = None 20 | -------------------------------------------------------------------------------- /.github/scripts/is_release_for_package.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # This script checks if the specified package has changesets in the current commit. 4 | 5 | set -eu 6 | 7 | if [ $# -lt 1 ]; then 8 | echo "Error: Package name is required as the first argument." >&2 9 | exit 1 10 | fi 11 | 12 | PACKAGE_NAME=$1 13 | PACKAGE_CHANGES=$(node -e "require('@changesets/read').default(process.cwd()).then(result => console.log(result.flatMap(changeset => changeset.releases.flatMap(release => release.name)).includes('${PACKAGE_NAME}')))") 14 | 15 | echo "${PACKAGE_CHANGES}" 16 | -------------------------------------------------------------------------------- /python/tests/sync/test_basic.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from e2b_code_interpreter.code_interpreter_sync import Sandbox 4 | 5 | 6 | def test_basic(sandbox: Sandbox): 7 | result = sandbox.run_code("x =1; x") 8 | assert result.text == "1" 9 | 10 | 11 | @pytest.mark.skip_debug 12 | def test_secure_access(sandbox_factory): 13 | sandbox = sandbox_factory(secure=True, network={"allow_public_traffic": False}) 14 | # Create sandbox with public traffic disabled (secure access) 15 | result = sandbox.run_code("x =1; x") 16 | assert result.text == "1" 17 | -------------------------------------------------------------------------------- /chart_data_extractor/tests/utils/test_is_grid_line.py: -------------------------------------------------------------------------------- 1 | from matplotlib.lines import Line2D 2 | 3 | from e2b_charts.utils.filtering import is_grid_line 4 | 5 | 6 | def test_is_grid_line(): 7 | not_a_grid_line = Line2D([1, 2], [2, 3]) 8 | assert not is_grid_line(not_a_grid_line) 9 | 10 | horizontal_grid_line = Line2D([1, 2], [2, 2]) 11 | assert is_grid_line(horizontal_grid_line) 12 | 13 | vertical_grid_line = Line2D([1, 1], [2, 3]) 14 | assert is_grid_line(vertical_grid_line) 15 | 16 | long_line = Line2D([1, 1, 1, 1], [2, 3, 4, 5]) 17 | assert not is_grid_line(long_line) 18 | -------------------------------------------------------------------------------- /js/tests/runtimes/deno/run.test.ts: -------------------------------------------------------------------------------- 1 | import { assertEquals } from 'https://deno.land/std@0.224.0/assert/mod.ts' 2 | import { load } from 'https://deno.land/std@0.224.0/dotenv/mod.ts' 3 | 4 | await load({ envPath: '.env', export: true }) 5 | 6 | import { Sandbox } from '../../../dist/index.mjs' 7 | 8 | Deno.test('Deno test', async () => { 9 | const sbx = await Sandbox.create({ timeoutMs: 5_000 }) 10 | 11 | try { 12 | const result = await sbx.runCode('print("Hello, World!")') 13 | assertEquals(result.logs.stdout.join(''), 'Hello, World!\n') 14 | } finally { 15 | await sbx.kill() 16 | } 17 | }) 18 | -------------------------------------------------------------------------------- /python/tests/sync/test_display_data.py: -------------------------------------------------------------------------------- 1 | from e2b_code_interpreter.code_interpreter_sync import Sandbox 2 | 3 | 4 | def test_display_data(sandbox: Sandbox): 5 | # plot random chart 6 | result = sandbox.run_code( 7 | """ 8 | import matplotlib.pyplot as plt 9 | import numpy as np 10 | 11 | x = np.linspace(0, 20, 100) 12 | y = np.sin(x) 13 | 14 | plt.plot(x, y) 15 | plt.show() 16 | """ 17 | ) 18 | 19 | # there's your image 20 | data = result.results[0] 21 | assert data.png 22 | assert data.text 23 | assert not data.extra 24 | -------------------------------------------------------------------------------- /template/server/api/models/error.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | from pydantic import BaseModel, StrictStr 3 | from pydantic import Field 4 | 5 | from api.models.output import OutputType 6 | 7 | 8 | class Error(BaseModel): 9 | type: OutputType = OutputType.ERROR 10 | 11 | name: Optional[StrictStr] = Field(default=None, description="Name of the exception") 12 | value: Optional[StrictStr] = Field( 13 | default=None, description="Value of the exception" 14 | ) 15 | traceback: Optional[StrictStr] = Field( 16 | default=None, description="Traceback of the exception" 17 | ) 18 | -------------------------------------------------------------------------------- /template/server/envs.py: -------------------------------------------------------------------------------- 1 | import os 2 | from typing import Optional 3 | 4 | import httpx 5 | 6 | LOCAL = os.getenv("E2B_LOCAL", False) 7 | ENVD_PORT = 49983 8 | 9 | 10 | async def get_envs(access_token: Optional[str]) -> dict: 11 | if LOCAL: 12 | return {"E2B_TEST_VARIABLE": "true"} 13 | async with httpx.AsyncClient() as client: 14 | headers = {} 15 | if access_token: 16 | headers["X-Access-Token"] = f"{access_token}" 17 | response = await client.get( 18 | f"http://localhost:{ENVD_PORT}/envs", headers=headers 19 | ) 20 | return response.json() 21 | -------------------------------------------------------------------------------- /js/tests/displayData.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'vitest' 2 | 3 | import { sandboxTest } from './setup' 4 | 5 | sandboxTest('display data', async ({ sandbox }) => { 6 | // plot random chart 7 | const result = await sandbox.runCode(` 8 | import matplotlib.pyplot as plt 9 | import numpy as np 10 | 11 | x = np.linspace(0, 20, 100) 12 | y = np.sin(x) 13 | 14 | plt.plot(x, y) 15 | plt.show() 16 | `) 17 | 18 | const image = result.results[0] 19 | expect(image.png).toBeDefined() 20 | expect(image.text).toBeDefined() 21 | expect(image.extra).toEqual({}) 22 | }) 23 | -------------------------------------------------------------------------------- /template/server/api/models/execution_request.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | from pydantic import BaseModel, StrictStr 3 | from pydantic import Field 4 | 5 | from .env_vars import EnvVars 6 | 7 | 8 | class ExecutionRequest(BaseModel): 9 | code: StrictStr = Field(description="Code to be executed") 10 | context_id: Optional[StrictStr] = Field(default=None, description="Context ID") 11 | language: Optional[StrictStr] = Field( 12 | default=None, description="Language of the code" 13 | ) 14 | env_vars: Optional[EnvVars] = Field( 15 | description="Environment variables", default=None 16 | ) 17 | -------------------------------------------------------------------------------- /python/tests/async/test_async_basic.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from e2b_code_interpreter.code_interpreter_async import AsyncSandbox 4 | 5 | 6 | async def test_basic(async_sandbox: AsyncSandbox): 7 | result = await async_sandbox.run_code("x =1; x") 8 | assert result.text == "1" 9 | 10 | 11 | @pytest.mark.skip_debug 12 | async def test_secure_access(async_sandbox_factory): 13 | # Create sandbox with public traffic disabled (secure access) 14 | async_sandbox = await async_sandbox_factory(network={"allow_public_traffic": False}) 15 | result = await async_sandbox.run_code("x =1; x") 16 | assert result.text == "1" 17 | -------------------------------------------------------------------------------- /js/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "dist", 4 | "target": "es6", 5 | "lib": ["dom", "ESNext"], 6 | "sourceMap": true, 7 | "allowJs": true, 8 | "skipLibCheck": true, 9 | "esModuleInterop": true, 10 | "allowSyntheticDefaultImports": true, 11 | "strict": true, 12 | "forceConsistentCasingInFileNames": true, 13 | "noFallthroughCasesInSwitch": true, 14 | "moduleResolution": "node", 15 | "resolveJsonModule": true, 16 | "isolatedModules": true, 17 | "declaration": true 18 | }, 19 | "include": ["src"], 20 | "exclude": ["dist", "node_modules", "tsup.config.js"] 21 | } 22 | -------------------------------------------------------------------------------- /chart_data_extractor/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@e2b/data-extractor", 3 | "private": true, 4 | "version": "0.0.4", 5 | "scripts": { 6 | "test": "poetry run pytest -n 4 --verbose -x", 7 | "example": "poetry run python3 example.py", 8 | "postVersion": "poetry version $(pnpm pkg get version --workspaces=false | tr -d \\\")", 9 | "pretest": "poetry install", 10 | "lint": "poetry run ruff check .", 11 | "format": "poetry run ruff format ." 12 | }, 13 | "devDependencies": { 14 | "@typescript-eslint/eslint-plugin": "^7.11.0", 15 | "@typescript-eslint/parser": "^7.11.0", 16 | "eslint": "^8.57.1" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /template/startup_scripts/0003_images.py: -------------------------------------------------------------------------------- 1 | from typing import Any 2 | 3 | from IPython.core.display_functions import display 4 | from PIL.Image import Image 5 | from PIL.ImageShow import UnixViewer 6 | 7 | 8 | def show_file(self, path: str, **options: Any) -> int: 9 | # To prevent errors from trying to display image without any display 10 | return 0 11 | 12 | 13 | UnixViewer.show_file = show_file 14 | original_save = Image.save 15 | 16 | 17 | def save(image, fp, format=None, **options): 18 | if isinstance(fp, str): 19 | display(image) 20 | 21 | original_save(image, fp, format, **options) 22 | 23 | 24 | Image.save = save 25 | -------------------------------------------------------------------------------- /python/tests/async/test_async_display_data.py: -------------------------------------------------------------------------------- 1 | from e2b_code_interpreter.code_interpreter_async import AsyncSandbox 2 | 3 | 4 | async def test_display_data(async_sandbox: AsyncSandbox): 5 | # plot random chart 6 | result = await async_sandbox.run_code( 7 | """ 8 | import matplotlib.pyplot as plt 9 | import numpy as np 10 | 11 | x = np.linspace(0, 20, 100) 12 | y = np.sin(x) 13 | 14 | plt.plot(x, y) 15 | plt.show() 16 | """ 17 | ) 18 | 19 | # there's your image 20 | data = result.results[0] 21 | assert data.png 22 | assert data.text 23 | assert not data.extra 24 | -------------------------------------------------------------------------------- /python/tests/charts/test_json.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from e2b_code_interpreter.code_interpreter_async import AsyncSandbox 4 | 5 | code = """ 6 | import matplotlib.pyplot as plt 7 | import numpy as np 8 | 9 | # Create data 10 | N = 5 11 | x = np.random.rand(N) 12 | y = np.random.rand(N) 13 | 14 | plt.xlabel("A") 15 | 16 | plt.scatter(x, y, c='blue', label='Dataset') 17 | 18 | plt.show() 19 | """ 20 | 21 | 22 | async def test_scatter_chart(async_sandbox: AsyncSandbox): 23 | result = await async_sandbox.run_code(code) 24 | serialized = result.to_json() 25 | assert isinstance(serialized, str) 26 | 27 | assert json.loads(serialized)["results"][0]["chart"]["type"] == "scatter" 28 | -------------------------------------------------------------------------------- /js/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from 'e2b' 2 | 3 | export { Sandbox } from './sandbox' 4 | export type { Context, RunCodeOpts, CreateCodeContextOpts } from './sandbox' 5 | export type { 6 | Logs, 7 | ExecutionError, 8 | Result, 9 | Execution, 10 | MIMEType, 11 | RawData, 12 | OutputMessage, 13 | } from './messaging' 14 | export type { 15 | ScaleType, 16 | ChartType, 17 | ChartTypes, 18 | Chart, 19 | BarChart, 20 | BarData, 21 | LineChart, 22 | ScatterChart, 23 | BoxAndWhiskerChart, 24 | BoxAndWhiskerData, 25 | PieChart, 26 | PieData, 27 | SuperChart, 28 | PointData, 29 | } from './charts' 30 | import { Sandbox } from './sandbox' 31 | 32 | export default Sandbox 33 | -------------------------------------------------------------------------------- /js/vitest.config.mts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vitest/config' 2 | import { config } from 'dotenv' 3 | 4 | const env = config() 5 | 6 | export default defineConfig({ 7 | test: { 8 | poolOptions: { 9 | threads: { 10 | minThreads: 1, 11 | maxThreads: 4, 12 | }, 13 | }, 14 | include: ['tests/**/*.test.ts'], 15 | exclude: ['tests/runtimes/**'], 16 | globals: false, 17 | testTimeout: 30000, 18 | environment: 'node', 19 | bail: 0, 20 | server: {}, 21 | deps: { 22 | interopDefault: true, 23 | }, 24 | env: { 25 | ...(process.env as Record), 26 | ...env.parsed, 27 | }, 28 | }, 29 | }) 30 | -------------------------------------------------------------------------------- /chart_data_extractor/tests/charts/test_categorical_scale.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | 3 | from e2b_charts import chart_figure_to_chart 4 | from e2b_charts.charts import LineChart 5 | 6 | 7 | def _prep_chart_figure(): 8 | x = [1, 2, 3, 4, 5] 9 | y = ["A", "B", "C", "D", "E"] 10 | 11 | # Create the plot 12 | plt.figure(figsize=(10, 6)) 13 | plt.plot(x, y) 14 | 15 | return plt.gcf() 16 | 17 | 18 | def test_categorical_scale(): 19 | figure = _prep_chart_figure() 20 | chart = chart_figure_to_chart(figure) 21 | assert chart 22 | 23 | assert isinstance(chart, LineChart) 24 | assert chart.x_scale == "linear" 25 | assert chart.y_scale == "categorical" 26 | -------------------------------------------------------------------------------- /js/tests/kernels.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'vitest' 2 | 3 | import { sandboxTest } from './setup' 4 | 5 | sandboxTest('create new kernel', async ({ sandbox }) => { 6 | await sandbox.createCodeContext() 7 | }) 8 | 9 | sandboxTest('independence of kernels', async ({ sandbox }) => { 10 | await sandbox.runCode('x = 1') 11 | const context = await sandbox.createCodeContext() 12 | const output = await sandbox.runCode('x', { context }) 13 | 14 | expect(output.error!.value).toEqual("name 'x' is not defined") 15 | }) 16 | 17 | sandboxTest('pass context and language', async ({ sandbox }) => { 18 | const context = await sandbox.createCodeContext() 19 | await expect( 20 | sandbox.runCode({ context, language: 'python' }) 21 | ).rejects.toThrowError() 22 | }) 23 | -------------------------------------------------------------------------------- /python/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@e2b/code-interpreter-python", 3 | "private": true, 4 | "version": "2.4.1", 5 | "packageManager": "pnpm@9.15.5", 6 | "scripts": { 7 | "test": "poetry run pytest -n 4 --verbose -x", 8 | "example": "poetry run python3 example.py", 9 | "async-example": "poetry run python3 async_example.py", 10 | "postVersion": "poetry version $(pnpm pkg get version --workspaces=false | tr -d \\\")", 11 | "postPublish": "poetry build && poetry config pypi-token.pypi ${PYPI_TOKEN} && poetry publish --skip-existing", 12 | "pretest": "poetry install", 13 | "generate-ref": "poetry install && ./scripts/generate_sdk_ref.sh", 14 | "lint": "poetry run ruff check .", 15 | "format": "poetry run ruff format ." 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /template/start-up.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function start_jupyter_server() { 4 | counter=0 5 | response=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:8888/api/status") 6 | while [[ ${response} -ne 200 ]]; do 7 | let counter++ 8 | if ((counter % 20 == 0)); then 9 | echo "Waiting for Jupyter Server to start..." 10 | sleep 0.1 11 | fi 12 | 13 | response=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:8888/api/status") 14 | done 15 | 16 | cd /root/.server/ 17 | .venv/bin/uvicorn main:app --host 0.0.0.0 --port 49999 --workers 1 --no-access-log --no-use-colors --timeout-keep-alive 640 18 | } 19 | 20 | echo "Starting Code Interpreter server..." 21 | start_jupyter_server & 22 | MATPLOTLIBRC=/root/.config/matplotlib/.matplotlibrc jupyter server --IdentityProvider.token="" >/dev/null 2>&1 23 | -------------------------------------------------------------------------------- /python/tests/sync/test_kernels.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from e2b import InvalidArgumentException 3 | 4 | from e2b_code_interpreter.code_interpreter_sync import Sandbox 5 | 6 | 7 | def test_create_new_kernel(sandbox: Sandbox): 8 | sandbox.create_code_context() 9 | 10 | 11 | def test_independence_of_kernels(sandbox: Sandbox): 12 | context = sandbox.create_code_context() 13 | sandbox.run_code("x = 1") 14 | 15 | r = sandbox.run_code("x", context=context) 16 | assert r.error is not None 17 | assert r.error.value == "name 'x' is not defined" 18 | 19 | 20 | def test_pass_context_and_language(sandbox: Sandbox): 21 | context = sandbox.create_code_context(language="python") 22 | with pytest.raises(InvalidArgumentException): 23 | sandbox.run_code("console.log('Hello, World!')", language="js", context=context) 24 | -------------------------------------------------------------------------------- /chart_data_extractor/tests/utils/test_detect_scale.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | 3 | from matplotlib.dates import _SwitchableDateConverter 4 | 5 | from e2b_charts.charts.planar import PointChart 6 | 7 | 8 | def test_detect_scale(): 9 | datetime_converter = _SwitchableDateConverter() 10 | scale = PointChart._detect_scale( 11 | datetime_converter, "linear", 3 * [datetime.date.today()], ["1", "2", "3"] 12 | ) 13 | assert scale == "datetime" 14 | 15 | scale = PointChart._detect_scale(None, "linear", [1, 2, 3], ["1", "2", "3"]) 16 | assert scale == "linear" 17 | 18 | scale = PointChart._detect_scale( 19 | None, "linear", [0, 1, 2], ["First", "Second", "Third"] 20 | ) 21 | assert scale == "categorical" 22 | 23 | scale = PointChart._detect_scale(None, "log", [1, 10, 100], ["1", "10", "100"]) 24 | assert scale == "log" 25 | -------------------------------------------------------------------------------- /chart_data_extractor/tests/charts/test_datetime_scale.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | import datetime 4 | 5 | from e2b_charts import chart_figure_to_chart 6 | from e2b_charts.charts import LineChart 7 | 8 | 9 | def _prep_chart_figure(): 10 | # Generate x values 11 | dates = [ 12 | datetime.date(2023, 9, 1) + datetime.timedelta(seconds=i) for i in range(100) 13 | ] 14 | y_sin = np.sin(np.linspace(0, 2 * np.pi, 100)) 15 | 16 | # Create the plot 17 | plt.figure(figsize=(10, 6)) 18 | plt.plot(dates, y_sin, label="sin(x)") 19 | 20 | return plt.gcf() 21 | 22 | 23 | def test_datetime_scale(): 24 | figure = _prep_chart_figure() 25 | chart = chart_figure_to_chart(figure) 26 | assert chart 27 | 28 | assert isinstance(chart, LineChart) 29 | assert chart.x_scale == "datetime" 30 | assert chart.y_scale == "linear" 31 | -------------------------------------------------------------------------------- /.github/workflows/cleanup_build_template.yml: -------------------------------------------------------------------------------- 1 | name: Cleanup Build Template 2 | 3 | on: 4 | workflow_call: 5 | secrets: 6 | E2B_TESTS_ACCESS_TOKEN: 7 | required: true 8 | inputs: 9 | E2B_DOMAIN: 10 | required: false 11 | type: string 12 | E2B_TESTS_TEMPLATE: 13 | required: true 14 | type: string 15 | 16 | permissions: 17 | contents: read 18 | 19 | jobs: 20 | cleanup: 21 | name: Cleanup Build Template 22 | runs-on: ubuntu-latest 23 | steps: 24 | - name: Install E2B CLI 25 | run: npm install -g @e2b/cli 26 | 27 | - name: Cleanup E2B template 28 | id: cleanup-template 29 | run: | 30 | e2b template delete -y "${{ inputs.E2B_TESTS_TEMPLATE }}" 31 | env: 32 | E2B_ACCESS_TOKEN: ${{ secrets.E2B_TESTS_ACCESS_TOKEN }} 33 | E2B_DOMAIN: ${{ inputs.E2B_DOMAIN }} 34 | -------------------------------------------------------------------------------- /template/server/api/models/output.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from enum import Enum 4 | from pydantic import BaseModel 5 | 6 | 7 | class OutputType(Enum): 8 | """ 9 | Represents the type of the data to send to the client. 10 | """ 11 | 12 | STDOUT = "stdout" 13 | STDERR = "stderr" 14 | RESULT = "result" 15 | ERROR = "error" 16 | NUMBER_OF_EXECUTIONS = "number_of_executions" 17 | END_OF_EXECUTION = "end_of_execution" 18 | UNEXPECTED_END_OF_EXECUTION = "unexpected_end_of_execution" 19 | 20 | 21 | class EndOfExecution(BaseModel): 22 | type: OutputType = OutputType.END_OF_EXECUTION 23 | 24 | 25 | class UnexpectedEndOfExecution(BaseModel): 26 | type: OutputType = OutputType.UNEXPECTED_END_OF_EXECUTION 27 | 28 | 29 | class NumberOfExecutions(BaseModel): 30 | type: OutputType = OutputType.NUMBER_OF_EXECUTIONS 31 | execution_count: int 32 | -------------------------------------------------------------------------------- /js/typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "out": "sdk_ref", 3 | "plugin": ["typedoc-plugin-markdown", "./scripts/CustomMarkdownTheme.js"], 4 | "exclude": ["**/*.spec.ts"], 5 | "entryPoints": [ 6 | "src/index.ts", 7 | "src/charts.ts", 8 | "src/consts.ts", 9 | "src/messaging.ts", 10 | "src/sandbox.ts" 11 | ], 12 | "excludeExternals": true, 13 | "excludePrivate": true, 14 | "excludeProtected": true, 15 | "navigation": { 16 | "includeGroups": false, 17 | "includeCategories": false 18 | }, 19 | "outputFileStrategy": "modules", 20 | "readme": "none", 21 | "disableSources": true, 22 | // typedoc-plugin-markdown options 23 | "classPropertiesFormat": "table", 24 | "typeDeclarationFormat": "table", 25 | "enumMembersFormat": "table", 26 | "parametersFormat": "table", 27 | "expandParameters": true, 28 | "useCodeBlocks": true, 29 | "hidePageTitle": true, 30 | "hideBreadcrumbs": true 31 | } 32 | -------------------------------------------------------------------------------- /chart_data_extractor/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "e2b-charts" 3 | version = "0.0.4" 4 | description = "Package for extracting data for E2B Code Interpreter" 5 | authors = ["e2b "] 6 | license = "MIT" 7 | readme = "README.md" 8 | homepage = "https://e2b.dev/" 9 | repository = "https://github.com/e2b-dev/e2b-code-interpreter/tree/python" 10 | packages = [{ include = "e2b_charts" }] 11 | 12 | [tool.poetry.dependencies] 13 | python = "^3.10" 14 | 15 | numpy = "^1.26.4" 16 | matplotlib = "^3.9.2" 17 | pydantic = "^2.8.2" 18 | 19 | [tool.poetry.group.dev.dependencies] 20 | pytest = "^7.4.0" 21 | python-dotenv = "^1.0.0" 22 | pytest-dotenv = "^0.5.2" 23 | ruff = "^0.11.12" 24 | 25 | 26 | [build-system] 27 | requires = ["poetry-core"] 28 | build-backend = "poetry.core.masonry.api" 29 | 30 | [tool.poetry.urls] 31 | "Bug Tracker" = "https://github.com/e2b-dev/code-interpreter/issues" 32 | 33 | [tool.ruff.lint] 34 | ignore = ["F401", "F403"] -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | node: true, 4 | browser: true, 5 | es6: true, 6 | }, 7 | extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'], 8 | parser: '@typescript-eslint/parser', 9 | parserOptions: { 10 | ecmaVersion: 'latest', 11 | sourceType: 'module', 12 | }, 13 | ignorePatterns: ['dist/', 'node_modules/', '*.gen.ts'], 14 | plugins: ['@typescript-eslint', 'unused-imports', '@stylistic/ts'], 15 | rules: { 16 | '@typescript-eslint/member-ordering': 'error', 17 | '@typescript-eslint/ban-ts-comment': 'off', // "move fast" mode 18 | '@typescript-eslint/no-explicit-any': 'off', // "move fast" mode 19 | 'linebreak-style': ['error', 'unix'], 20 | 'unused-imports/no-unused-imports': 'error', 21 | // No double quotes 22 | quotes: ['error', 'single', { avoidEscape: true }], 23 | // No extra semicolon 24 | '@stylistic/ts/semi': ['error', 'never'], 25 | }, 26 | } 27 | -------------------------------------------------------------------------------- /chart_data_extractor/e2b_charts/charts/pie.py: -------------------------------------------------------------------------------- 1 | from decimal import Decimal 2 | from typing import Literal, List 3 | 4 | from matplotlib.axes import Axes 5 | from pydantic import BaseModel, Field 6 | 7 | from .base import Chart, ChartType 8 | from ..utils.rounding import dynamic_round 9 | 10 | 11 | class PieData(BaseModel): 12 | label: str 13 | angle: float 14 | radius: float 15 | 16 | 17 | class PieChart(Chart): 18 | type: Literal[ChartType.PIE] = ChartType.PIE 19 | 20 | elements: List[PieData] = Field(default_factory=list) 21 | 22 | def _extract_info(self, ax: Axes) -> None: 23 | super()._extract_info(ax) 24 | 25 | for wedge in ax.patches: 26 | pie_data = PieData( 27 | label=wedge.get_label(), 28 | angle=abs(dynamic_round(Decimal(wedge.theta2) - Decimal(wedge.theta1))), 29 | radius=wedge.r, 30 | ) 31 | 32 | self.elements.append(pie_data) 33 | -------------------------------------------------------------------------------- /js/example.mts: -------------------------------------------------------------------------------- 1 | import { config } from 'dotenv' 2 | 3 | import { Sandbox } from './dist' 4 | 5 | function log(...args: any[]) { 6 | console.log(...args) 7 | } 8 | 9 | config() 10 | 11 | const sbx = await Sandbox.create('bwyvo5fk343pbvxst536') 12 | log('ℹ️ sandbox created', sbx.sandboxId) 13 | 14 | await sbx.runCode('x = 1') 15 | log('Sandbox code executed') 16 | 17 | const sandboxId = await sbx.betaPause() 18 | log('Sandbox paused', sandboxId) 19 | 20 | // Resume the sandbox from the same state 21 | const sameSbx = await Sandbox.connect(sbx.sandboxId) 22 | log('Sandbox resumed', sameSbx.sandboxId) 23 | 24 | const execution = await sameSbx.runCode('x+=1; x') 25 | // Output result 26 | log(execution.text) 27 | log(execution.error) 28 | if (execution.text !== '2') { 29 | log('Test failed:', 'Failed to resume sandbox') 30 | throw new Error('Failed to resume sandbox') 31 | } 32 | log('Sandbox resumed successfully') 33 | 34 | await sbx.kill() 35 | log('Sandbox deleted') 36 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "e2b-code-interpreter-root", 3 | "private": true, 4 | "scripts": { 5 | "version": "pnpm changeset version && pnpm run -r postVersion", 6 | "publish": "pnpm changeset publish && pnpm run -r postPublish", 7 | "rm-node-modules": "find . -name 'node_modules' -type d -prune -exec rm -rf '{}' +", 8 | "lint": "pnpm --if-present --recursive run lint", 9 | "format": "pnpm --if-present --recursive run format", 10 | "changeset": "pnpx @changesets/cli" 11 | }, 12 | "packageManager": "pnpm@9.15.5", 13 | "devDependencies": { 14 | "@changesets/read": "^0.6.2", 15 | "changeset": "^0.2.6", 16 | "@typescript-eslint/eslint-plugin": "^6.7.2", 17 | "@typescript-eslint/parser": "^6.7.2", 18 | "eslint": "^8.57.1", 19 | "eslint-plugin-unused-imports": "^3.0.0", 20 | "@stylistic/eslint-plugin-ts": "^1.6.2", 21 | "prettier": "^3.6.2" 22 | }, 23 | "engines": { 24 | "pnpm": ">=9.0.0 <10" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /python/tests/async/test_async_kernels.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from e2b import InvalidArgumentException 3 | 4 | from e2b_code_interpreter.code_interpreter_async import AsyncSandbox 5 | 6 | 7 | async def test_create_new_kernel(async_sandbox: AsyncSandbox): 8 | await async_sandbox.create_code_context() 9 | 10 | 11 | async def test_independence_of_kernels(async_sandbox: AsyncSandbox): 12 | context = await async_sandbox.create_code_context() 13 | await async_sandbox.run_code("x = 1") 14 | 15 | r = await async_sandbox.run_code("x", context=context) 16 | assert r.error is not None 17 | assert r.error.value == "name 'x' is not defined" 18 | 19 | 20 | async def test_pass_context_and_language(async_sandbox: AsyncSandbox): 21 | context = await async_sandbox.create_code_context(language="python") 22 | with pytest.raises(InvalidArgumentException): 23 | await async_sandbox.run_code( 24 | "console.log('Hello, World!')", language="js", context=context 25 | ) 26 | -------------------------------------------------------------------------------- /template/requirements.txt: -------------------------------------------------------------------------------- 1 | # Jupyter server requirements 2 | jupyter-server==2.16.0 3 | ipykernel==6.29.5 4 | ipython==9.2.0 5 | 6 | orjson==3.10.18 7 | pandas==2.2.3 8 | matplotlib==3.10.3 9 | pillow==11.3.0 10 | 11 | # Latest version for 12 | e2b_charts 13 | 14 | # Other packages 15 | aiohttp==3.12.14 16 | beautifulsoup4==4.13.4 17 | bokeh==3.7.3 18 | gensim==4.3.3 # unmaintained, blocking numpy and scipy bump 19 | imageio==2.37.0 20 | joblib==1.5.0 21 | librosa==0.11.0 22 | nltk==3.9.1 23 | numpy==1.26.4 # bump blocked by gensim 24 | numba==0.61.2 25 | opencv-python==4.11.0.86 26 | openpyxl==3.1.5 27 | plotly==6.0.1 28 | kaleido==1.0.0 29 | pytest==8.3.5 30 | python-docx==1.1.2 31 | pytz==2025.2 32 | requests==2.32.4 33 | scikit-image==0.25.2 34 | scikit-learn==1.6.1 35 | scipy==1.13.1 # bump blocked by gensim 36 | seaborn==0.13.2 37 | soundfile==0.13.1 38 | spacy==3.8.2 # doesn't work on 3.13.x 39 | textblob==0.19.0 40 | tornado==6.5.1 41 | urllib3==2.6.0 42 | xarray==2025.4.0 43 | xlrd==2.0.1 44 | sympy==1.14.0 45 | -------------------------------------------------------------------------------- /python/tests/sync/test_streaming.py: -------------------------------------------------------------------------------- 1 | from e2b_code_interpreter.code_interpreter_sync import Sandbox 2 | 3 | 4 | def test_streaming_output(sandbox: Sandbox): 5 | out = [] 6 | 7 | def test(line) -> None: 8 | out.append(line) 9 | return 10 | 11 | sandbox.run_code("print(1)", on_stdout=test) 12 | 13 | assert len(out) == 1 14 | assert out[0].line == "1\n" 15 | 16 | 17 | def test_streaming_error(sandbox: Sandbox): 18 | out = [] 19 | 20 | sandbox.run_code("import sys;print(1, file=sys.stderr)", on_stderr=out.append) 21 | 22 | assert len(out) == 1 23 | assert out[0].line == "1\n" 24 | 25 | 26 | def test_streaming_result(sandbox: Sandbox): 27 | code = """ 28 | import matplotlib.pyplot as plt 29 | import numpy as np 30 | 31 | x = np.linspace(0, 20, 100) 32 | y = np.sin(x) 33 | 34 | plt.plot(x, y) 35 | plt.show() 36 | 37 | x 38 | """ 39 | 40 | out = [] 41 | sandbox.run_code(code, on_result=out.append) 42 | 43 | assert len(out) == 2 44 | -------------------------------------------------------------------------------- /.github/workflows/charts_tests.yml: -------------------------------------------------------------------------------- 1 | name: Test Python SDK 2 | 3 | on: 4 | workflow_call: 5 | 6 | permissions: 7 | contents: read 8 | 9 | jobs: 10 | publish: 11 | defaults: 12 | run: 13 | working-directory: ./chart_data_extractor 14 | name: Chart Data Extractor - Build and test 15 | runs-on: ubuntu-22.04 16 | steps: 17 | - name: Checkout repository 18 | uses: actions/checkout@v4 19 | 20 | - name: Set up Python 21 | uses: actions/setup-python@v4 22 | with: 23 | python-version: '3.12' 24 | 25 | - name: Install and configure Poetry 26 | uses: snok/install-poetry@v1 27 | with: 28 | version: 1.5.1 29 | virtualenvs-create: true 30 | virtualenvs-in-project: true 31 | installer-parallel: true 32 | 33 | - name: Install dependencies 34 | run: poetry install 35 | 36 | - name: Test build 37 | run: poetry build 38 | 39 | - name: Run tests 40 | run: poetry run pytest --verbose -x 41 | -------------------------------------------------------------------------------- /python/example.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | 3 | from dotenv import load_dotenv 4 | 5 | from e2b_code_interpreter import Sandbox 6 | 7 | load_dotenv() 8 | 9 | 10 | code = """ 11 | import matplotlib.pyplot as plt 12 | import numpy as np 13 | 14 | # Step 1: Define the data for the pie chart 15 | categories = ["No", "No, in blue"] 16 | sizes = [90, 10] 17 | 18 | # Step 2: Create the figure and axis objects 19 | fig, ax = plt.subplots(figsize=(8, 8)) 20 | 21 | plt.xlabel("x") 22 | plt.ylabel("y") 23 | 24 | # Step 3: Create the pie chart 25 | ax.pie(sizes, labels=categories, autopct='%1.1f%%', startangle=90, colors=plt.cm.Pastel1.colors[:len(categories)]) 26 | 27 | # Step 4: Add title and legend 28 | ax.axis('equal') # Equal aspect ratio ensures that pie is drawn as a circle 29 | plt.title('Will I wake up early tomorrow?') 30 | 31 | # Step 5: Show the plot 32 | plt.show() 33 | """ 34 | 35 | 36 | async def run(): 37 | sbx = Sandbox.create(timeout=60) 38 | e = sbx.run_code(code) 39 | print(e.results[0].chart) 40 | 41 | 42 | asyncio.run(run()) 43 | -------------------------------------------------------------------------------- /python/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "e2b-code-interpreter" 3 | version = "2.4.1" 4 | description = "E2B Code Interpreter - Stateful code execution" 5 | authors = ["e2b "] 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.9" 14 | 15 | httpx = ">=0.20.0, <1.0.0" 16 | attrs = ">=21.3.0" 17 | e2b = "^2.7.0" 18 | 19 | [tool.poetry.group.dev.dependencies] 20 | pytest = "^8.2.0" 21 | python-dotenv = "^1.0.0" 22 | pytest-dotenv = "^0.5.2" 23 | pytest-asyncio = "^0.24.0" 24 | pytest-xdist = "^3.6.1" 25 | pydoc-markdown = "^4.8.2" 26 | matplotlib = "^3.8.0" 27 | ruff = "^0.11.12" 28 | 29 | 30 | [build-system] 31 | requires = ["poetry-core"] 32 | build-backend = "poetry.core.masonry.api" 33 | 34 | [tool.poetry.urls] 35 | "Bug Tracker" = "https://github.com/e2b-dev/code-interpreter/issues" 36 | 37 | [tool.ruff.lint] 38 | ignore = ["F401", "F403"] -------------------------------------------------------------------------------- /js/LICENSE: -------------------------------------------------------------------------------- 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. 10 | -------------------------------------------------------------------------------- /chart_data_extractor/tests/charts/test_unknown.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | 3 | from e2b_charts import chart_figure_to_chart 4 | from e2b_charts.charts import Chart, ChartType 5 | 6 | 7 | def _prep_chart_figure(): 8 | # Create a figure and an axis 9 | fig, ax = plt.subplots() 10 | 11 | # Create data for two concentric circles 12 | circle1 = plt.Circle((0, 0), 1, color="blue", fill=False, linewidth=2) 13 | circle2 = plt.Circle((0, 0), 2, color="red", fill=False, linewidth=2) 14 | 15 | # Add the circles to the axes 16 | ax.add_artist(circle1) 17 | ax.add_artist(circle2) 18 | 19 | # Set grid 20 | ax.grid(True) 21 | 22 | # Set title 23 | plt.title("Two Concentric Circles") 24 | 25 | return plt.gcf() 26 | 27 | 28 | def test_unknown_charts(): 29 | figure = _prep_chart_figure() 30 | chart = chart_figure_to_chart(figure) 31 | assert chart 32 | 33 | assert isinstance(chart, Chart) 34 | assert chart.type == ChartType.UNKNOWN 35 | assert chart.title == "Two Concentric Circles" 36 | 37 | assert len(chart.elements) == 0 38 | -------------------------------------------------------------------------------- /python/LICENSE: -------------------------------------------------------------------------------- 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. 10 | -------------------------------------------------------------------------------- /chart_data_extractor/LICENSE: -------------------------------------------------------------------------------- 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. 10 | -------------------------------------------------------------------------------- /python/scripts/generate_sdk_ref.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euo pipefail 4 | 5 | # This script generates the python SDK reference markdown files 6 | # Run it in the `python-sdk/` directory 7 | 8 | PKG_VERSION="v$(node -p "require('./package.json').version")" 9 | ROUTES_DIR="../sdk-reference/code-interpreter-python-sdk/${PKG_VERSION}" 10 | mkdir -p "${ROUTES_DIR}" 11 | 12 | package="e2b_code_interpreter" 13 | 14 | mkdir -p sdk_ref 15 | 16 | # generate raw SDK reference markdown file 17 | poetry run pydoc-markdown -p "${package}" >sdk_ref/"${package}".mdx 18 | # remove package path display 19 | sed -i'' -e '/]*>.*<\/a>/d' "sdk_ref/${package}.mdx" 20 | # remove empty hyperlinks 21 | sed -i'' -e '/^# /d' "sdk_ref/${package}.mdx" 22 | # remove " Objects" from lines starting with "##" 23 | sed -i'' -e '/^## / s/ Objects$//' "sdk_ref/${package}.mdx" 24 | # replace lines starting with "####" with "###" 25 | sed -i'' -e 's/^####/###/' "sdk_ref/${package}.mdx" 26 | # move to docs 27 | mkdir -p "${ROUTES_DIR}/sandbox" 28 | mv "sdk_ref/${package}.mdx" "${ROUTES_DIR}/sandbox/page.mdx" 29 | 30 | rm -rf sdk_ref 31 | -------------------------------------------------------------------------------- /python/tests/charts/test_unknown.py: -------------------------------------------------------------------------------- 1 | from e2b_code_interpreter.code_interpreter_async import AsyncSandbox 2 | from e2b_code_interpreter.charts import ChartType, Chart 3 | 4 | code = """ 5 | import matplotlib.pyplot as plt 6 | import numpy as np 7 | 8 | # Create a figure and an axis 9 | fig, ax = plt.subplots() 10 | 11 | # Create data for two concentric circles 12 | circle1 = plt.Circle((0, 0), 1, color='blue', fill=False, linewidth=2) 13 | circle2 = plt.Circle((0, 0), 2, color='red', fill=False, linewidth=2) 14 | 15 | # Add the circles to the axes 16 | ax.add_artist(circle1) 17 | ax.add_artist(circle2) 18 | 19 | # Set grid 20 | ax.grid(True) 21 | 22 | # Set title 23 | plt.title('Two Concentric Circles') 24 | 25 | # Show the plot 26 | plt.show() 27 | """ 28 | 29 | 30 | async def test_unknown_charts(async_sandbox: AsyncSandbox): 31 | result = await async_sandbox.run_code(code) 32 | 33 | chart = result.results[0].chart 34 | assert chart 35 | 36 | assert isinstance(chart, Chart) 37 | assert chart.type == ChartType.UNKNOWN 38 | assert chart.title == "Two Concentric Circles" 39 | 40 | assert len(chart.elements) == 0 41 | -------------------------------------------------------------------------------- /python/tests/async/test_async_streaming.py: -------------------------------------------------------------------------------- 1 | from e2b_code_interpreter.code_interpreter_async import AsyncSandbox 2 | 3 | 4 | async def test_streaming_output(async_sandbox: AsyncSandbox): 5 | out = [] 6 | 7 | def test(line) -> None: 8 | out.append(line) 9 | return 10 | 11 | await async_sandbox.run_code("print(1)", on_stdout=test) 12 | 13 | assert len(out) == 1 14 | assert out[0].line == "1\n" 15 | 16 | 17 | async def test_streaming_error(async_sandbox: AsyncSandbox): 18 | out = [] 19 | 20 | await async_sandbox.run_code( 21 | "import sys;print(1, file=sys.stderr)", on_stderr=out.append 22 | ) 23 | 24 | assert len(out) == 1 25 | assert out[0].line == "1\n" 26 | 27 | 28 | async def test_streaming_result(async_sandbox: AsyncSandbox): 29 | code = """ 30 | import matplotlib.pyplot as plt 31 | import numpy as np 32 | 33 | x = np.linspace(0, 20, 100) 34 | y = np.sin(x) 35 | 36 | plt.plot(x, y) 37 | plt.show() 38 | 39 | x 40 | """ 41 | 42 | out = [] 43 | await async_sandbox.run_code(code, on_result=out.append) 44 | 45 | assert len(out) == 2 46 | -------------------------------------------------------------------------------- /js/tests/charts/unknown.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'vitest' 2 | 3 | import { sandboxTest } from '../setup' 4 | 5 | // Skip this test if we are running in debug mode — the pwd and user in the testing docker container are not the same as in the actual sandbox. 6 | sandboxTest('unknown', async ({ sandbox }) => { 7 | const code = ` 8 | import matplotlib.pyplot as plt 9 | import numpy as np 10 | 11 | # Create a figure and an axis 12 | fig, ax = plt.subplots() 13 | 14 | # Create data for two concentric circles 15 | circle1 = plt.Circle((0, 0), 1, color='blue', fill=False, linewidth=2) 16 | circle2 = plt.Circle((0, 0), 2, color='red', fill=False, linewidth=2) 17 | 18 | # Add the circles to the axes 19 | ax.add_artist(circle1) 20 | ax.add_artist(circle2) 21 | 22 | # Set grid 23 | ax.grid(True) 24 | 25 | # Set title 26 | plt.title('Two Concentric Circles') 27 | 28 | # Show the plot 29 | plt.show() 30 | ` 31 | const result = await sandbox.runCode(code) 32 | const chart = result.results[0].chart 33 | 34 | expect(chart).toBeDefined() 35 | expect(chart.type).toBe('unknown') 36 | expect(chart.title).toBe('Two Concentric Circles') 37 | 38 | expect(chart.elements.length).toBe(0) 39 | }) 40 | -------------------------------------------------------------------------------- /python/tests/sync/test_callbacks.py: -------------------------------------------------------------------------------- 1 | from e2b_code_interpreter.code_interpreter_sync import Sandbox 2 | 3 | 4 | def test_resuls(sandbox: Sandbox): 5 | results = [] 6 | execution = sandbox.run_code( 7 | "x = 1;x", on_result=lambda result: results.append(result) 8 | ) 9 | assert len(results) == 1 10 | assert execution.results[0].text == "1" 11 | 12 | 13 | def test_error(sandbox: Sandbox): 14 | errors = [] 15 | execution = sandbox.run_code("xyz", on_error=lambda error: errors.append(error)) 16 | assert len(errors) == 1 17 | assert execution.error.name == "NameError" 18 | 19 | 20 | def test_stdout(sandbox: Sandbox): 21 | stdout = [] 22 | execution = sandbox.run_code( 23 | "print('Hello from e2b')", on_stdout=lambda out: stdout.append(out) 24 | ) 25 | assert len(stdout) == 1 26 | assert execution.logs.stdout == ["Hello from e2b\n"] 27 | 28 | 29 | def test_stderr(sandbox: Sandbox): 30 | stderr = [] 31 | execution = sandbox.run_code( 32 | 'import sys;print("This is an error message", file=sys.stderr)', 33 | on_stderr=lambda err: stderr.append(err), 34 | ) 35 | assert len(stderr) == 1 36 | assert execution.logs.stderr == ["This is an error message\n"] 37 | -------------------------------------------------------------------------------- /python/tests/async/test_async_default_kernels.py: -------------------------------------------------------------------------------- 1 | from e2b_code_interpreter.code_interpreter_async import AsyncSandbox 2 | 3 | 4 | async def test_js_kernel(async_sandbox: AsyncSandbox): 5 | execution = await async_sandbox.run_code( 6 | "console.log('Hello, World!')", language="js" 7 | ) 8 | assert execution.logs.stdout == ["Hello, World!\n"] 9 | 10 | 11 | async def test_js_esm_imports(async_sandbox: AsyncSandbox): 12 | execution = await async_sandbox.run_code( 13 | """ 14 | import { readFileSync } from 'fs' 15 | console.log(typeof readFileSync) 16 | """, 17 | language="js", 18 | ) 19 | assert execution.logs.stdout == ["function\n"] 20 | 21 | 22 | async def test_js_top_level_await(async_sandbox: AsyncSandbox): 23 | execution = await async_sandbox.run_code( 24 | """ 25 | await Promise.resolve('Hello World!') 26 | """, 27 | language="js", 28 | ) 29 | assert execution.text == "Hello World!" 30 | 31 | 32 | async def test_ts_kernel(async_sandbox: AsyncSandbox): 33 | execution = await async_sandbox.run_code( 34 | "const message: string = 'Hello, World!'; console.log(message);", language="ts" 35 | ) 36 | assert execution.logs.stdout == ["Hello, World!\n"] 37 | -------------------------------------------------------------------------------- /js/scripts/generate_sdk_ref.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euo pipefail 4 | 5 | # This script generates the Code Interpreter JS SDK reference markdown files 6 | # Run it in the `js/` directory 7 | 8 | # generate raw SDK reference markdown files 9 | npx typedoc 10 | 11 | PKG_VERSION="v$(node -p "require('./package.json').version")" 12 | ROUTES_DIR="../sdk-reference/code-interpreter-js-sdk/${PKG_VERSION}" 13 | mkdir -p "${ROUTES_DIR}" 14 | 15 | rm -rf sdk_ref/README.md 16 | 17 | # Flatten the sdk_ref directory by moving all nested files to the root level and remove empty subdirectories 18 | find sdk_ref -mindepth 2 -type f | while read -r file; do 19 | mv "$file" sdk_ref/ 20 | done 21 | find sdk_ref -type d -empty -delete 22 | 23 | # Transfrom top level MD files into folders of the same name with page.mdx inside 24 | find sdk_ref -maxdepth 1 -type f -name "*.md" | while read -r file; do 25 | # Extract the filename without extension 26 | filename=$(basename "$file" .md) 27 | # Create the directory of the same name in sdk_ref 28 | mkdir -p "sdk_ref/${filename}" 29 | # Move the file inside the newly created directory 30 | mv "$file" "sdk_ref/${filename}/page.mdx" 31 | done 32 | 33 | cp -r sdk_ref/* "${ROUTES_DIR}" 34 | 35 | rm -rf sdk_ref 36 | -------------------------------------------------------------------------------- /js/tests/streaming.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'vitest' 2 | 3 | import { Result, OutputMessage } from '../src' 4 | 5 | import { sandboxTest } from './setup' 6 | 7 | sandboxTest('streaming output', async ({ sandbox }) => { 8 | const out: OutputMessage[] = [] 9 | await sandbox.runCode('print(1)', { 10 | onStdout: (msg) => out.push(msg), 11 | }) 12 | 13 | expect(out.length).toEqual(1) 14 | expect(out[0].line).toEqual('1\n') 15 | }) 16 | 17 | sandboxTest('streaming error', async ({ sandbox }) => { 18 | const out: OutputMessage[] = [] 19 | await sandbox.runCode('import sys;print(1, file=sys.stderr)', { 20 | onStderr: (msg) => out.push(msg), 21 | }) 22 | 23 | expect(out.length).toEqual(1) 24 | expect(out[0].line).toEqual('1\n') 25 | }) 26 | 27 | sandboxTest('streaming result', async ({ sandbox }) => { 28 | const out: Result[] = [] 29 | const code = ` 30 | import matplotlib.pyplot as plt 31 | import numpy as np 32 | 33 | x = np.linspace(0, 20, 100) 34 | y = np.sin(x) 35 | 36 | plt.plot(x, y) 37 | plt.show() 38 | 39 | x 40 | ` 41 | await sandbox.runCode(code, { 42 | onResult: (result) => out.push(result), 43 | }) 44 | 45 | expect(out.length).toEqual(2) 46 | }) 47 | -------------------------------------------------------------------------------- /template/README.md: -------------------------------------------------------------------------------- 1 | # Using custom sandbox with Code Interpreter SDK 2 | 3 | If you want to customize the Code Interpreter sandbox (e.g.: add a preinstalled package) you can do that by creating a [custom sandbox template](https://e2b.dev/docs/template/quickstart). 4 | 5 | ## Step-by-step guide 6 | 7 | 1. Install E2B SDK 8 | 9 | ``` 10 | pip install e2b dotenv 11 | ``` 12 | 13 | 2. Create a custom sandbox template: 14 | 15 | **template.py** 16 | 17 | ```python 18 | from e2b import Template 19 | 20 | template = Template().from_template("code-interpreter-v1") 21 | ``` 22 | 23 | 3. Create a build script: 24 | 25 | **build.py** 26 | 27 | ```python 28 | from dotenv import load_dotenv 29 | from .template import template 30 | from e2b import Template, default_build_logger 31 | 32 | load_dotenv() 33 | 34 | Template.build( 35 | template, 36 | alias="code-interpreter-custom", 37 | cpu_count=2, 38 | memory_mb=2048, 39 | on_build_logs=default_build_logger(), 40 | ) 41 | ``` 42 | 43 | 3. Build the template: 44 | 45 | ``` 46 | python build.py 47 | ``` 48 | 49 | 4. Use the custom template: 50 | 51 | ```python 52 | from e2b import Sandbox 53 | 54 | sbx = Sandbox.create(template="code-interpreter-custom") 55 | execution = sbx.run_code("print('Hello, World!')") 56 | print(execution.logs.stdout) 57 | ``` 58 | -------------------------------------------------------------------------------- /js/tests/defaultKernels.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'vitest' 2 | 3 | import { sandboxTest } from './setup' 4 | 5 | sandboxTest('test js kernel', async ({ sandbox }) => { 6 | const output = await sandbox.runCode('console.log("Hello World!")', { 7 | language: 'js', 8 | }) 9 | expect(output.logs.stdout).toEqual(['Hello World!\n']) 10 | }) 11 | 12 | sandboxTest('test esm imports', async ({ sandbox }) => { 13 | const output = await sandbox.runCode( 14 | ` 15 | import { readFileSync } from 'fs' 16 | console.log(typeof readFileSync) 17 | `, 18 | { 19 | language: 'js', 20 | } 21 | ) 22 | expect(output.logs.stdout).toEqual(['function\n']) 23 | }) 24 | 25 | sandboxTest( 26 | 'test top-level await and promise resolution', 27 | async ({ sandbox }) => { 28 | const output = await sandbox.runCode( 29 | ` 30 | await Promise.resolve('Hello World!') 31 | `, 32 | { 33 | language: 'js', 34 | } 35 | ) 36 | expect(output.text).toEqual('Hello World!') 37 | } 38 | ) 39 | 40 | sandboxTest('test ts kernel', async ({ sandbox }) => { 41 | const output = await sandbox.runCode( 42 | 'const message: string = "Hello World!"; console.log(message)', 43 | { language: 'ts' } 44 | ) 45 | expect(output.logs.stdout).toEqual(['Hello World!\n']) 46 | }) 47 | -------------------------------------------------------------------------------- /python/tests/sync/env_vars/test_bash.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from e2b_code_interpreter import Sandbox 3 | 4 | 5 | @pytest.mark.skip_debug() 6 | def test_env_vars_on_sandbox(template): 7 | sandbox = Sandbox.create(template=template, envs={"TEST_ENV_VAR": "supertest"}) 8 | try: 9 | result = sandbox.run_code("echo $TEST_ENV_VAR", language="bash") 10 | assert result.logs.stdout[0] == "supertest\n" 11 | finally: 12 | sandbox.kill() 13 | 14 | 15 | def test_env_vars_per_execution(sandbox: Sandbox): 16 | result = sandbox.run_code("echo $FOO", envs={"FOO": "bar"}, language="bash") 17 | 18 | result_empty = sandbox.run_code("echo ${FOO:-default}", language="bash") 19 | 20 | assert result.logs.stdout[0] == "bar\n" 21 | assert result_empty.logs.stdout[0] == "default\n" 22 | 23 | 24 | @pytest.mark.skip_debug() 25 | def test_env_vars_overwrite(template): 26 | sandbox = Sandbox.create(template=template, envs={"TEST_ENV_VAR": "supertest"}) 27 | try: 28 | result = sandbox.run_code( 29 | "echo $TEST_ENV_VAR", language="bash", envs={"TEST_ENV_VAR": "overwrite"} 30 | ) 31 | result_global_default = sandbox.run_code("echo $TEST_ENV_VAR", language="bash") 32 | assert result.logs.stdout[0] == "overwrite\n" 33 | assert result_global_default.logs.stdout[0] == "supertest\n" 34 | finally: 35 | sandbox.kill() 36 | -------------------------------------------------------------------------------- /js/tests/callbacks.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'vitest' 2 | 3 | import { sandboxTest } from './setup' 4 | 5 | sandboxTest('callback results', async ({ sandbox }) => { 6 | const results = [] 7 | const result = await sandbox.runCode('x =1; x', { 8 | onResult: (result) => results.push(result), 9 | }) 10 | 11 | expect(results.length).toBe(1) 12 | expect(result.results[0].text).toBe('1') 13 | }) 14 | 15 | sandboxTest('callback error', async ({ sandbox }) => { 16 | const errors = [] 17 | const result = await sandbox.runCode('xyz', { 18 | onError: (error) => errors.push(error), 19 | }) 20 | 21 | expect(errors.length).toBe(1) 22 | expect(result.error.name).toBe('NameError') 23 | }) 24 | 25 | sandboxTest('callback stdout', async ({ sandbox }) => { 26 | const stdout = [] 27 | const result = await sandbox.runCode('print("hello")', { 28 | onStdout: (out) => stdout.push(out), 29 | }) 30 | 31 | expect(stdout.length).toBe(1) 32 | expect(result.logs.stdout).toEqual(['hello\n']) 33 | }) 34 | 35 | sandboxTest('callback stderr', async ({ sandbox }) => { 36 | const stderr = [] 37 | const result = await sandbox.runCode( 38 | 'import sys;print("This is an error message", file=sys.stderr)', 39 | { 40 | onStderr: (err) => stderr.push(err), 41 | } 42 | ) 43 | 44 | expect(stderr.length).toBe(1) 45 | expect(result.logs.stderr).toEqual(['This is an error message\n']) 46 | }) 47 | -------------------------------------------------------------------------------- /.github/workflows/python_tests.yml: -------------------------------------------------------------------------------- 1 | name: Test Python SDK 2 | 3 | on: 4 | workflow_call: 5 | secrets: 6 | E2B_API_KEY: 7 | required: true 8 | inputs: 9 | E2B_DOMAIN: 10 | required: false 11 | type: string 12 | E2B_TESTS_TEMPLATE: 13 | required: false 14 | type: string 15 | 16 | permissions: 17 | contents: read 18 | 19 | jobs: 20 | publish: 21 | defaults: 22 | run: 23 | working-directory: ./python 24 | name: Python SDK - Build and test 25 | runs-on: ubuntu-22.04 26 | steps: 27 | - name: Checkout repository 28 | uses: actions/checkout@v4 29 | 30 | - name: Set up Python 31 | uses: actions/setup-python@v4 32 | with: 33 | python-version: '3.12' 34 | 35 | - name: Install and configure Poetry 36 | uses: snok/install-poetry@v1 37 | with: 38 | version: 1.5.1 39 | virtualenvs-create: true 40 | virtualenvs-in-project: true 41 | installer-parallel: true 42 | 43 | - name: Install dependencies 44 | run: poetry install 45 | 46 | - name: Test build 47 | run: poetry build 48 | 49 | - name: Run tests 50 | run: poetry run pytest --verbose -x 51 | env: 52 | E2B_API_KEY: ${{ secrets.E2B_API_KEY }} 53 | E2B_DOMAIN: ${{ inputs.E2B_DOMAIN }} 54 | E2B_TESTS_TEMPLATE: ${{ inputs.E2B_TESTS_TEMPLATE }} -------------------------------------------------------------------------------- /js/tests/charts/scales.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'vitest' 2 | 3 | import { sandboxTest } from '../setup' 4 | sandboxTest('datetime scale', async ({ sandbox }) => { 5 | const code = ` 6 | import numpy as np 7 | import matplotlib.pyplot as plt 8 | import datetime 9 | 10 | # Generate x values 11 | dates = [datetime.date(2023, 9, 1) + datetime.timedelta(seconds=i) for i in range(100)] 12 | y_sin = np.sin(np.linspace(0, 2*np.pi, 100)) 13 | 14 | # Create the plot 15 | plt.figure(figsize=(10, 6)) 16 | plt.plot(dates, y_sin, label='sin(x)') 17 | plt.show() 18 | ` 19 | 20 | const result = await sandbox.runCode(code) 21 | 22 | const chart = result.results[0].chart 23 | expect(chart).toBeDefined() 24 | expect(chart.type).toBe('line') 25 | 26 | expect(chart.x_scale).toBe('datetime') 27 | expect(chart.y_scale).toBe('linear') 28 | }) 29 | 30 | sandboxTest('categorical scale', async ({ sandbox }) => { 31 | const code = ` 32 | import numpy as np 33 | import matplotlib.pyplot as plt 34 | 35 | x = [1, 2, 3, 4, 5] 36 | y = ['A', 'B', 'C', 'D', 'E'] 37 | 38 | # Create the plot 39 | plt.figure(figsize=(10, 6)) 40 | plt.plot(x, y) 41 | plt.show() 42 | ` 43 | 44 | const result = await sandbox.runCode(code) 45 | 46 | const chart = result.results[0].chart 47 | expect(chart).toBeTruthy() 48 | 49 | expect(chart.type).toBe('line') 50 | expect(chart.x_scale).toBe('linear') 51 | expect(chart.y_scale).toBe('categorical') 52 | }) 53 | -------------------------------------------------------------------------------- /python/tests/images/test_images.py: -------------------------------------------------------------------------------- 1 | from e2b_code_interpreter.code_interpreter_async import AsyncSandbox 2 | 3 | 4 | async def test_show_image(async_sandbox: AsyncSandbox): 5 | code = """ 6 | import numpy 7 | from PIL import Image 8 | 9 | imarray = numpy.random.rand(16,16,3) * 255 10 | image = Image.fromarray(imarray.astype('uint8')).convert('RGBA') 11 | 12 | image.show() 13 | print("Image shown.") 14 | """ 15 | 16 | execution = await async_sandbox.run_code(code) 17 | 18 | image = execution.results[0].png 19 | assert image 20 | 21 | 22 | async def test_image_as_last_command(async_sandbox: AsyncSandbox): 23 | code = """ 24 | import numpy 25 | from PIL import Image 26 | 27 | imarray = numpy.random.rand(16,16,3) * 255 28 | image = Image.fromarray(imarray.astype('uint8')).convert('RGBA') 29 | 30 | image 31 | """ 32 | execution = await async_sandbox.run_code(code) 33 | 34 | image = execution.results[0].png 35 | assert image 36 | 37 | 38 | async def test_get_image_on_save(async_sandbox: AsyncSandbox): 39 | code = """ 40 | import numpy 41 | from PIL import Image 42 | 43 | imarray = numpy.random.rand(16,16,3) * 255 44 | image = Image.fromarray(imarray.astype('uint8')).convert('RGBA') 45 | 46 | image.save("test.png") 47 | print("Image saved.") 48 | """ 49 | 50 | execution = await async_sandbox.run_code(code) 51 | 52 | image = execution.results[0].png 53 | assert image 54 | -------------------------------------------------------------------------------- /template/server/stream.py: -------------------------------------------------------------------------------- 1 | import json 2 | from typing import Mapping, Optional, AsyncIterable 3 | 4 | from fastapi.encoders import jsonable_encoder 5 | from starlette.background import BackgroundTask 6 | from fastapi.responses import StreamingResponse 7 | 8 | 9 | class StreamingListJsonResponse(StreamingResponse): 10 | """Converts a pydantic model generator into a streaming HTTP Response 11 | that streams a JSON list, one element at a time. 12 | 13 | See https://github.com/tiangolo/fastapi/issues/1978 14 | """ 15 | 16 | def __init__( 17 | self, 18 | content_generator: AsyncIterable, 19 | status_code: int = 200, 20 | headers: Optional[Mapping[str, str]] = None, 21 | media_type: Optional[str] = None, 22 | background: Optional[BackgroundTask] = None, 23 | ) -> None: 24 | body_iterator = self._encoded_async_generator(content_generator) 25 | 26 | super().__init__( 27 | content=body_iterator, 28 | status_code=status_code, 29 | headers=headers, 30 | media_type=media_type, 31 | background=background, 32 | ) 33 | 34 | async def _encoded_async_generator(self, async_generator: AsyncIterable): 35 | """Converts an asynchronous pydantic model generator 36 | into a streaming JSON list 37 | """ 38 | async for item in async_generator: 39 | yield f"{json.dumps(jsonable_encoder(item))}\n" 40 | yield '{"type": "end_of_execution"}\n' 41 | -------------------------------------------------------------------------------- /chart_data_extractor/tests/charts/test_bar.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | 3 | from e2b_charts import chart_figure_to_chart 4 | from e2b_charts.charts import BarChart, ChartType 5 | 6 | 7 | def _prep_chart_figure(): 8 | # Prepare data 9 | authors = ["Author A", "Author B", "Author C", "Author D"] 10 | sales = [100, 200, 300, 400] 11 | 12 | # Create and customize the bar chart 13 | plt.figure(figsize=(10, 6)) 14 | plt.bar(authors, sales, label="Books Sold", color="blue") 15 | plt.xlabel("Authors") 16 | plt.ylabel("Number of Books Sold") 17 | plt.title("Book Sales by Authors") 18 | 19 | # Display the chart 20 | plt.tight_layout() 21 | return plt.gcf() 22 | 23 | 24 | def test_chart_bar(): 25 | figure = _prep_chart_figure() 26 | chart = chart_figure_to_chart(figure) 27 | assert chart 28 | 29 | assert isinstance(chart, BarChart) 30 | assert chart.type == ChartType.BAR 31 | assert chart.title == "Book Sales by Authors" 32 | 33 | assert chart.x_label == "Authors" 34 | assert chart.y_label == "Number of Books Sold" 35 | 36 | assert chart.x_unit is None 37 | assert chart.y_unit is None 38 | 39 | bars = chart.elements 40 | assert len(bars) == 4 41 | 42 | assert [bar.value for bar in bars] == [100, 200, 300, 400] 43 | assert [bar.label for bar in bars] == [ 44 | "Author A", 45 | "Author B", 46 | "Author C", 47 | "Author D", 48 | ] 49 | assert [bar.group for bar in bars] == ["Books Sold"] * 4 50 | -------------------------------------------------------------------------------- /js/src/utils.ts: -------------------------------------------------------------------------------- 1 | import { TimeoutError } from 'e2b' 2 | 3 | export function formatRequestTimeoutError(error: unknown) { 4 | if (error instanceof Error && error.name === 'AbortError') { 5 | return new TimeoutError( 6 | "Request timed out — the 'requestTimeoutMs' option can be used to increase this timeout" 7 | ) 8 | } 9 | 10 | return error 11 | } 12 | 13 | export function formatExecutionTimeoutError(error: unknown) { 14 | if (error instanceof Error && error.name === 'AbortError') { 15 | return new TimeoutError( 16 | "Execution timed out — the 'timeoutMs' option can be used to increase this timeout" 17 | ) 18 | } 19 | 20 | return error 21 | } 22 | 23 | export async function* readLines(stream: ReadableStream) { 24 | const reader = stream.getReader() 25 | let buffer = '' 26 | 27 | try { 28 | while (true) { 29 | const { done, value } = await reader.read() 30 | 31 | if (value !== undefined) { 32 | buffer += new TextDecoder().decode(value) 33 | } 34 | 35 | if (done) { 36 | if (buffer.length > 0) { 37 | yield buffer 38 | } 39 | break 40 | } 41 | 42 | let newlineIdx = -1 43 | 44 | do { 45 | newlineIdx = buffer.indexOf('\n') 46 | if (newlineIdx !== -1) { 47 | yield buffer.slice(0, newlineIdx) 48 | buffer = buffer.slice(newlineIdx + 1) 49 | } 50 | } while (newlineIdx !== -1) 51 | } 52 | } finally { 53 | reader.releaseLock() 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /python/tests/charts/test_bar.py: -------------------------------------------------------------------------------- 1 | from e2b_code_interpreter.code_interpreter_async import AsyncSandbox 2 | from e2b_code_interpreter.charts import ChartType, BarChart 3 | 4 | code = """ 5 | import matplotlib.pyplot as plt 6 | 7 | # Prepare data 8 | authors = ['Author A', 'Author B', 'Author C', 'Author D'] 9 | sales = [100, 200, 300, 400] 10 | 11 | # Create and customize the bar chart 12 | plt.figure(figsize=(10, 6)) 13 | plt.bar(authors, sales, label='Books Sold', color='blue') 14 | plt.xlabel('Authors') 15 | plt.ylabel('Number of Books Sold') 16 | plt.title('Book Sales by Authors') 17 | 18 | # Display the chart 19 | plt.tight_layout() 20 | plt.show() 21 | """ 22 | 23 | 24 | async def test_chart_bar(async_sandbox: AsyncSandbox): 25 | result = await async_sandbox.run_code(code) 26 | 27 | chart = result.results[0].chart 28 | assert chart 29 | 30 | assert isinstance(chart, BarChart) 31 | assert chart.type == ChartType.BAR 32 | assert chart.title == "Book Sales by Authors" 33 | 34 | assert chart.x_label == "Authors" 35 | assert chart.y_label == "Number of Books Sold" 36 | 37 | assert chart.x_unit is None 38 | assert chart.y_unit is None 39 | 40 | bars = chart.elements 41 | assert len(bars) == 4 42 | 43 | assert [bar.value for bar in bars] == [100, 200, 300, 400] 44 | assert [bar.label for bar in bars] == [ 45 | "Author A", 46 | "Author B", 47 | "Author C", 48 | "Author D", 49 | ] 50 | assert [bar.group for bar in bars] == ["Books Sold"] * 4 51 | -------------------------------------------------------------------------------- /js/tests/charts/pie.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'vitest' 2 | 3 | import { sandboxTest } from '../setup' 4 | 5 | sandboxTest('pie', async ({ sandbox }) => { 6 | const code = ` 7 | import matplotlib.pyplot as plt 8 | import numpy as np 9 | 10 | # Step 1: Define the data for the pie chart 11 | categories = ["No", "No, in blue"] 12 | sizes = [90, 10] 13 | 14 | # Step 2: Create the figure and axis objects 15 | fig, ax = plt.subplots(figsize=(8, 8)) 16 | 17 | plt.xlabel("x") 18 | plt.ylabel("y") 19 | 20 | # Step 3: Create the pie chart 21 | ax.pie(sizes, labels=categories, autopct='%1.1f%%', startangle=90, colors=plt.cm.Pastel1.colors[:len(categories)]) 22 | 23 | # Step 4: Add title and legend 24 | ax.axis('equal') # Equal aspect ratio ensures that pie is drawn as a circle 25 | plt.title('Will I wake up early tomorrow?') 26 | 27 | # Step 5: Show the plot 28 | plt.show() 29 | ` 30 | const result = await sandbox.runCode(code) 31 | const chart = result.results[0].chart 32 | 33 | expect(chart).toBeDefined() 34 | expect(chart.type).toBe('pie') 35 | 36 | expect(chart.title).toBe('Will I wake up early tomorrow?') 37 | 38 | expect(chart.elements.length).toBe(2) 39 | 40 | const [firstData, secondData] = chart.elements 41 | 42 | expect(firstData.label).toBe('No') 43 | expect(firstData.angle).toBe(324) // 90% of 360 degrees 44 | expect(firstData.radius).toBe(1) 45 | 46 | expect(secondData.label).toBe('No, in blue') 47 | expect(secondData.angle).toBe(36) // 10% of 360 degrees 48 | expect(secondData.radius).toBe(1) 49 | }) 50 | -------------------------------------------------------------------------------- /python/tests/charts/test_scale.py: -------------------------------------------------------------------------------- 1 | from e2b_code_interpreter.code_interpreter_async import AsyncSandbox 2 | from e2b_code_interpreter.charts import LineChart 3 | 4 | 5 | async def test_datetime_scale(async_sandbox: AsyncSandbox): 6 | code = """ 7 | import numpy as np 8 | import matplotlib.pyplot as plt 9 | import datetime 10 | 11 | # Generate x values 12 | dates = [datetime.date(2023, 9, 1) + datetime.timedelta(seconds=i) for i in range(100)] 13 | y_sin = np.sin(np.linspace(0, 2*np.pi, 100)) 14 | 15 | # Create the plot 16 | plt.figure(figsize=(10, 6)) 17 | plt.plot(dates, y_sin, label='sin(x)') 18 | plt.show() 19 | """ 20 | 21 | result = await async_sandbox.run_code(code) 22 | 23 | chart = result.results[0].chart 24 | assert chart 25 | 26 | assert isinstance(chart, LineChart) 27 | assert chart.x_scale == "datetime" 28 | assert chart.y_scale == "linear" 29 | 30 | 31 | async def test_categorical_scale(async_sandbox: AsyncSandbox): 32 | code = """ 33 | import numpy as np 34 | import matplotlib.pyplot as plt 35 | 36 | x = [1, 2, 3, 4, 5] 37 | y = ['A', 'B', 'C', 'D', 'E'] 38 | 39 | # Create the plot 40 | plt.figure(figsize=(10, 6)) 41 | plt.plot(x, y) 42 | plt.show() 43 | """ 44 | 45 | result = await async_sandbox.run_code(code) 46 | 47 | chart = result.results[0].chart 48 | assert chart 49 | 50 | assert isinstance(chart, LineChart) 51 | assert chart.x_scale == "linear" 52 | assert chart.y_scale == "categorical" 53 | -------------------------------------------------------------------------------- /python/tests/charts/test_pie.py: -------------------------------------------------------------------------------- 1 | from e2b_code_interpreter.code_interpreter_async import AsyncSandbox 2 | from e2b_code_interpreter.charts import PieChart 3 | 4 | code = """ 5 | import matplotlib.pyplot as plt 6 | import numpy as np 7 | 8 | # Step 1: Define the data for the pie chart 9 | categories = ["No", "No, in blue"] 10 | sizes = [90, 10] 11 | 12 | # Step 2: Create the figure and axis objects 13 | fig, ax = plt.subplots(figsize=(8, 8)) 14 | 15 | plt.xlabel("x") 16 | plt.ylabel("y") 17 | 18 | # Step 3: Create the pie chart 19 | ax.pie(sizes, labels=categories, autopct='%1.1f%%', startangle=90, colors=plt.cm.Pastel1.colors[:len(categories)]) 20 | 21 | # Step 4: Add title and legend 22 | ax.axis('equal') # Equal aspect ratio ensures that pie is drawn as a circle 23 | plt.title('Will I wake up early tomorrow?') 24 | 25 | # Step 5: Show the plot 26 | plt.show() 27 | """ 28 | 29 | 30 | async def test_pie_chart(async_sandbox: AsyncSandbox): 31 | result = await async_sandbox.run_code(code) 32 | 33 | chart = result.results[0].chart 34 | assert chart 35 | 36 | assert isinstance(chart, PieChart) 37 | 38 | assert chart.title == "Will I wake up early tomorrow?" 39 | 40 | assert len(chart.elements) == 2 41 | 42 | first_data = chart.elements[0] 43 | assert first_data.label == "No" 44 | assert first_data.angle == 324 45 | assert first_data.radius == 1 46 | 47 | second_data = chart.elements[1] 48 | assert second_data.label == "No, in blue" 49 | assert second_data.angle == 36 50 | assert second_data.radius == 1 51 | -------------------------------------------------------------------------------- /chart_data_extractor/tests/charts/test_pie.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | 3 | from e2b_charts import chart_figure_to_chart 4 | from e2b_charts.charts import PieChart 5 | 6 | 7 | def _prep_chart_figure(): 8 | # Step 1: Define the data for the pie chart 9 | categories = ["No", "No, in blue"] 10 | sizes = [90, 10] 11 | 12 | # Step 2: Create the figure and axis objects 13 | fig, ax = plt.subplots(figsize=(8, 8)) 14 | 15 | plt.xlabel("x") 16 | plt.ylabel("y") 17 | 18 | # Step 3: Create the pie chart 19 | ax.pie( 20 | sizes, 21 | labels=categories, 22 | autopct="%1.1f%%", 23 | startangle=90, 24 | colors=plt.cm.Pastel1.colors[: len(categories)], 25 | ) 26 | 27 | # Step 4: Add title and legend 28 | ax.axis("equal") # Equal aspect ratio ensures that pie is drawn as a circle 29 | plt.title("Will I wake up early tomorrow?") 30 | 31 | return plt.gcf() 32 | 33 | 34 | def test_pie_chart(): 35 | figure = _prep_chart_figure() 36 | chart = chart_figure_to_chart(figure) 37 | assert chart 38 | 39 | assert isinstance(chart, PieChart) 40 | 41 | assert chart.title == "Will I wake up early tomorrow?" 42 | 43 | assert len(chart.elements) == 2 44 | 45 | first_data = chart.elements[0] 46 | assert first_data.label == "No" 47 | assert first_data.angle == 324 48 | assert first_data.radius == 1 49 | 50 | second_data = chart.elements[1] 51 | assert second_data.label == "No, in blue" 52 | assert second_data.angle == 36 53 | assert second_data.radius == 1 54 | -------------------------------------------------------------------------------- /python/tests/sync/test_default_kernels.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from e2b_code_interpreter.code_interpreter_sync import Sandbox 4 | 5 | 6 | def test_js_kernel(sandbox: Sandbox): 7 | execution = sandbox.run_code("console.log('Hello, World!')", language="js") 8 | assert execution.logs.stdout == ["Hello, World!\n"] 9 | 10 | 11 | @pytest.mark.skip_debug() 12 | def test_r_kernel(sandbox: Sandbox): 13 | execution = sandbox.run_code('print("Hello, World!")', language="r") 14 | assert execution.logs.stdout == ['[1] "Hello, World!"\n'] 15 | 16 | 17 | @pytest.mark.skip_debug() 18 | def test_java_kernel(sandbox: Sandbox): 19 | execution = sandbox.run_code('System.out.println("Hello, World!")', language="java") 20 | assert execution.logs.stdout[0] == "Hello, World!" 21 | 22 | 23 | def test_js_esm_imports(sandbox: Sandbox): 24 | execution = sandbox.run_code( 25 | """ 26 | import { readFileSync } from 'fs' 27 | console.log(typeof readFileSync) 28 | """, 29 | language="js", 30 | ) 31 | assert execution.logs.stdout == ["function\n"] 32 | 33 | 34 | def test_js_top_level_await(sandbox: Sandbox): 35 | execution = sandbox.run_code( 36 | """ 37 | await Promise.resolve('Hello World!') 38 | """, 39 | language="js", 40 | ) 41 | assert execution.text == "Hello World!" 42 | 43 | 44 | @pytest.mark.skip_debug() 45 | def test_ts_kernel(sandbox: Sandbox): 46 | execution = sandbox.run_code( 47 | "const message: string = 'Hello, World!'; console.log(message)", language="ts" 48 | ) 49 | assert execution.logs.stdout == ["Hello, World!\n"] 50 | -------------------------------------------------------------------------------- /python/tests/async/env_vars/test_bash.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from e2b_code_interpreter.code_interpreter_async import AsyncSandbox 3 | 4 | 5 | @pytest.mark.skip_debug() 6 | async def test_env_vars_on_sandbox(template): 7 | sandbox = await AsyncSandbox.create( 8 | template=template, envs={"TEST_ENV_VAR": "supertest"} 9 | ) 10 | try: 11 | result = await sandbox.run_code("echo $TEST_ENV_VAR", language="bash") 12 | assert result.logs.stdout[0] == "supertest\n" 13 | finally: 14 | await sandbox.kill() 15 | 16 | 17 | async def test_env_vars_per_execution(async_sandbox: AsyncSandbox): 18 | result = await async_sandbox.run_code( 19 | "echo $FOO", envs={"FOO": "bar"}, language="bash" 20 | ) 21 | 22 | result_empty = await async_sandbox.run_code("echo ${FOO:-default}", language="bash") 23 | 24 | assert result.logs.stdout[0] == "bar\n" 25 | assert result_empty.logs.stdout[0] == "default\n" 26 | 27 | 28 | @pytest.mark.skip_debug() 29 | async def test_env_vars_overwrite(template): 30 | sandbox = await AsyncSandbox.create( 31 | template=template, envs={"TEST_ENV_VAR": "supertest"} 32 | ) 33 | try: 34 | result = await sandbox.run_code( 35 | "echo $TEST_ENV_VAR", language="bash", envs={"TEST_ENV_VAR": "overwrite"} 36 | ) 37 | result_global_default = await sandbox.run_code( 38 | "echo $TEST_ENV_VAR", language="bash" 39 | ) 40 | assert result.logs.stdout[0] == "overwrite\n" 41 | assert result_global_default.logs.stdout[0] == "supertest\n" 42 | finally: 43 | await sandbox.kill() 44 | -------------------------------------------------------------------------------- /sdk-reference/code-interpreter-js-sdk/v1.0.4/index/page.mdx: -------------------------------------------------------------------------------- 1 | ### BarChart 2 | 3 | Re-exports BarChart 4 | 5 | ### BarData 6 | 7 | Re-exports BarData 8 | 9 | ### BoxAndWhiskerChart 10 | 11 | Re-exports BoxAndWhiskerChart 12 | 13 | ### BoxAndWhiskerData 14 | 15 | Re-exports BoxAndWhiskerData 16 | 17 | ### Chart 18 | 19 | Re-exports Chart 20 | 21 | ### ChartType 22 | 23 | Re-exports ChartType 24 | 25 | ### ChartTypes 26 | 27 | Re-exports ChartTypes 28 | 29 | ### Context 30 | 31 | Re-exports Context 32 | 33 | ### CreateCodeContextOpts 34 | 35 | Re-exports CreateCodeContextOpts 36 | 37 | ### default 38 | 39 | Renames and re-exports Sandbox 40 | 41 | ### Execution 42 | 43 | Re-exports Execution 44 | 45 | ### ExecutionError 46 | 47 | Re-exports ExecutionError 48 | 49 | ### LineChart 50 | 51 | Re-exports LineChart 52 | 53 | ### Logs 54 | 55 | Re-exports Logs 56 | 57 | ### MIMEType 58 | 59 | Re-exports MIMEType 60 | 61 | ### OutputMessage 62 | 63 | Re-exports OutputMessage 64 | 65 | ### PieChart 66 | 67 | Re-exports PieChart 68 | 69 | ### PieData 70 | 71 | Re-exports PieData 72 | 73 | ### PointData 74 | 75 | Re-exports PointData 76 | 77 | ### RawData 78 | 79 | Re-exports RawData 80 | 81 | ### Result 82 | 83 | Re-exports Result 84 | 85 | ### RunCodeOpts 86 | 87 | Re-exports RunCodeOpts 88 | 89 | ### Sandbox 90 | 91 | Re-exports Sandbox 92 | 93 | ### ScaleType 94 | 95 | Re-exports ScaleType 96 | 97 | ### ScatterChart 98 | 99 | Re-exports ScatterChart 100 | 101 | ### SuperChart 102 | 103 | Re-exports SuperChart 104 | -------------------------------------------------------------------------------- /sdk-reference/code-interpreter-js-sdk/v1.1.0/index/page.mdx: -------------------------------------------------------------------------------- 1 | ### BarChart 2 | 3 | Re-exports BarChart 4 | 5 | ### BarData 6 | 7 | Re-exports BarData 8 | 9 | ### BoxAndWhiskerChart 10 | 11 | Re-exports BoxAndWhiskerChart 12 | 13 | ### BoxAndWhiskerData 14 | 15 | Re-exports BoxAndWhiskerData 16 | 17 | ### Chart 18 | 19 | Re-exports Chart 20 | 21 | ### ChartType 22 | 23 | Re-exports ChartType 24 | 25 | ### ChartTypes 26 | 27 | Re-exports ChartTypes 28 | 29 | ### Context 30 | 31 | Re-exports Context 32 | 33 | ### CreateCodeContextOpts 34 | 35 | Re-exports CreateCodeContextOpts 36 | 37 | ### default 38 | 39 | Renames and re-exports Sandbox 40 | 41 | ### Execution 42 | 43 | Re-exports Execution 44 | 45 | ### ExecutionError 46 | 47 | Re-exports ExecutionError 48 | 49 | ### LineChart 50 | 51 | Re-exports LineChart 52 | 53 | ### Logs 54 | 55 | Re-exports Logs 56 | 57 | ### MIMEType 58 | 59 | Re-exports MIMEType 60 | 61 | ### OutputMessage 62 | 63 | Re-exports OutputMessage 64 | 65 | ### PieChart 66 | 67 | Re-exports PieChart 68 | 69 | ### PieData 70 | 71 | Re-exports PieData 72 | 73 | ### PointData 74 | 75 | Re-exports PointData 76 | 77 | ### RawData 78 | 79 | Re-exports RawData 80 | 81 | ### Result 82 | 83 | Re-exports Result 84 | 85 | ### RunCodeOpts 86 | 87 | Re-exports RunCodeOpts 88 | 89 | ### Sandbox 90 | 91 | Re-exports Sandbox 92 | 93 | ### ScaleType 94 | 95 | Re-exports ScaleType 96 | 97 | ### ScatterChart 98 | 99 | Re-exports ScatterChart 100 | 101 | ### SuperChart 102 | 103 | Re-exports SuperChart 104 | -------------------------------------------------------------------------------- /sdk-reference/code-interpreter-js-sdk/v1.1.1/index/page.mdx: -------------------------------------------------------------------------------- 1 | ### BarChart 2 | 3 | Re-exports BarChart 4 | 5 | ### BarData 6 | 7 | Re-exports BarData 8 | 9 | ### BoxAndWhiskerChart 10 | 11 | Re-exports BoxAndWhiskerChart 12 | 13 | ### BoxAndWhiskerData 14 | 15 | Re-exports BoxAndWhiskerData 16 | 17 | ### Chart 18 | 19 | Re-exports Chart 20 | 21 | ### ChartType 22 | 23 | Re-exports ChartType 24 | 25 | ### ChartTypes 26 | 27 | Re-exports ChartTypes 28 | 29 | ### Context 30 | 31 | Re-exports Context 32 | 33 | ### CreateCodeContextOpts 34 | 35 | Re-exports CreateCodeContextOpts 36 | 37 | ### default 38 | 39 | Renames and re-exports Sandbox 40 | 41 | ### Execution 42 | 43 | Re-exports Execution 44 | 45 | ### ExecutionError 46 | 47 | Re-exports ExecutionError 48 | 49 | ### LineChart 50 | 51 | Re-exports LineChart 52 | 53 | ### Logs 54 | 55 | Re-exports Logs 56 | 57 | ### MIMEType 58 | 59 | Re-exports MIMEType 60 | 61 | ### OutputMessage 62 | 63 | Re-exports OutputMessage 64 | 65 | ### PieChart 66 | 67 | Re-exports PieChart 68 | 69 | ### PieData 70 | 71 | Re-exports PieData 72 | 73 | ### PointData 74 | 75 | Re-exports PointData 76 | 77 | ### RawData 78 | 79 | Re-exports RawData 80 | 81 | ### Result 82 | 83 | Re-exports Result 84 | 85 | ### RunCodeOpts 86 | 87 | Re-exports RunCodeOpts 88 | 89 | ### Sandbox 90 | 91 | Re-exports Sandbox 92 | 93 | ### ScaleType 94 | 95 | Re-exports ScaleType 96 | 97 | ### ScatterChart 98 | 99 | Re-exports ScatterChart 100 | 101 | ### SuperChart 102 | 103 | Re-exports SuperChart 104 | -------------------------------------------------------------------------------- /sdk-reference/code-interpreter-js-sdk/v1.2.0/index/page.mdx: -------------------------------------------------------------------------------- 1 | ### BarChart 2 | 3 | Re-exports BarChart 4 | 5 | ### BarData 6 | 7 | Re-exports BarData 8 | 9 | ### BoxAndWhiskerChart 10 | 11 | Re-exports BoxAndWhiskerChart 12 | 13 | ### BoxAndWhiskerData 14 | 15 | Re-exports BoxAndWhiskerData 16 | 17 | ### Chart 18 | 19 | Re-exports Chart 20 | 21 | ### ChartType 22 | 23 | Re-exports ChartType 24 | 25 | ### ChartTypes 26 | 27 | Re-exports ChartTypes 28 | 29 | ### Context 30 | 31 | Re-exports Context 32 | 33 | ### CreateCodeContextOpts 34 | 35 | Re-exports CreateCodeContextOpts 36 | 37 | ### default 38 | 39 | Renames and re-exports Sandbox 40 | 41 | ### Execution 42 | 43 | Re-exports Execution 44 | 45 | ### ExecutionError 46 | 47 | Re-exports ExecutionError 48 | 49 | ### LineChart 50 | 51 | Re-exports LineChart 52 | 53 | ### Logs 54 | 55 | Re-exports Logs 56 | 57 | ### MIMEType 58 | 59 | Re-exports MIMEType 60 | 61 | ### OutputMessage 62 | 63 | Re-exports OutputMessage 64 | 65 | ### PieChart 66 | 67 | Re-exports PieChart 68 | 69 | ### PieData 70 | 71 | Re-exports PieData 72 | 73 | ### PointData 74 | 75 | Re-exports PointData 76 | 77 | ### RawData 78 | 79 | Re-exports RawData 80 | 81 | ### Result 82 | 83 | Re-exports Result 84 | 85 | ### RunCodeOpts 86 | 87 | Re-exports RunCodeOpts 88 | 89 | ### Sandbox 90 | 91 | Re-exports Sandbox 92 | 93 | ### ScaleType 94 | 95 | Re-exports ScaleType 96 | 97 | ### ScatterChart 98 | 99 | Re-exports ScatterChart 100 | 101 | ### SuperChart 102 | 103 | Re-exports SuperChart 104 | -------------------------------------------------------------------------------- /sdk-reference/code-interpreter-js-sdk/v1.5.0/index/page.mdx: -------------------------------------------------------------------------------- 1 | ### BarChart 2 | 3 | Re-exports BarChart 4 | 5 | ### BarData 6 | 7 | Re-exports BarData 8 | 9 | ### BoxAndWhiskerChart 10 | 11 | Re-exports BoxAndWhiskerChart 12 | 13 | ### BoxAndWhiskerData 14 | 15 | Re-exports BoxAndWhiskerData 16 | 17 | ### Chart 18 | 19 | Re-exports Chart 20 | 21 | ### ChartType 22 | 23 | Re-exports ChartType 24 | 25 | ### ChartTypes 26 | 27 | Re-exports ChartTypes 28 | 29 | ### Context 30 | 31 | Re-exports Context 32 | 33 | ### CreateCodeContextOpts 34 | 35 | Re-exports CreateCodeContextOpts 36 | 37 | ### default 38 | 39 | Renames and re-exports Sandbox 40 | 41 | ### Execution 42 | 43 | Re-exports Execution 44 | 45 | ### ExecutionError 46 | 47 | Re-exports ExecutionError 48 | 49 | ### LineChart 50 | 51 | Re-exports LineChart 52 | 53 | ### Logs 54 | 55 | Re-exports Logs 56 | 57 | ### MIMEType 58 | 59 | Re-exports MIMEType 60 | 61 | ### OutputMessage 62 | 63 | Re-exports OutputMessage 64 | 65 | ### PieChart 66 | 67 | Re-exports PieChart 68 | 69 | ### PieData 70 | 71 | Re-exports PieData 72 | 73 | ### PointData 74 | 75 | Re-exports PointData 76 | 77 | ### RawData 78 | 79 | Re-exports RawData 80 | 81 | ### Result 82 | 83 | Re-exports Result 84 | 85 | ### RunCodeOpts 86 | 87 | Re-exports RunCodeOpts 88 | 89 | ### Sandbox 90 | 91 | Re-exports Sandbox 92 | 93 | ### ScaleType 94 | 95 | Re-exports ScaleType 96 | 97 | ### ScatterChart 98 | 99 | Re-exports ScatterChart 100 | 101 | ### SuperChart 102 | 103 | Re-exports SuperChart 104 | -------------------------------------------------------------------------------- /sdk-reference/code-interpreter-js-sdk/v1.5.1/index/page.mdx: -------------------------------------------------------------------------------- 1 | ### BarChart 2 | 3 | Re-exports BarChart 4 | 5 | ### BarData 6 | 7 | Re-exports BarData 8 | 9 | ### BoxAndWhiskerChart 10 | 11 | Re-exports BoxAndWhiskerChart 12 | 13 | ### BoxAndWhiskerData 14 | 15 | Re-exports BoxAndWhiskerData 16 | 17 | ### Chart 18 | 19 | Re-exports Chart 20 | 21 | ### ChartType 22 | 23 | Re-exports ChartType 24 | 25 | ### ChartTypes 26 | 27 | Re-exports ChartTypes 28 | 29 | ### Context 30 | 31 | Re-exports Context 32 | 33 | ### CreateCodeContextOpts 34 | 35 | Re-exports CreateCodeContextOpts 36 | 37 | ### default 38 | 39 | Renames and re-exports Sandbox 40 | 41 | ### Execution 42 | 43 | Re-exports Execution 44 | 45 | ### ExecutionError 46 | 47 | Re-exports ExecutionError 48 | 49 | ### LineChart 50 | 51 | Re-exports LineChart 52 | 53 | ### Logs 54 | 55 | Re-exports Logs 56 | 57 | ### MIMEType 58 | 59 | Re-exports MIMEType 60 | 61 | ### OutputMessage 62 | 63 | Re-exports OutputMessage 64 | 65 | ### PieChart 66 | 67 | Re-exports PieChart 68 | 69 | ### PieData 70 | 71 | Re-exports PieData 72 | 73 | ### PointData 74 | 75 | Re-exports PointData 76 | 77 | ### RawData 78 | 79 | Re-exports RawData 80 | 81 | ### Result 82 | 83 | Re-exports Result 84 | 85 | ### RunCodeOpts 86 | 87 | Re-exports RunCodeOpts 88 | 89 | ### Sandbox 90 | 91 | Re-exports Sandbox 92 | 93 | ### ScaleType 94 | 95 | Re-exports ScaleType 96 | 97 | ### ScatterChart 98 | 99 | Re-exports ScatterChart 100 | 101 | ### SuperChart 102 | 103 | Re-exports SuperChart 104 | -------------------------------------------------------------------------------- /sdk-reference/code-interpreter-js-sdk/v2.0.0/index/page.mdx: -------------------------------------------------------------------------------- 1 | ### BarChart 2 | 3 | Re-exports BarChart 4 | 5 | ### BarData 6 | 7 | Re-exports BarData 8 | 9 | ### BoxAndWhiskerChart 10 | 11 | Re-exports BoxAndWhiskerChart 12 | 13 | ### BoxAndWhiskerData 14 | 15 | Re-exports BoxAndWhiskerData 16 | 17 | ### Chart 18 | 19 | Re-exports Chart 20 | 21 | ### ChartType 22 | 23 | Re-exports ChartType 24 | 25 | ### ChartTypes 26 | 27 | Re-exports ChartTypes 28 | 29 | ### Context 30 | 31 | Re-exports Context 32 | 33 | ### CreateCodeContextOpts 34 | 35 | Re-exports CreateCodeContextOpts 36 | 37 | ### default 38 | 39 | Renames and re-exports Sandbox 40 | 41 | ### Execution 42 | 43 | Re-exports Execution 44 | 45 | ### ExecutionError 46 | 47 | Re-exports ExecutionError 48 | 49 | ### LineChart 50 | 51 | Re-exports LineChart 52 | 53 | ### Logs 54 | 55 | Re-exports Logs 56 | 57 | ### MIMEType 58 | 59 | Re-exports MIMEType 60 | 61 | ### OutputMessage 62 | 63 | Re-exports OutputMessage 64 | 65 | ### PieChart 66 | 67 | Re-exports PieChart 68 | 69 | ### PieData 70 | 71 | Re-exports PieData 72 | 73 | ### PointData 74 | 75 | Re-exports PointData 76 | 77 | ### RawData 78 | 79 | Re-exports RawData 80 | 81 | ### Result 82 | 83 | Re-exports Result 84 | 85 | ### RunCodeOpts 86 | 87 | Re-exports RunCodeOpts 88 | 89 | ### Sandbox 90 | 91 | Re-exports Sandbox 92 | 93 | ### ScaleType 94 | 95 | Re-exports ScaleType 96 | 97 | ### ScatterChart 98 | 99 | Re-exports ScatterChart 100 | 101 | ### SuperChart 102 | 103 | Re-exports SuperChart 104 | -------------------------------------------------------------------------------- /sdk-reference/code-interpreter-js-sdk/v2.0.1/index/page.mdx: -------------------------------------------------------------------------------- 1 | ### BarChart 2 | 3 | Re-exports BarChart 4 | 5 | ### BarData 6 | 7 | Re-exports BarData 8 | 9 | ### BoxAndWhiskerChart 10 | 11 | Re-exports BoxAndWhiskerChart 12 | 13 | ### BoxAndWhiskerData 14 | 15 | Re-exports BoxAndWhiskerData 16 | 17 | ### Chart 18 | 19 | Re-exports Chart 20 | 21 | ### ChartType 22 | 23 | Re-exports ChartType 24 | 25 | ### ChartTypes 26 | 27 | Re-exports ChartTypes 28 | 29 | ### Context 30 | 31 | Re-exports Context 32 | 33 | ### CreateCodeContextOpts 34 | 35 | Re-exports CreateCodeContextOpts 36 | 37 | ### default 38 | 39 | Renames and re-exports Sandbox 40 | 41 | ### Execution 42 | 43 | Re-exports Execution 44 | 45 | ### ExecutionError 46 | 47 | Re-exports ExecutionError 48 | 49 | ### LineChart 50 | 51 | Re-exports LineChart 52 | 53 | ### Logs 54 | 55 | Re-exports Logs 56 | 57 | ### MIMEType 58 | 59 | Re-exports MIMEType 60 | 61 | ### OutputMessage 62 | 63 | Re-exports OutputMessage 64 | 65 | ### PieChart 66 | 67 | Re-exports PieChart 68 | 69 | ### PieData 70 | 71 | Re-exports PieData 72 | 73 | ### PointData 74 | 75 | Re-exports PointData 76 | 77 | ### RawData 78 | 79 | Re-exports RawData 80 | 81 | ### Result 82 | 83 | Re-exports Result 84 | 85 | ### RunCodeOpts 86 | 87 | Re-exports RunCodeOpts 88 | 89 | ### Sandbox 90 | 91 | Re-exports Sandbox 92 | 93 | ### ScaleType 94 | 95 | Re-exports ScaleType 96 | 97 | ### ScatterChart 98 | 99 | Re-exports ScatterChart 100 | 101 | ### SuperChart 102 | 103 | Re-exports SuperChart 104 | -------------------------------------------------------------------------------- /sdk-reference/code-interpreter-js-sdk/v2.1.0/index/page.mdx: -------------------------------------------------------------------------------- 1 | ### BarChart 2 | 3 | Re-exports BarChart 4 | 5 | ### BarData 6 | 7 | Re-exports BarData 8 | 9 | ### BoxAndWhiskerChart 10 | 11 | Re-exports BoxAndWhiskerChart 12 | 13 | ### BoxAndWhiskerData 14 | 15 | Re-exports BoxAndWhiskerData 16 | 17 | ### Chart 18 | 19 | Re-exports Chart 20 | 21 | ### ChartType 22 | 23 | Re-exports ChartType 24 | 25 | ### ChartTypes 26 | 27 | Re-exports ChartTypes 28 | 29 | ### Context 30 | 31 | Re-exports Context 32 | 33 | ### CreateCodeContextOpts 34 | 35 | Re-exports CreateCodeContextOpts 36 | 37 | ### default 38 | 39 | Renames and re-exports Sandbox 40 | 41 | ### Execution 42 | 43 | Re-exports Execution 44 | 45 | ### ExecutionError 46 | 47 | Re-exports ExecutionError 48 | 49 | ### LineChart 50 | 51 | Re-exports LineChart 52 | 53 | ### Logs 54 | 55 | Re-exports Logs 56 | 57 | ### MIMEType 58 | 59 | Re-exports MIMEType 60 | 61 | ### OutputMessage 62 | 63 | Re-exports OutputMessage 64 | 65 | ### PieChart 66 | 67 | Re-exports PieChart 68 | 69 | ### PieData 70 | 71 | Re-exports PieData 72 | 73 | ### PointData 74 | 75 | Re-exports PointData 76 | 77 | ### RawData 78 | 79 | Re-exports RawData 80 | 81 | ### Result 82 | 83 | Re-exports Result 84 | 85 | ### RunCodeOpts 86 | 87 | Re-exports RunCodeOpts 88 | 89 | ### Sandbox 90 | 91 | Re-exports Sandbox 92 | 93 | ### ScaleType 94 | 95 | Re-exports ScaleType 96 | 97 | ### ScatterChart 98 | 99 | Re-exports ScatterChart 100 | 101 | ### SuperChart 102 | 103 | Re-exports SuperChart 104 | -------------------------------------------------------------------------------- /sdk-reference/code-interpreter-js-sdk/v2.2.0/index/page.mdx: -------------------------------------------------------------------------------- 1 | ### BarChart 2 | 3 | Re-exports BarChart 4 | 5 | ### BarData 6 | 7 | Re-exports BarData 8 | 9 | ### BoxAndWhiskerChart 10 | 11 | Re-exports BoxAndWhiskerChart 12 | 13 | ### BoxAndWhiskerData 14 | 15 | Re-exports BoxAndWhiskerData 16 | 17 | ### Chart 18 | 19 | Re-exports Chart 20 | 21 | ### ChartType 22 | 23 | Re-exports ChartType 24 | 25 | ### ChartTypes 26 | 27 | Re-exports ChartTypes 28 | 29 | ### Context 30 | 31 | Re-exports Context 32 | 33 | ### CreateCodeContextOpts 34 | 35 | Re-exports CreateCodeContextOpts 36 | 37 | ### default 38 | 39 | Renames and re-exports Sandbox 40 | 41 | ### Execution 42 | 43 | Re-exports Execution 44 | 45 | ### ExecutionError 46 | 47 | Re-exports ExecutionError 48 | 49 | ### LineChart 50 | 51 | Re-exports LineChart 52 | 53 | ### Logs 54 | 55 | Re-exports Logs 56 | 57 | ### MIMEType 58 | 59 | Re-exports MIMEType 60 | 61 | ### OutputMessage 62 | 63 | Re-exports OutputMessage 64 | 65 | ### PieChart 66 | 67 | Re-exports PieChart 68 | 69 | ### PieData 70 | 71 | Re-exports PieData 72 | 73 | ### PointData 74 | 75 | Re-exports PointData 76 | 77 | ### RawData 78 | 79 | Re-exports RawData 80 | 81 | ### Result 82 | 83 | Re-exports Result 84 | 85 | ### RunCodeOpts 86 | 87 | Re-exports RunCodeOpts 88 | 89 | ### Sandbox 90 | 91 | Re-exports Sandbox 92 | 93 | ### ScaleType 94 | 95 | Re-exports ScaleType 96 | 97 | ### ScatterChart 98 | 99 | Re-exports ScatterChart 100 | 101 | ### SuperChart 102 | 103 | Re-exports SuperChart 104 | -------------------------------------------------------------------------------- /sdk-reference/code-interpreter-js-sdk/v2.3.0/index/page.mdx: -------------------------------------------------------------------------------- 1 | ### BarChart 2 | 3 | Re-exports BarChart 4 | 5 | ### BarData 6 | 7 | Re-exports BarData 8 | 9 | ### BoxAndWhiskerChart 10 | 11 | Re-exports BoxAndWhiskerChart 12 | 13 | ### BoxAndWhiskerData 14 | 15 | Re-exports BoxAndWhiskerData 16 | 17 | ### Chart 18 | 19 | Re-exports Chart 20 | 21 | ### ChartType 22 | 23 | Re-exports ChartType 24 | 25 | ### ChartTypes 26 | 27 | Re-exports ChartTypes 28 | 29 | ### Context 30 | 31 | Re-exports Context 32 | 33 | ### CreateCodeContextOpts 34 | 35 | Re-exports CreateCodeContextOpts 36 | 37 | ### default 38 | 39 | Renames and re-exports Sandbox 40 | 41 | ### Execution 42 | 43 | Re-exports Execution 44 | 45 | ### ExecutionError 46 | 47 | Re-exports ExecutionError 48 | 49 | ### LineChart 50 | 51 | Re-exports LineChart 52 | 53 | ### Logs 54 | 55 | Re-exports Logs 56 | 57 | ### MIMEType 58 | 59 | Re-exports MIMEType 60 | 61 | ### OutputMessage 62 | 63 | Re-exports OutputMessage 64 | 65 | ### PieChart 66 | 67 | Re-exports PieChart 68 | 69 | ### PieData 70 | 71 | Re-exports PieData 72 | 73 | ### PointData 74 | 75 | Re-exports PointData 76 | 77 | ### RawData 78 | 79 | Re-exports RawData 80 | 81 | ### Result 82 | 83 | Re-exports Result 84 | 85 | ### RunCodeOpts 86 | 87 | Re-exports RunCodeOpts 88 | 89 | ### Sandbox 90 | 91 | Re-exports Sandbox 92 | 93 | ### ScaleType 94 | 95 | Re-exports ScaleType 96 | 97 | ### ScatterChart 98 | 99 | Re-exports ScatterChart 100 | 101 | ### SuperChart 102 | 103 | Re-exports SuperChart 104 | -------------------------------------------------------------------------------- /sdk-reference/code-interpreter-js-sdk/v2.3.1/index/page.mdx: -------------------------------------------------------------------------------- 1 | ### BarChart 2 | 3 | Re-exports BarChart 4 | 5 | ### BarData 6 | 7 | Re-exports BarData 8 | 9 | ### BoxAndWhiskerChart 10 | 11 | Re-exports BoxAndWhiskerChart 12 | 13 | ### BoxAndWhiskerData 14 | 15 | Re-exports BoxAndWhiskerData 16 | 17 | ### Chart 18 | 19 | Re-exports Chart 20 | 21 | ### ChartType 22 | 23 | Re-exports ChartType 24 | 25 | ### ChartTypes 26 | 27 | Re-exports ChartTypes 28 | 29 | ### Context 30 | 31 | Re-exports Context 32 | 33 | ### CreateCodeContextOpts 34 | 35 | Re-exports CreateCodeContextOpts 36 | 37 | ### default 38 | 39 | Renames and re-exports Sandbox 40 | 41 | ### Execution 42 | 43 | Re-exports Execution 44 | 45 | ### ExecutionError 46 | 47 | Re-exports ExecutionError 48 | 49 | ### LineChart 50 | 51 | Re-exports LineChart 52 | 53 | ### Logs 54 | 55 | Re-exports Logs 56 | 57 | ### MIMEType 58 | 59 | Re-exports MIMEType 60 | 61 | ### OutputMessage 62 | 63 | Re-exports OutputMessage 64 | 65 | ### PieChart 66 | 67 | Re-exports PieChart 68 | 69 | ### PieData 70 | 71 | Re-exports PieData 72 | 73 | ### PointData 74 | 75 | Re-exports PointData 76 | 77 | ### RawData 78 | 79 | Re-exports RawData 80 | 81 | ### Result 82 | 83 | Re-exports Result 84 | 85 | ### RunCodeOpts 86 | 87 | Re-exports RunCodeOpts 88 | 89 | ### Sandbox 90 | 91 | Re-exports Sandbox 92 | 93 | ### ScaleType 94 | 95 | Re-exports ScaleType 96 | 97 | ### ScatterChart 98 | 99 | Re-exports ScatterChart 100 | 101 | ### SuperChart 102 | 103 | Re-exports SuperChart 104 | -------------------------------------------------------------------------------- /sdk-reference/code-interpreter-js-sdk/v2.3.2/index/page.mdx: -------------------------------------------------------------------------------- 1 | ### BarChart 2 | 3 | Re-exports BarChart 4 | 5 | ### BarData 6 | 7 | Re-exports BarData 8 | 9 | ### BoxAndWhiskerChart 10 | 11 | Re-exports BoxAndWhiskerChart 12 | 13 | ### BoxAndWhiskerData 14 | 15 | Re-exports BoxAndWhiskerData 16 | 17 | ### Chart 18 | 19 | Re-exports Chart 20 | 21 | ### ChartType 22 | 23 | Re-exports ChartType 24 | 25 | ### ChartTypes 26 | 27 | Re-exports ChartTypes 28 | 29 | ### Context 30 | 31 | Re-exports Context 32 | 33 | ### CreateCodeContextOpts 34 | 35 | Re-exports CreateCodeContextOpts 36 | 37 | ### default 38 | 39 | Renames and re-exports Sandbox 40 | 41 | ### Execution 42 | 43 | Re-exports Execution 44 | 45 | ### ExecutionError 46 | 47 | Re-exports ExecutionError 48 | 49 | ### LineChart 50 | 51 | Re-exports LineChart 52 | 53 | ### Logs 54 | 55 | Re-exports Logs 56 | 57 | ### MIMEType 58 | 59 | Re-exports MIMEType 60 | 61 | ### OutputMessage 62 | 63 | Re-exports OutputMessage 64 | 65 | ### PieChart 66 | 67 | Re-exports PieChart 68 | 69 | ### PieData 70 | 71 | Re-exports PieData 72 | 73 | ### PointData 74 | 75 | Re-exports PointData 76 | 77 | ### RawData 78 | 79 | Re-exports RawData 80 | 81 | ### Result 82 | 83 | Re-exports Result 84 | 85 | ### RunCodeOpts 86 | 87 | Re-exports RunCodeOpts 88 | 89 | ### Sandbox 90 | 91 | Re-exports Sandbox 92 | 93 | ### ScaleType 94 | 95 | Re-exports ScaleType 96 | 97 | ### ScatterChart 98 | 99 | Re-exports ScatterChart 100 | 101 | ### SuperChart 102 | 103 | Re-exports SuperChart 104 | -------------------------------------------------------------------------------- /sdk-reference/code-interpreter-js-sdk/v2.3.3/index/page.mdx: -------------------------------------------------------------------------------- 1 | ### BarChart 2 | 3 | Re-exports BarChart 4 | 5 | ### BarData 6 | 7 | Re-exports BarData 8 | 9 | ### BoxAndWhiskerChart 10 | 11 | Re-exports BoxAndWhiskerChart 12 | 13 | ### BoxAndWhiskerData 14 | 15 | Re-exports BoxAndWhiskerData 16 | 17 | ### Chart 18 | 19 | Re-exports Chart 20 | 21 | ### ChartType 22 | 23 | Re-exports ChartType 24 | 25 | ### ChartTypes 26 | 27 | Re-exports ChartTypes 28 | 29 | ### Context 30 | 31 | Re-exports Context 32 | 33 | ### CreateCodeContextOpts 34 | 35 | Re-exports CreateCodeContextOpts 36 | 37 | ### default 38 | 39 | Renames and re-exports Sandbox 40 | 41 | ### Execution 42 | 43 | Re-exports Execution 44 | 45 | ### ExecutionError 46 | 47 | Re-exports ExecutionError 48 | 49 | ### LineChart 50 | 51 | Re-exports LineChart 52 | 53 | ### Logs 54 | 55 | Re-exports Logs 56 | 57 | ### MIMEType 58 | 59 | Re-exports MIMEType 60 | 61 | ### OutputMessage 62 | 63 | Re-exports OutputMessage 64 | 65 | ### PieChart 66 | 67 | Re-exports PieChart 68 | 69 | ### PieData 70 | 71 | Re-exports PieData 72 | 73 | ### PointData 74 | 75 | Re-exports PointData 76 | 77 | ### RawData 78 | 79 | Re-exports RawData 80 | 81 | ### Result 82 | 83 | Re-exports Result 84 | 85 | ### RunCodeOpts 86 | 87 | Re-exports RunCodeOpts 88 | 89 | ### Sandbox 90 | 91 | Re-exports Sandbox 92 | 93 | ### ScaleType 94 | 95 | Re-exports ScaleType 96 | 97 | ### ScatterChart 98 | 99 | Re-exports ScatterChart 100 | 101 | ### SuperChart 102 | 103 | Re-exports SuperChart 104 | -------------------------------------------------------------------------------- /js/tests/images/bar.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'vitest' 2 | 3 | import { sandboxTest } from '../setup' 4 | 5 | // Skip this test if we are running in debug mode — the pwd and user in the testing docker container are not the same as in the actual sandbox. 6 | sandboxTest('test show image', async ({ sandbox }) => { 7 | const code = ` 8 | import numpy 9 | from PIL import Image 10 | 11 | imarray = numpy.random.rand(16,16,3) * 255 12 | image = Image.fromarray(imarray.astype('uint8')).convert('RGBA') 13 | 14 | image.show() 15 | print("done") 16 | ` 17 | 18 | const execution = await sandbox.runCode(code) 19 | 20 | const image = execution.results[0].png 21 | expect(image).toBeDefined() 22 | }) 23 | 24 | sandboxTest('test image represent', async ({ sandbox }) => { 25 | const code = ` 26 | import numpy 27 | from PIL import Image 28 | 29 | imarray = numpy.random.rand(16,16,3) * 255 30 | image = Image.fromarray(imarray.astype('uint8')).convert('RGBA') 31 | 32 | image 33 | ` 34 | const execution = await sandbox.runCode(code) 35 | 36 | const image = execution.results[0].png 37 | expect(image).toBeDefined() 38 | }) 39 | 40 | sandboxTest('get image on save', async ({ sandbox }) => { 41 | const code = ` 42 | import numpy 43 | from PIL import Image 44 | 45 | imarray = numpy.random.rand(16,16,3) * 255 46 | image = Image.fromarray(imarray.astype('uint8')).convert('RGBA') 47 | 48 | image.save("test.png") 49 | ` 50 | 51 | const execution = await sandbox.runCode(code) 52 | 53 | const image = execution.results[0].png 54 | expect(image).toBeDefined() 55 | }) 56 | -------------------------------------------------------------------------------- /js/tests/charts/bar.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'vitest' 2 | 3 | import { sandboxTest } from '../setup' 4 | 5 | // Skip this test if we are running in debug mode — the pwd and user in the testing docker container are not the same as in the actual sandbox. 6 | sandboxTest('bar', async ({ sandbox }) => { 7 | const code = ` 8 | import matplotlib.pyplot as plt 9 | 10 | # Prepare data 11 | authors = ['Author A', 'Author B', 'Author C', 'Author D'] 12 | sales = [100, 200, 300, 400] 13 | 14 | # Create and customize the bar chart 15 | plt.figure(figsize=(10, 6)) 16 | plt.bar(authors, sales, label='Books Sold', color='blue') 17 | plt.xlabel('Authors') 18 | plt.ylabel('Number of Books Sold') 19 | plt.title('Book Sales by Authors') 20 | 21 | # Display the chart 22 | plt.tight_layout() 23 | plt.show() 24 | ` 25 | const result = await sandbox.runCode(code) 26 | const chart = result.results[0].chart 27 | 28 | expect(chart).toBeDefined() 29 | expect(chart.type).toBe('bar') 30 | expect(chart.title).toBe('Book Sales by Authors') 31 | 32 | expect(chart.x_label).toBe('Authors') 33 | expect(chart.y_label).toBe('Number of Books Sold') 34 | 35 | expect(chart.x_unit).toBeNull() 36 | expect(chart.y_unit).toBeNull() 37 | 38 | const bars = chart.elements 39 | expect(bars.length).toBe(4) 40 | 41 | expect(bars.map((bar) => bar.value)).toEqual([100, 200, 300, 400]) 42 | expect(bars.map((bar) => bar.group)).toEqual([ 43 | 'Books Sold', 44 | 'Books Sold', 45 | 'Books Sold', 46 | 'Books Sold', 47 | ]) 48 | expect(bars.map((bar) => bar.label)).toEqual([ 49 | 'Author A', 50 | 'Author B', 51 | 'Author C', 52 | 'Author D', 53 | ]) 54 | }) 55 | -------------------------------------------------------------------------------- /python/async_example.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | 3 | from dotenv import load_dotenv 4 | 5 | from e2b_code_interpreter import AsyncSandbox 6 | 7 | load_dotenv() 8 | 9 | code = """ 10 | import matplotlib.pyplot as plt 11 | import numpy as np 12 | 13 | # Data for plotting 14 | x = np.linspace(0, 10, 100) 15 | y1 = np.sin(x) 16 | y2 = np.cos(x) 17 | y3 = x**2 18 | y4 = np.sqrt(x) 19 | 20 | # Create a figure with multiple subplots 21 | fig, axs = plt.subplots(2, 2, figsize=(10, 8)) 22 | 23 | # Plotting on the different axes 24 | axs[0, 0].plot(x, y1, 'r') 25 | axs[0, 0].set_title('Sine Wave') 26 | axs[0, 0].grid(True) 27 | 28 | axs[0, 1].plot(x, y2, 'b') 29 | axs[0, 1].set_title('Cosine Wave') 30 | axs[0, 1].grid(True) 31 | 32 | axs[1, 0].plot(x, y3, 'g') 33 | axs[1, 0].set_title('Quadratic Function') 34 | axs[1, 0].grid(True) 35 | 36 | axs[1, 1].plot(x, y4, 'm') 37 | axs[1, 1].set_title('Square Root Function') 38 | axs[1, 1].grid(True) 39 | 40 | # Adjust layout to prevent overlap 41 | plt.tight_layout() 42 | 43 | # Display the figure 44 | plt.show() 45 | """ 46 | 47 | 48 | async def create_sbx(sbx, i: int): 49 | await asyncio.sleep(i * 0.01) 50 | return (await sbx.run_code("os.getenv('TEST')", envs={"TEST": str(i)})).text 51 | 52 | 53 | async def run(): 54 | sbx = await AsyncSandbox.create(debug=True) 55 | result = await sbx.run_code(code) 56 | 57 | print("".join(result.logs.stdout)) 58 | print("".join(result.logs.stderr)) 59 | if result.error: 60 | print(result.error.traceback) 61 | 62 | print(result.results[0].formats()) 63 | print(result.results[0].elements.elements) 64 | 65 | await sbx.kill() 66 | 67 | 68 | asyncio.run(run()) 69 | -------------------------------------------------------------------------------- /python/tests/charts/test_scatter.py: -------------------------------------------------------------------------------- 1 | from e2b_code_interpreter.code_interpreter_async import AsyncSandbox 2 | from e2b_code_interpreter.charts import ScatterChart 3 | 4 | code = """ 5 | import matplotlib.pyplot as plt 6 | import numpy as np 7 | 8 | # Create data 9 | N = 5 10 | x1 = np.random.rand(N) 11 | y1 = np.random.rand(N) 12 | x2 = np.random.rand(2*N) 13 | y2 = np.random.rand(2*N) 14 | 15 | plt.xlabel("A") 16 | plt.ylabel("B") 17 | 18 | plt.scatter(x1, y1, c='blue', label='Dataset 1') 19 | plt.scatter(x2, y2, c='red', label='Dataset 2') 20 | 21 | plt.show() 22 | """ 23 | 24 | 25 | async def test_scatter_chart(async_sandbox: AsyncSandbox): 26 | result = await async_sandbox.run_code(code) 27 | 28 | chart = result.results[0].chart 29 | assert chart 30 | 31 | assert isinstance(chart, ScatterChart) 32 | 33 | assert chart.title is None 34 | assert chart.x_label == "A" 35 | assert chart.y_label == "B" 36 | 37 | assert chart.x_scale == "linear" 38 | assert chart.y_scale == "linear" 39 | 40 | assert all(isinstance(x, float) for x in chart.x_ticks) 41 | assert all(isinstance(y, float) for y in chart.y_ticks) 42 | 43 | assert all(isinstance(x, str) for x in chart.y_tick_labels) 44 | assert all(isinstance(y, str) for y in chart.y_tick_labels) 45 | 46 | assert len(chart.elements) == 2 47 | 48 | first_data = chart.elements[0] 49 | assert first_data.label == "Dataset 1" 50 | assert len(first_data.points) == 5 51 | print(first_data.points) 52 | assert all(isinstance(x, tuple) for x in first_data.points) 53 | 54 | second_data = chart.elements[1] 55 | assert second_data.label == "Dataset 2" 56 | assert len(second_data.points) == 10 57 | assert all(isinstance(x, tuple) for x in second_data.points) 58 | -------------------------------------------------------------------------------- /python/tests/async/test_async_callbacks.py: -------------------------------------------------------------------------------- 1 | from e2b_code_interpreter.code_interpreter_async import AsyncSandbox 2 | 3 | 4 | def async_append_fn(items): 5 | async def async_append(item): 6 | items.append(item) 7 | 8 | return async_append 9 | 10 | 11 | async def test_results(async_sandbox: AsyncSandbox): 12 | results = [] 13 | 14 | execution = await async_sandbox.run_code( 15 | "x = 1;x", on_result=async_append_fn(results) 16 | ) 17 | assert len(results) == 1 18 | assert execution.results[0].text == "1" 19 | 20 | 21 | async def test_results_sync_callback(async_sandbox: AsyncSandbox): 22 | results = [] 23 | 24 | execution = await async_sandbox.run_code( 25 | "x = 1;x", on_result=lambda result: results.append(result) 26 | ) 27 | assert len(results) == 1 28 | assert execution.results[0].text == "1" 29 | 30 | 31 | async def test_error(async_sandbox: AsyncSandbox): 32 | errors = [] 33 | execution = await async_sandbox.run_code("xyz", on_error=async_append_fn(errors)) 34 | assert len(errors) == 1 35 | assert execution.error.name == "NameError" 36 | 37 | 38 | async def test_stdout(async_sandbox: AsyncSandbox): 39 | stdout = [] 40 | execution = await async_sandbox.run_code( 41 | "print('Hello from e2b')", on_stdout=async_append_fn(stdout) 42 | ) 43 | assert len(stdout) == 1 44 | assert execution.logs.stdout == ["Hello from e2b\n"] 45 | 46 | 47 | async def test_stderr(async_sandbox: AsyncSandbox): 48 | stderr = [] 49 | execution = await async_sandbox.run_code( 50 | 'import sys;print("This is an error message", file=sys.stderr)', 51 | on_stderr=async_append_fn(stderr), 52 | ) 53 | assert len(stderr) == 1 54 | assert execution.logs.stderr == ["This is an error message\n"] 55 | -------------------------------------------------------------------------------- /chart_data_extractor/tests/charts/test_scatter.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import numpy as np 3 | 4 | from e2b_charts import chart_figure_to_chart 5 | from e2b_charts.charts import ScatterChart 6 | 7 | 8 | def _prep_chart_figure(): 9 | # Create data 10 | N = 5 11 | x1 = np.random.rand(N) 12 | y1 = np.random.rand(N) 13 | x2 = np.random.rand(2 * N) 14 | y2 = np.random.rand(2 * N) 15 | 16 | plt.figure(figsize=(10, 6)) 17 | 18 | plt.xlabel("A") 19 | plt.ylabel("B") 20 | 21 | plt.scatter(x1, y1, c="blue", label="Dataset 1") 22 | plt.scatter(x2, y2, c="red", label="Dataset 2") 23 | 24 | return plt.gcf() 25 | 26 | 27 | def test_scatter_chart(): 28 | figure = _prep_chart_figure() 29 | chart = chart_figure_to_chart(figure) 30 | assert chart 31 | 32 | assert isinstance(chart, ScatterChart) 33 | 34 | assert chart.title is None 35 | assert chart.x_label == "A" 36 | assert chart.y_label == "B" 37 | 38 | assert chart.x_scale == "linear" 39 | assert chart.y_scale == "linear" 40 | 41 | assert all(isinstance(x, float) for x in chart.x_ticks) 42 | assert all(isinstance(y, float) for y in chart.y_ticks) 43 | 44 | assert all(isinstance(x, str) for x in chart.y_tick_labels) 45 | assert all(isinstance(y, str) for y in chart.y_tick_labels) 46 | 47 | assert len(chart.elements) == 2 48 | 49 | first_data = chart.elements[0] 50 | assert first_data.label == "Dataset 1" 51 | assert len(first_data.points) == 5 52 | print(first_data.points) 53 | assert all(isinstance(x, tuple) for x in first_data.points) 54 | 55 | second_data = chart.elements[1] 56 | assert second_data.label == "Dataset 2" 57 | assert len(second_data.points) == 10 58 | assert all(isinstance(x, tuple) for x in second_data.points) 59 | -------------------------------------------------------------------------------- /js/tests/env_vars/bash.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'vitest' 2 | 3 | import { isDebug, sandboxTest } from '../setup' 4 | import { Sandbox } from '../../src' 5 | 6 | // Bash Env Vars 7 | sandboxTest.skipIf(isDebug)( 8 | 'env vars on sandbox (bash)', 9 | async ({ template }) => { 10 | const sandbox = await Sandbox.create(template, { 11 | envs: { TEST_ENV_VAR: 'supertest' }, 12 | }) 13 | 14 | try { 15 | const result = await sandbox.runCode('echo $TEST_ENV_VAR', { 16 | language: 'bash', 17 | }) 18 | 19 | expect(result.logs.stdout[0]).toEqual('supertest\n') 20 | } finally { 21 | await sandbox.kill() 22 | } 23 | } 24 | ) 25 | 26 | sandboxTest('env vars per execution (bash)', async ({ sandbox }) => { 27 | const result = await sandbox.runCode('echo $FOO', { 28 | envs: { FOO: 'bar' }, 29 | language: 'bash', 30 | }) 31 | 32 | const result_empty = await sandbox.runCode('echo ${FOO:-default}', { 33 | language: 'bash', 34 | }) 35 | 36 | expect(result.logs.stdout[0]).toEqual('bar\n') 37 | expect(result_empty.logs.stdout[0]).toEqual('default\n') 38 | }) 39 | 40 | sandboxTest.skipIf(isDebug)('env vars overwrite', async ({ template }) => { 41 | const sandbox = await Sandbox.create(template, { 42 | envs: { TEST_ENV_VAR: 'supertest' }, 43 | }) 44 | 45 | try { 46 | const result = await sandbox.runCode('echo $TEST_ENV_VAR', { 47 | language: 'bash', 48 | envs: { TEST_ENV_VAR: 'overwrite' }, 49 | }) 50 | 51 | const result_global_default = await sandbox.runCode('echo $TEST_ENV_VAR', { 52 | language: 'bash', 53 | }) 54 | 55 | expect(result.logs.stdout[0]).toEqual('overwrite\n') 56 | expect(result_global_default.logs.stdout[0]).toEqual('supertest\n') 57 | } finally { 58 | await sandbox.kill() 59 | } 60 | }) 61 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: Lint 2 | 3 | on: 4 | pull_request: 5 | 6 | jobs: 7 | lint: 8 | name: Lint 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - name: Checkout Repo 13 | uses: actions/checkout@v4 14 | 15 | - uses: pnpm/action-setup@v4 16 | with: 17 | version: 9.15.5 18 | 19 | - name: Setup Node.js 20 20 | uses: actions/setup-node@v4 21 | with: 22 | node-version: '20.x' 23 | cache: pnpm 24 | 25 | - name: Configure pnpm 26 | run: | 27 | pnpm config set auto-install-peers true 28 | pnpm config set exclude-links-from-lockfile true 29 | 30 | - name: Install dependencies 31 | run: pnpm install --frozen-lockfile 32 | 33 | - name: Set up Python 34 | uses: actions/setup-python@v4 35 | with: 36 | python-version: '3.10' 37 | 38 | - name: Install and configure Poetry 39 | uses: snok/install-poetry@v1 40 | with: 41 | version: 1.5.1 42 | virtualenvs-create: true 43 | virtualenvs-in-project: true 44 | installer-parallel: true 45 | 46 | - name: Install Python dependencies 47 | working-directory: python 48 | run: | 49 | poetry install --with dev 50 | pip install ruff=="0.11.12" 51 | 52 | - name: Run linting 53 | run: | 54 | pnpm run lint 55 | 56 | - name: Run formatting 57 | run: | 58 | pnpm run format 59 | 60 | - name: Check for uncommitted changes 61 | run: | 62 | if [[ -n $(git status --porcelain) ]]; then 63 | echo "❌ Files are not formatted properly:" 64 | git status --short 65 | git diff 66 | exit 1 67 | else 68 | echo "✅ No changes detected." 69 | fi -------------------------------------------------------------------------------- /python/tests/sync/env_vars/test_js.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from e2b_code_interpreter import Sandbox 3 | 4 | 5 | @pytest.mark.skip_debug() 6 | def test_env_vars_on_sandbox(template): 7 | sandbox = Sandbox.create(template=template, envs={"TEST_ENV_VAR": "supertest"}) 8 | try: 9 | result = sandbox.run_code("process.env.TEST_ENV_VAR", language="javascript") 10 | assert result.text is not None 11 | assert result.text.strip() == "supertest" 12 | finally: 13 | sandbox.kill() 14 | 15 | 16 | def test_env_vars_per_execution(sandbox: Sandbox): 17 | try: 18 | result = sandbox.run_code( 19 | "process.env.FOO", envs={"FOO": "bar"}, language="javascript" 20 | ) 21 | 22 | result_empty = sandbox.run_code( 23 | "process.env.FOO || 'default'", language="javascript" 24 | ) 25 | 26 | assert result.text is not None 27 | assert result.text.strip() == "bar" 28 | assert result_empty.text is not None 29 | assert result_empty.text.strip() == "default" 30 | finally: 31 | sandbox.kill() 32 | 33 | 34 | @pytest.mark.skip_debug() 35 | def test_env_vars_overwrite(template): 36 | sandbox = Sandbox.create(template=template, envs={"TEST_ENV_VAR": "supertest"}) 37 | try: 38 | result = sandbox.run_code( 39 | "process.env.TEST_ENV_VAR", 40 | language="javascript", 41 | envs={"TEST_ENV_VAR": "overwrite"}, 42 | ) 43 | result_global_default = sandbox.run_code( 44 | "process.env.TEST_ENV_VAR", language="javascript" 45 | ) 46 | assert result.text is not None 47 | assert result.text.strip() == "overwrite" 48 | assert result_global_default.text is not None 49 | assert result_global_default.text.strip() == "supertest" 50 | finally: 51 | sandbox.kill() 52 | -------------------------------------------------------------------------------- /python/README.md: -------------------------------------------------------------------------------- 1 |

2 | e2b logo 3 |

4 | 5 |

6 | 7 | Last 1 month downloads for the Python SDK 9 | 10 |

11 | 12 | 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. 50 | -------------------------------------------------------------------------------- /python/tests/sync/env_vars/test_java.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from e2b_code_interpreter import Sandbox 3 | 4 | 5 | @pytest.mark.skip_debug() 6 | def test_env_vars_on_sandbox(template): 7 | sandbox = Sandbox.create(template=template, envs={"TEST_ENV_VAR": "supertest"}) 8 | try: 9 | result = sandbox.run_code('System.getProperty("TEST_ENV_VAR")', language="java") 10 | assert result.text is not None 11 | assert result.text.strip() == "supertest" 12 | finally: 13 | sandbox.kill() 14 | 15 | 16 | def test_env_vars_per_execution(sandbox: Sandbox): 17 | try: 18 | result = sandbox.run_code( 19 | 'System.getProperty("FOO")', envs={"FOO": "bar"}, language="java" 20 | ) 21 | 22 | result_empty = sandbox.run_code( 23 | 'System.getProperty("FOO", "default")', language="java" 24 | ) 25 | 26 | assert result.text is not None 27 | assert result.text.strip() == "bar" 28 | assert result_empty.text is not None 29 | assert result_empty.text.strip() == "default" 30 | finally: 31 | sandbox.kill() 32 | 33 | 34 | @pytest.mark.skip_debug() 35 | def test_env_vars_overwrite(template): 36 | sandbox = Sandbox.create(template=template, envs={"TEST_ENV_VAR": "supertest"}) 37 | try: 38 | result = sandbox.run_code( 39 | 'System.getProperty("TEST_ENV_VAR")', 40 | language="java", 41 | envs={"TEST_ENV_VAR": "overwrite"}, 42 | ) 43 | result_global_default = sandbox.run_code( 44 | 'System.getProperty("TEST_ENV_VAR")', language="java" 45 | ) 46 | assert result.text is not None 47 | assert result.text.strip() == "overwrite" 48 | assert result_global_default.text is not None 49 | assert result_global_default.text.strip() == "supertest" 50 | finally: 51 | sandbox.kill() 52 | -------------------------------------------------------------------------------- /js/tests/charts/boxAndWhisker.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'vitest' 2 | 3 | import { sandboxTest } from '../setup' 4 | 5 | sandboxTest('box-and-whisker', async ({ sandbox }) => { 6 | const code = ` 7 | import matplotlib.pyplot as plt 8 | import numpy as np 9 | 10 | # Sample data 11 | data = { 12 | 'Class A': [85, 90, 78, 92, 88], 13 | 'Class B': [95, 89, 76, 91, 84, 87], 14 | 'Class C': [75, 82, 88, 79, 86] 15 | } 16 | 17 | # Create figure and axis 18 | fig, ax = plt.subplots(figsize=(10, 6)) 19 | 20 | # Customize plot 21 | ax.set_title('Exam Scores Distribution') 22 | ax.set_xlabel('Class') 23 | ax.set_ylabel('Score') 24 | 25 | # Set custom colors 26 | ax.boxplot(data.values(), labels=data.keys(), patch_artist=True) 27 | 28 | # Add legend 29 | ax.legend() 30 | 31 | # Adjust layout and show plot 32 | plt.tight_layout() 33 | plt.show() 34 | ` 35 | const result = await sandbox.runCode(code) 36 | const chart = result.results[0].chart 37 | 38 | expect(chart).toBeDefined() 39 | 40 | expect(chart.type).toBe('box_and_whisker') 41 | expect(chart.title).toBe('Exam Scores Distribution') 42 | 43 | expect(chart.x_label).toBe('Class') 44 | expect(chart.y_label).toBe('Score') 45 | 46 | expect(chart.x_unit).toBeNull() 47 | expect(chart.y_unit).toBeNull() 48 | 49 | const bars = chart.elements 50 | expect(bars.length).toBe(3) 51 | 52 | expect(bars.map((bar) => bar.label)).toEqual([ 53 | 'Class A', 54 | 'Class B', 55 | 'Class C', 56 | ]) 57 | expect(bars.map((bar) => bar.outliers)).toEqual([[], [76], []]) 58 | expect(bars.map((bar) => bar.min)).toEqual([78, 84, 75]) 59 | expect(bars.map((bar) => bar.first_quartile)).toEqual([85, 84.75, 79]) 60 | expect(bars.map((bar) => bar.median)).toEqual([88, 88, 82]) 61 | expect(bars.map((bar) => bar.third_quartile)).toEqual([90, 90.5, 86]) 62 | expect(bars.map((bar) => bar.max)).toEqual([92, 95, 88]) 63 | }) 64 | -------------------------------------------------------------------------------- /js/tests/charts/log.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'vitest' 2 | 3 | import { sandboxTest } from '../setup' 4 | 5 | sandboxTest('log', async ({ sandbox }) => { 6 | const code = ` 7 | import numpy as np 8 | import matplotlib.pyplot as plt 9 | 10 | # Generate x values 11 | x = np.linspace(0, 100, 100) 12 | # Calculate y values 13 | y = np.exp(x) 14 | 15 | # Create the plot 16 | plt.figure(figsize=(10, 6)) 17 | plt.plot(x, y, label='y = e^x') 18 | 19 | # Set log scale for the y-axis 20 | plt.yscale('log') 21 | 22 | # Add labels and title 23 | plt.xlabel('X-axis') 24 | plt.ylabel('Y-axis (log scale)') 25 | plt.title('Chart with Log Scale on Y-axis') 26 | 27 | plt.legend() 28 | plt.grid(True) 29 | plt.show() 30 | ` 31 | 32 | const result = await sandbox.runCode(code) 33 | const chart = result.results[0].chart 34 | expect(chart).toBeDefined() 35 | expect(chart.type).toBe('line') 36 | 37 | expect(chart.title).toBe('Chart with Log Scale on Y-axis') 38 | 39 | expect(chart.x_label).toBe('X-axis') 40 | expect(chart.y_label).toBe('Y-axis (log scale)') 41 | 42 | expect(chart.x_unit).toBeNull() 43 | expect(chart.y_unit).toBe('log scale') 44 | 45 | expect(chart.x_scale).toBe('linear') 46 | expect(chart.y_scale).toBe('log') 47 | 48 | expect(chart.x_ticks.every((x) => typeof x === 'number')).toBe(true) 49 | expect(chart.y_ticks.every((y) => typeof y === 'number')).toBe(true) 50 | 51 | expect(chart.x_tick_labels.every((x) => typeof x === 'string')).toBe(true) 52 | expect(chart.y_tick_labels.every((y) => typeof y === 'string')).toBe(true) 53 | 54 | const lines = chart.elements 55 | expect(lines.length).toBe(1) 56 | 57 | const line = lines[0] 58 | expect(line.label).toBe('y = e^x') 59 | expect(line.points.length).toBe(100) 60 | 61 | expect( 62 | line.points.every( 63 | ([x, y]) => typeof x === 'number' && typeof y === 'number' 64 | ) 65 | ).toBe(true) 66 | }) 67 | -------------------------------------------------------------------------------- /python/tests/charts/test_log_chart.py: -------------------------------------------------------------------------------- 1 | from e2b_code_interpreter.code_interpreter_async import AsyncSandbox 2 | from e2b_code_interpreter.charts import LineChart 3 | 4 | # Log chart 5 | code = """ 6 | import numpy as np 7 | import matplotlib.pyplot as plt 8 | 9 | # Generate x values 10 | x = np.linspace(0, 100, 100) 11 | # Calculate y values 12 | y = np.exp(x) 13 | 14 | # Create the plot 15 | plt.figure(figsize=(10, 6)) 16 | plt.plot(x, y, label='y = e^x') 17 | 18 | # Set log scale for the y-axis 19 | plt.yscale('log') 20 | 21 | # Add labels and title 22 | plt.xlabel('X-axis') 23 | plt.ylabel('Y-axis (log scale)') 24 | plt.title('Chart with Log Scale on Y-axis') 25 | 26 | plt.legend() 27 | plt.grid(True) 28 | plt.show() 29 | """ 30 | 31 | 32 | async def test_log_chart(async_sandbox: AsyncSandbox): 33 | result = await async_sandbox.run_code(code) 34 | 35 | chart = result.results[0].chart 36 | assert chart 37 | 38 | assert isinstance(chart, LineChart) 39 | assert chart.title == "Chart with Log Scale on Y-axis" 40 | 41 | assert chart.x_label == "X-axis" 42 | assert chart.y_label == "Y-axis (log scale)" 43 | 44 | assert chart.x_unit is None 45 | assert chart.y_unit == "log scale" 46 | 47 | assert chart.x_scale == "linear" 48 | assert chart.y_scale == "log" 49 | 50 | assert all(isinstance(x, float) for x in chart.x_ticks) 51 | assert all(isinstance(y, float) for y in chart.y_ticks) 52 | 53 | assert all(isinstance(x, str) for x in chart.x_tick_labels) 54 | assert all(isinstance(y, str) for y in chart.y_tick_labels) 55 | 56 | lines = chart.elements 57 | assert len(lines) == 1 58 | 59 | line = lines[0] 60 | assert line.label == "y = e^x" 61 | assert len(line.points) == 100 62 | 63 | assert all(isinstance(x, tuple) for x in line.points) 64 | assert all(isinstance(x, float) and isinstance(y, float) for x, y in line.points) 65 | -------------------------------------------------------------------------------- /chart_data_extractor/tests/charts/test_log_graph.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | 4 | from e2b_charts import chart_figure_to_chart 5 | from e2b_charts.charts import LineChart 6 | 7 | 8 | def _prep_chart_figure(): 9 | # Generate x values 10 | x = np.linspace(0, 100, 100) 11 | # Calculate y values 12 | y = np.exp(x) 13 | 14 | # Create the plot 15 | plt.figure(figsize=(10, 6)) 16 | plt.plot(x, y, label="y = e^x") 17 | 18 | # Set log scale for the y-axis 19 | plt.yscale("log") 20 | 21 | # Add labels and title 22 | plt.xlabel("X-axis") 23 | plt.ylabel("Y-axis (log scale)") 24 | plt.title("Chart with Log Scale on Y-axis") 25 | 26 | plt.legend() 27 | plt.grid(True) 28 | 29 | return plt.gcf() 30 | 31 | 32 | def test_log_chart(): 33 | figure = _prep_chart_figure() 34 | chart = chart_figure_to_chart(figure) 35 | assert chart 36 | 37 | assert isinstance(chart, LineChart) 38 | assert chart.title == "Chart with Log Scale on Y-axis" 39 | 40 | assert chart.x_label == "X-axis" 41 | assert chart.y_label == "Y-axis (log scale)" 42 | 43 | assert chart.x_unit is None 44 | assert chart.y_unit == "log scale" 45 | 46 | assert chart.x_scale == "linear" 47 | assert chart.y_scale == "log" 48 | 49 | assert all(isinstance(x, float) for x in chart.x_ticks) 50 | assert all(isinstance(y, float) for y in chart.y_ticks) 51 | 52 | assert all(isinstance(x, str) for x in chart.x_tick_labels) 53 | assert all(isinstance(y, str) for y in chart.y_tick_labels) 54 | 55 | lines = chart.elements 56 | assert len(lines) == 1 57 | 58 | line = lines[0] 59 | assert line.label == "y = e^x" 60 | assert len(line.points) == 100 61 | 62 | assert all(isinstance(x, tuple) for x in line.points) 63 | assert all(isinstance(x, float) and isinstance(y, float) for x, y in line.points) 64 | -------------------------------------------------------------------------------- /js/README.md: -------------------------------------------------------------------------------- 1 |

2 | e2b logo 3 |

4 | 5 |

6 | 7 | Last 1 month downloads for the JavaScript SDK 9 | 10 |

11 | 12 | 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 | npm i @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 | ```ts 37 | import { Sandbox } from '@e2b/code-interpreter' 38 | 39 | const sbx = await Sandbox.create() 40 | await sbx.runCode('x = 1') 41 | 42 | const execution = await sbx.runCode('x+=1; x') 43 | console.log(execution.text) // outputs 2 44 | ``` 45 | 46 | ### 4. Check docs 47 | Visit [E2B documentation](https://e2b.dev/docs). 48 | 49 | ### 5. E2B cookbook 50 | Visit our [Cookbook](https://github.com/e2b-dev/e2b-cookbook/tree/main) to get inspired by examples with different LLMs and AI frameworks. 51 | -------------------------------------------------------------------------------- /chart_data_extractor/tests/charts/test_box_and_whiskers.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | 3 | from e2b_charts import chart_figure_to_chart 4 | from e2b_charts.charts import BoxAndWhiskerChart, ChartType 5 | 6 | 7 | def _prep_chart_figure(): 8 | # Sample data 9 | data = { 10 | "Class A": [85, 90, 78, 92, 88], 11 | "Class B": [95, 89, 76, 91, 84, 87], 12 | "Class C": [75, 82, 88, 79, 86], 13 | } 14 | 15 | # Create figure and axis 16 | fig, ax = plt.subplots(figsize=(10, 6)) 17 | 18 | # Plot box plot 19 | ax.boxplot(data.values(), tick_labels=data.keys()) 20 | 21 | # Customize plot 22 | ax.set_title("Exam Scores Distribution") 23 | ax.set_xlabel("Class") 24 | ax.set_ylabel("Score") 25 | 26 | # Set custom colors 27 | ax.boxplot(data.values(), tick_labels=data.keys(), patch_artist=True) 28 | 29 | # Adjust layout and show plot 30 | plt.tight_layout() 31 | return plt.gcf() 32 | 33 | 34 | def test_box_and_whiskers(): 35 | figure = _prep_chart_figure() 36 | chart = chart_figure_to_chart(figure) 37 | assert chart 38 | 39 | assert isinstance(chart, BoxAndWhiskerChart) 40 | assert chart.type == ChartType.BOX_AND_WHISKER 41 | assert chart.title == "Exam Scores Distribution" 42 | 43 | assert chart.x_label == "Class" 44 | assert chart.y_label == "Score" 45 | 46 | assert chart.x_unit is None 47 | assert chart.y_unit is None 48 | 49 | bars = chart.elements 50 | assert len(bars) == 3 51 | 52 | assert all(isinstance(bar.min, float) for bar in bars) 53 | assert all(isinstance(bar.first_quartile, float) for bar in bars) 54 | assert all(isinstance(bar.median, float) for bar in bars) 55 | assert all(isinstance(bar.third_quartile, float) for bar in bars) 56 | assert all(isinstance(bar.max, float) for bar in bars) 57 | assert all(isinstance(bar.label, str) for bar in bars) 58 | -------------------------------------------------------------------------------- /python/tests/charts/test_box_and_whiskers.py: -------------------------------------------------------------------------------- 1 | from e2b_code_interpreter.code_interpreter_async import AsyncSandbox 2 | from e2b_code_interpreter.charts import BoxAndWhiskerChart, ChartType 3 | 4 | code = """ 5 | import matplotlib.pyplot as plt 6 | import numpy as np 7 | 8 | # Sample data 9 | data = { 10 | 'Class A': [85, 90, 78, 92, 88], 11 | 'Class B': [95, 89, 76, 91, 84, 87], 12 | 'Class C': [75, 82, 88, 79, 86] 13 | } 14 | 15 | # Create figure and axis 16 | fig, ax = plt.subplots(figsize=(10, 6)) 17 | 18 | # Customize plot 19 | ax.set_title('Exam Scores Distribution') 20 | ax.set_xlabel('Class') 21 | ax.set_ylabel('Score') 22 | 23 | # Set custom colors 24 | ax.boxplot(data.values(), labels=data.keys(), patch_artist=True) 25 | 26 | # Add legend 27 | ax.legend() 28 | 29 | # Adjust layout and show plot 30 | plt.tight_layout() 31 | plt.show() 32 | """ 33 | 34 | 35 | async def test_box_and_whiskers(async_sandbox: AsyncSandbox): 36 | result = await async_sandbox.run_code(code) 37 | 38 | chart = result.results[0].chart 39 | assert chart 40 | 41 | assert isinstance(chart, BoxAndWhiskerChart) 42 | assert chart.type == ChartType.BOX_AND_WHISKER 43 | assert chart.title == "Exam Scores Distribution" 44 | 45 | assert chart.x_label == "Class" 46 | assert chart.y_label == "Score" 47 | 48 | assert chart.x_unit is None 49 | assert chart.y_unit is None 50 | 51 | bars = chart.elements 52 | assert len(bars) == 3 53 | 54 | assert [bar.outliers for bar in bars] == [[], [76], []] 55 | assert [bar.min for bar in bars] == [78, 84, 75] 56 | assert [bar.first_quartile for bar in bars] == [85, 84.75, 79] 57 | assert [bar.median for bar in bars] == [88, 88, 82] 58 | assert [bar.third_quartile for bar in bars] == [90, 90.5, 86] 59 | assert [bar.max for bar in bars] == [92, 95, 88] 60 | assert [bar.label for bar in bars] == ["Class A", "Class B", "Class C"] 61 | -------------------------------------------------------------------------------- /.github/workflows/performance_tests.yml: -------------------------------------------------------------------------------- 1 | name: Performance tests 2 | 3 | on: 4 | workflow_call: 5 | secrets: 6 | E2B_API_KEY: 7 | required: true 8 | inputs: 9 | E2B_DOMAIN: 10 | required: false 11 | type: string 12 | E2B_TESTS_TEMPLATE: 13 | required: false 14 | type: string 15 | E2B_TESTS_BENCHMARK_ITERATIONS_COUNT: 16 | required: false 17 | type: number 18 | default: 20 19 | 20 | permissions: 21 | contents: read 22 | 23 | jobs: 24 | performance-tests: 25 | defaults: 26 | run: 27 | working-directory: ./python 28 | name: Performance tests 29 | runs-on: ubuntu-22.04 30 | steps: 31 | - name: Checkout repository 32 | uses: actions/checkout@v4 33 | 34 | - name: Set up Python 35 | uses: actions/setup-python@v4 36 | with: 37 | python-version: '3.12' 38 | 39 | - name: Install and configure Poetry 40 | uses: snok/install-poetry@v1 41 | with: 42 | version: 1.5.1 43 | virtualenvs-create: true 44 | virtualenvs-in-project: true 45 | installer-parallel: true 46 | 47 | - name: Install dependencies 48 | run: poetry install 49 | 50 | - name: Run performance tests 51 | run: poetry run python tests/performance.py 52 | env: 53 | E2B_API_KEY: ${{ secrets.E2B_API_KEY }} 54 | E2B_DOMAIN: ${{ inputs.E2B_DOMAIN }} 55 | E2B_TESTS_TEMPLATE: ${{ inputs.E2B_TESTS_TEMPLATE }} 56 | E2B_TESTS_BENCHMARK_ITERATIONS_COUNT: ${{ inputs.E2B_TESTS_BENCHMARK_ITERATIONS_COUNT }} 57 | - name: Upload performance plot artifact 58 | uses: actions/upload-artifact@v4 59 | if: always() 60 | with: 61 | name: performance-plot-${{ github.run_number }} 62 | path: ./python/performance_plot.png 63 | retention-days: 30 -------------------------------------------------------------------------------- /python/tests/sync/env_vars/test_python.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from e2b_code_interpreter import Sandbox 3 | 4 | 5 | @pytest.mark.skip_debug() 6 | def test_env_vars_on_sandbox(template): 7 | sandbox = Sandbox.create(template=template, envs={"TEST_ENV_VAR": "supertest"}) 8 | try: 9 | result = sandbox.run_code( 10 | "import os; os.getenv('TEST_ENV_VAR')", language="python" 11 | ) 12 | assert result.text is not None 13 | assert result.text.strip() == "supertest" 14 | finally: 15 | sandbox.kill() 16 | 17 | 18 | def test_env_vars_per_execution(sandbox: Sandbox): 19 | try: 20 | result = sandbox.run_code( 21 | "import os; os.getenv('FOO')", envs={"FOO": "bar"}, language="python" 22 | ) 23 | 24 | result_empty = sandbox.run_code( 25 | "import os; os.getenv('FOO', 'default')", language="python" 26 | ) 27 | 28 | assert result.text is not None 29 | assert result.text.strip() == "bar" 30 | assert result_empty.text is not None 31 | assert result_empty.text.strip() == "default" 32 | finally: 33 | sandbox.kill() 34 | 35 | 36 | @pytest.mark.skip_debug() 37 | def test_env_vars_overwrite(template): 38 | sandbox = Sandbox.create(template=template, envs={"TEST_ENV_VAR": "supertest"}) 39 | try: 40 | result = sandbox.run_code( 41 | "import os; os.getenv('TEST_ENV_VAR')", 42 | language="python", 43 | envs={"TEST_ENV_VAR": "overwrite"}, 44 | ) 45 | result_global_default = sandbox.run_code( 46 | "import os; os.getenv('TEST_ENV_VAR')", language="python" 47 | ) 48 | assert result.text is not None 49 | assert result.text.strip() == "overwrite" 50 | assert result_global_default.text is not None 51 | assert result_global_default.text.strip() == "supertest" 52 | finally: 53 | sandbox.kill() 54 | -------------------------------------------------------------------------------- /js/tests/env_vars/r.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'vitest' 2 | 3 | import { isDebug, sandboxTest } from '../setup' 4 | import { Sandbox } from '../../src' 5 | 6 | // R Env Vars 7 | sandboxTest.skipIf(isDebug)('env vars on sandbox (R)', async ({ template }) => { 8 | const sandbox = await Sandbox.create(template, { 9 | envs: { TEST_ENV_VAR: 'supertest' }, 10 | }) 11 | 12 | try { 13 | const result = await sandbox.runCode('Sys.getenv("TEST_ENV_VAR")', { 14 | language: 'r', 15 | }) 16 | 17 | expect(result.results[0]?.text.trim()).toEqual('[1] "supertest"') 18 | } finally { 19 | await sandbox.kill() 20 | } 21 | }) 22 | 23 | sandboxTest('env vars per execution (R)', async ({ sandbox }) => { 24 | const result = await sandbox.runCode('Sys.getenv("FOO")', { 25 | envs: { FOO: 'bar' }, 26 | language: 'r', 27 | }) 28 | 29 | const result_empty = await sandbox.runCode( 30 | 'Sys.getenv("FOO", unset = "default")', 31 | { 32 | language: 'r', 33 | } 34 | ) 35 | 36 | expect(result.results[0]?.text.trim()).toEqual('[1] "bar"') 37 | expect(result_empty.results[0]?.text.trim()).toEqual('[1] "default"') 38 | }) 39 | 40 | sandboxTest.skipIf(isDebug)('env vars overwrite', async ({ template }) => { 41 | const sandbox = await Sandbox.create(template, { 42 | envs: { TEST_ENV_VAR: 'supertest' }, 43 | }) 44 | 45 | try { 46 | const result = await sandbox.runCode('Sys.getenv("TEST_ENV_VAR")', { 47 | language: 'r', 48 | envs: { TEST_ENV_VAR: 'overwrite' }, 49 | }) 50 | 51 | const result_global_default = await sandbox.runCode( 52 | 'Sys.getenv("TEST_ENV_VAR")', 53 | { 54 | language: 'r', 55 | } 56 | ) 57 | 58 | expect(result.results[0]?.text.trim()).toEqual('[1] "overwrite"') 59 | expect(result_global_default.results[0]?.text.trim()).toEqual( 60 | '[1] "supertest"' 61 | ) 62 | } finally { 63 | await sandbox.kill() 64 | } 65 | }) 66 | -------------------------------------------------------------------------------- /js/tests/charts/superchart.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'vitest' 2 | 3 | import { sandboxTest } from '../setup' 4 | 5 | sandboxTest('superchart', async ({ sandbox }) => { 6 | const code = ` 7 | import matplotlib.pyplot as plt 8 | import numpy as np 9 | 10 | # Data for plotting 11 | x1 = np.linspace(0, 10, 100) 12 | y1 = np.sin(x1) 13 | 14 | # Create a figure with multiple subplots 15 | fig, axs = plt.subplots(1, 2, figsize=(10, 8)) 16 | fig.suptitle('Multiple Charts Example', fontsize=16) 17 | 18 | # Plotting on the different axes 19 | axs[0].plot(x1, y1, 'r') 20 | axs[0].set_title('Sine Wave') 21 | axs[0].grid(True) 22 | 23 | N = 5 24 | x2 = np.random.rand(N) 25 | y2 = np.random.rand(N) 26 | 27 | axs[1].scatter(x2, y2, c='blue', label='Dataset 1') 28 | axs[1].set_xlabel('X') 29 | axs[1].set_ylabel('Y') 30 | axs[1].set_title('Scatter Plot') 31 | axs[1].grid(True) 32 | 33 | plt.show() 34 | ` 35 | const result = await sandbox.runCode(code) 36 | const chart = result.results[0].chart 37 | 38 | expect(chart).toBeDefined() 39 | expect(chart.type).toBe('superchart') 40 | expect(chart.title).toBe('Multiple Charts Example') 41 | 42 | const charts = chart.elements 43 | expect(charts.length).toBe(2) 44 | 45 | const [firstChart, secondChart] = charts 46 | 47 | // Check the first chart (LineChart) 48 | expect(firstChart.title).toBe('Sine Wave') 49 | expect(firstChart.type).toBe('line') 50 | 51 | expect(firstChart.x_label).toBeNull() 52 | expect(firstChart.y_label).toBeNull() 53 | expect(firstChart.elements.length).toBe(1) 54 | expect(firstChart.elements[0].points.length).toBe(100) 55 | 56 | // Check the second chart (ScatterChart) 57 | expect(secondChart.title).toBe('Scatter Plot') 58 | expect(secondChart.type).toBe('scatter') 59 | 60 | expect(secondChart.x_label).toBe('X') 61 | expect(secondChart.y_label).toBe('Y') 62 | expect(secondChart.elements.length).toBe(1) 63 | expect(secondChart.elements[0].points.length).toBe(5) 64 | }) 65 | -------------------------------------------------------------------------------- /js/tests/setup.ts: -------------------------------------------------------------------------------- 1 | import { test as base } from 'vitest' 2 | import { Sandbox, SandboxOpts } from '../src' 3 | 4 | interface SandboxFixture { 5 | sandbox: Sandbox 6 | template: string 7 | sandboxTestId: string 8 | sandboxOpts: Partial 9 | } 10 | 11 | const template = process.env.E2B_TESTS_TEMPLATE || 'code-interpreter-v1' 12 | 13 | export const sandboxTest = base.extend({ 14 | template, 15 | sandboxTestId: [ 16 | // eslint-disable-next-line no-empty-pattern 17 | async ({}, use) => { 18 | const id = `test-${generateRandomString()}` 19 | await use(id) 20 | }, 21 | { auto: true }, 22 | ], 23 | sandboxOpts: {}, 24 | sandbox: [ 25 | async ({ sandboxTestId, sandboxOpts }, use) => { 26 | const sandbox = await Sandbox.create(template, { 27 | metadata: { sandboxTestId }, 28 | ...sandboxOpts, 29 | }) 30 | try { 31 | await use(sandbox) 32 | } finally { 33 | try { 34 | await sandbox.kill() 35 | } catch (err) { 36 | if (!isDebug) { 37 | console.warn( 38 | 'Failed to kill sandbox — this is expected if the test runs with local envd.' 39 | ) 40 | } 41 | } 42 | } 43 | }, 44 | { auto: false }, 45 | ], 46 | }) 47 | 48 | export const isDebug = process.env.E2B_DEBUG !== undefined 49 | export const isIntegrationTest = process.env.E2B_INTEGRATION_TEST !== undefined 50 | 51 | export const secureSandboxTest = sandboxTest.extend({ 52 | sandboxOpts: { 53 | secure: true, 54 | network: { 55 | allowPublicTraffic: false, 56 | }, 57 | }, 58 | }) 59 | 60 | function generateRandomString(length: number = 8): string { 61 | return Math.random() 62 | .toString(36) 63 | .substring(2, length + 2) 64 | } 65 | 66 | export async function wait(ms: number) { 67 | return new Promise((resolve) => setTimeout(resolve, ms)) 68 | } 69 | 70 | export { template } 71 | -------------------------------------------------------------------------------- /js/tests/env_vars/js.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'vitest' 2 | 3 | import { isDebug, sandboxTest } from '../setup' 4 | import { Sandbox } from '../../src' 5 | 6 | // JavaScript Env Vars 7 | sandboxTest.skipIf(isDebug)( 8 | 'env vars on sandbox (javascript)', 9 | async ({ template }) => { 10 | const sandbox = await Sandbox.create(template, { 11 | envs: { TEST_ENV_VAR: 'supertest' }, 12 | }) 13 | 14 | try { 15 | const result = await sandbox.runCode('process.env.TEST_ENV_VAR', { 16 | language: 'javascript', 17 | }) 18 | 19 | expect(result.results[0]?.text.trim()).toEqual('supertest') 20 | } finally { 21 | await sandbox.kill() 22 | } 23 | } 24 | ) 25 | 26 | sandboxTest('env vars per execution (javascript)', async ({ sandbox }) => { 27 | const result = await sandbox.runCode('process.env.FOO', { 28 | envs: { FOO: 'bar' }, 29 | language: 'javascript', 30 | }) 31 | 32 | const result_empty = await sandbox.runCode("process.env.FOO || 'default'", { 33 | language: 'javascript', 34 | }) 35 | 36 | expect(result.results[0]?.text.trim()).toEqual('bar') 37 | expect(result_empty.results[0]?.text.trim()).toEqual('default') 38 | }) 39 | 40 | sandboxTest.skipIf(isDebug)('env vars overwrite', async ({ template }) => { 41 | const sandbox = await Sandbox.create(template, { 42 | envs: { TEST_ENV_VAR: 'supertest' }, 43 | }) 44 | 45 | try { 46 | const result = await sandbox.runCode('process.env.TEST_ENV_VAR', { 47 | language: 'javascript', 48 | envs: { TEST_ENV_VAR: 'overwrite' }, 49 | }) 50 | 51 | const result_global_default = await sandbox.runCode( 52 | 'process.env.TEST_ENV_VAR', 53 | { 54 | language: 'javascript', 55 | } 56 | ) 57 | 58 | expect(result.results[0]?.text.trim()).toEqual('overwrite') 59 | expect(result_global_default.results[0]?.text.trim()).toEqual('supertest') 60 | } finally { 61 | await sandbox.kill() 62 | } 63 | }) 64 | -------------------------------------------------------------------------------- /python/tests/sync/env_vars/test_r.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from e2b_code_interpreter import Sandbox 3 | 4 | 5 | @pytest.mark.skip_debug() 6 | def test_env_vars_on_sandbox(template): 7 | sandbox = Sandbox.create(template=template, envs={"TEST_ENV_VAR": "supertest"}) 8 | try: 9 | result = sandbox.run_code("Sys.getenv('TEST_ENV_VAR')", language="r") 10 | assert result.results[0].text is not None 11 | assert result.results[0].text.strip() == '[1] "supertest"' 12 | finally: 13 | sandbox.kill() 14 | 15 | 16 | def test_env_vars_per_execution(sandbox: Sandbox): 17 | try: 18 | result = sandbox.run_code( 19 | "Sys.getenv('FOO')", envs={"FOO": "bar"}, language="r" 20 | ) 21 | 22 | result_empty = sandbox.run_code( 23 | "Sys.getenv('FOO', unset = 'default')", language="r" 24 | ) 25 | 26 | assert result.results[0].text is not None 27 | assert result.results[0].text.strip() == '[1] "bar"' 28 | assert result_empty.results[0].text is not None 29 | assert result_empty.results[0].text.strip() == '[1] "default"' 30 | finally: 31 | sandbox.kill() 32 | 33 | 34 | @pytest.mark.skip_debug() 35 | def test_env_vars_overwrite(template): 36 | sandbox = Sandbox.create(template=template, envs={"TEST_ENV_VAR": "supertest"}) 37 | try: 38 | result = sandbox.run_code( 39 | "Sys.getenv('TEST_ENV_VAR')", 40 | language="r", 41 | envs={"TEST_ENV_VAR": "overwrite"}, 42 | ) 43 | result_global_default = sandbox.run_code( 44 | "Sys.getenv('TEST_ENV_VAR')", language="r" 45 | ) 46 | assert result.results[0].text is not None 47 | assert result.results[0].text.strip() == '[1] "overwrite"' 48 | assert result_global_default.results[0].text is not None 49 | assert result_global_default.results[0].text.strip() == '[1] "supertest"' 50 | finally: 51 | sandbox.kill() 52 | -------------------------------------------------------------------------------- /.github/workflows/build_test_template.yml: -------------------------------------------------------------------------------- 1 | name: Build Template 2 | 3 | on: 4 | workflow_call: 5 | secrets: 6 | E2B_API_KEY: 7 | required: true 8 | inputs: 9 | E2B_DOMAIN: 10 | required: false 11 | type: string 12 | outputs: 13 | template_id: 14 | description: "The ID of the built template" 15 | value: ${{ jobs.build.outputs.template_id }} 16 | 17 | permissions: 18 | contents: read 19 | 20 | jobs: 21 | build: 22 | name: Build E2B Template 23 | runs-on: ubuntu-latest 24 | outputs: 25 | template_id: ${{ steps.generate-template-id.outputs.template_id }} 26 | steps: 27 | - name: Checkout repository 28 | uses: actions/checkout@v4 29 | 30 | - name: Set package version 31 | working-directory: ./template 32 | run: | 33 | VERSION=$(cat ../chart_data_extractor/pyproject.toml | grep version | cut -d '"' -f 2) 34 | echo "Version: $VERSION" 35 | sed -i "s/e2b_charts/e2b_charts==${VERSION}/g" requirements.txt 36 | 37 | - uses: actions/setup-python@v6 38 | with: 39 | python-version: '3.13' 40 | 41 | - name: Install development dependencies 42 | working-directory: ./template 43 | run: pip install -r requirements-dev.txt 44 | 45 | - name: Generate Template ID 46 | id: generate-template-id 47 | run: | 48 | E2B_TESTS_TEMPLATE=e2b-code-interpreter-ci-$(uuidgen) 49 | echo "Generated Template ID: $E2B_TESTS_TEMPLATE" 50 | echo "template_id=$E2B_TESTS_TEMPLATE" >> $GITHUB_OUTPUT 51 | 52 | - name: Build E2B template 53 | id: build-template 54 | working-directory: ./template 55 | run: | 56 | python build_ci.py 57 | env: 58 | E2B_API_KEY: ${{ secrets.E2B_API_KEY }} 59 | E2B_DOMAIN: ${{ inputs.E2B_DOMAIN }} 60 | E2B_TESTS_TEMPLATE: ${{ steps.generate-template-id.outputs.template_id }} 61 | -------------------------------------------------------------------------------- /python/tests/async/env_vars/test_js.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from e2b_code_interpreter.code_interpreter_async import AsyncSandbox 3 | 4 | 5 | @pytest.mark.skip_debug() 6 | async def test_env_vars_on_sandbox(template): 7 | sandbox = await AsyncSandbox.create( 8 | template=template, envs={"TEST_ENV_VAR": "supertest"} 9 | ) 10 | try: 11 | result = await sandbox.run_code( 12 | "process.env.TEST_ENV_VAR", language="javascript" 13 | ) 14 | assert result.text is not None 15 | assert result.text.strip() == "supertest" 16 | finally: 17 | await sandbox.kill() 18 | 19 | 20 | async def test_env_vars_per_execution(async_sandbox: AsyncSandbox): 21 | result = await async_sandbox.run_code( 22 | "process.env.FOO", envs={"FOO": "bar"}, language="javascript" 23 | ) 24 | 25 | result_empty = await async_sandbox.run_code( 26 | "process.env.FOO || 'default'", language="javascript" 27 | ) 28 | 29 | assert result.text is not None 30 | assert result.text.strip() == "bar" 31 | assert result_empty.text is not None 32 | assert result_empty.text.strip() == "default" 33 | 34 | 35 | @pytest.mark.skip_debug() 36 | async def test_env_vars_overwrite(template): 37 | sandbox = await AsyncSandbox.create( 38 | template=template, envs={"TEST_ENV_VAR": "supertest"} 39 | ) 40 | try: 41 | result = await sandbox.run_code( 42 | "process.env.TEST_ENV_VAR", 43 | language="javascript", 44 | envs={"TEST_ENV_VAR": "overwrite"}, 45 | ) 46 | result_global_default = await sandbox.run_code( 47 | "process.env.TEST_ENV_VAR", language="javascript" 48 | ) 49 | assert result.text is not None 50 | assert result.text.strip() == "overwrite" 51 | assert result_global_default.text is not None 52 | assert result_global_default.text.strip() == "supertest" 53 | finally: 54 | await sandbox.kill() 55 | -------------------------------------------------------------------------------- /python/tests/charts/test_superchart.py: -------------------------------------------------------------------------------- 1 | from e2b_code_interpreter.code_interpreter_async import AsyncSandbox 2 | from e2b_code_interpreter.charts import ChartType, SuperChart, LineChart, ScatterChart 3 | 4 | code = """ 5 | import matplotlib.pyplot as plt 6 | import numpy as np 7 | 8 | # Data for plotting 9 | x1 = np.linspace(0, 10, 100) 10 | y1 = np.sin(x1) 11 | 12 | # Create a figure with multiple subplots 13 | fig, axs = plt.subplots(1, 2, figsize=(10, 8)) 14 | fig.suptitle('Multiple Charts Example', fontsize=16) 15 | 16 | # Plotting on the different axes 17 | axs[0].plot(x1, y1, 'r') 18 | axs[0].set_title('Sine Wave') 19 | axs[0].grid(True) 20 | 21 | N = 5 22 | x2 = np.random.rand(N) 23 | y2 = np.random.rand(N) 24 | 25 | axs[1].scatter(x2, y2, c='blue', label='Dataset 1') 26 | axs[1].set_xlabel('X') 27 | axs[1].set_ylabel('Y') 28 | axs[1].set_title('Scatter Plot') 29 | axs[1].grid(True) 30 | 31 | plt.show() 32 | """ 33 | 34 | 35 | async def test_super_chart(async_sandbox: AsyncSandbox): 36 | result = await async_sandbox.run_code(code) 37 | chart = result.results[0].chart 38 | assert chart 39 | 40 | assert isinstance(chart, SuperChart) 41 | assert chart.type == ChartType.SUPERCHART 42 | assert chart.title == "Multiple Charts Example" 43 | 44 | charts = chart.elements 45 | assert len(charts) == 2 46 | 47 | first_chart = charts[0] 48 | assert first_chart.title == "Sine Wave" 49 | assert isinstance(first_chart, LineChart) 50 | assert first_chart.x_label is None 51 | assert first_chart.y_label is None 52 | assert len(first_chart.elements) == 1 53 | assert len(first_chart.elements[0].points) == 100 54 | 55 | second_chart = charts[1] 56 | assert second_chart.title == "Scatter Plot" 57 | assert isinstance(second_chart, ScatterChart) 58 | assert second_chart.x_label == "X" 59 | assert second_chart.y_label == "Y" 60 | assert len(second_chart.elements) == 1 61 | assert len(second_chart.elements[0].points) == 5 62 | -------------------------------------------------------------------------------- /python/tests/async/env_vars/test_java.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from e2b_code_interpreter.code_interpreter_async import AsyncSandbox 3 | 4 | 5 | @pytest.mark.skip_debug() 6 | async def test_env_vars_on_sandbox(template): 7 | sandbox = await AsyncSandbox.create( 8 | template=template, envs={"TEST_ENV_VAR": "supertest"} 9 | ) 10 | try: 11 | result = await sandbox.run_code( 12 | 'System.getProperty("TEST_ENV_VAR")', language="java" 13 | ) 14 | assert result.text is not None 15 | assert result.text.strip() == "supertest" 16 | finally: 17 | await sandbox.kill() 18 | 19 | 20 | async def test_env_vars_per_execution(async_sandbox: AsyncSandbox): 21 | result = await async_sandbox.run_code( 22 | 'System.getProperty("FOO")', envs={"FOO": "bar"}, language="java" 23 | ) 24 | 25 | result_empty = await async_sandbox.run_code( 26 | 'System.getProperty("FOO", "default")', language="java" 27 | ) 28 | 29 | assert result.text is not None 30 | assert result.text.strip() == "bar" 31 | assert result_empty.text is not None 32 | assert result_empty.text.strip() == "default" 33 | 34 | 35 | @pytest.mark.skip_debug() 36 | async def test_env_vars_overwrite(template): 37 | sandbox = await AsyncSandbox.create( 38 | template=template, envs={"TEST_ENV_VAR": "supertest"} 39 | ) 40 | try: 41 | result = await sandbox.run_code( 42 | 'System.getProperty("TEST_ENV_VAR")', 43 | language="java", 44 | envs={"TEST_ENV_VAR": "overwrite"}, 45 | ) 46 | result_global_default = await sandbox.run_code( 47 | 'System.getProperty("TEST_ENV_VAR")', language="java" 48 | ) 49 | assert result.text is not None 50 | assert result.text.strip() == "overwrite" 51 | assert result_global_default.text is not None 52 | assert result_global_default.text.strip() == "supertest" 53 | finally: 54 | await sandbox.kill() 55 | -------------------------------------------------------------------------------- /.github/workflows/pull_request.yml: -------------------------------------------------------------------------------- 1 | name: Pull Request 2 | 3 | permissions: 4 | contents: read 5 | id-token: write 6 | 7 | concurrency: 8 | group: ${{ github.workflow }}-${{ github.ref }} 9 | cancel-in-progress: true 10 | 11 | on: 12 | pull_request: 13 | branches: 14 | - main 15 | 16 | jobs: 17 | build-template: 18 | uses: ./.github/workflows/build_test_template.yml 19 | secrets: 20 | E2B_API_KEY: ${{ secrets.E2B_API_KEY }} 21 | with: 22 | E2B_DOMAIN: ${{ vars.E2B_DOMAIN }} 23 | js-sdk: 24 | uses: ./.github/workflows/js_tests.yml 25 | needs: build-template 26 | secrets: 27 | E2B_API_KEY: ${{ secrets.E2B_API_KEY }} 28 | with: 29 | E2B_DOMAIN: ${{ vars.E2B_DOMAIN }} 30 | E2B_TESTS_TEMPLATE: ${{ needs.build-template.outputs.template_id }} 31 | python-sdk: 32 | uses: ./.github/workflows/python_tests.yml 33 | needs: build-template 34 | secrets: 35 | E2B_API_KEY: ${{ secrets.E2B_API_KEY }} 36 | with: 37 | E2B_DOMAIN: ${{ vars.E2B_DOMAIN }} 38 | E2B_TESTS_TEMPLATE: ${{ needs.build-template.outputs.template_id }} 39 | performance-tests: 40 | uses: ./.github/workflows/performance_tests.yml 41 | needs: build-template 42 | secrets: 43 | E2B_API_KEY: ${{ secrets.E2B_API_KEY }} 44 | with: 45 | E2B_DOMAIN: ${{ vars.E2B_DOMAIN }} 46 | E2B_TESTS_TEMPLATE: ${{ needs.build-template.outputs.template_id }} 47 | cleanup-build-template: 48 | uses: ./.github/workflows/cleanup_build_template.yml 49 | needs: [build-template, js-sdk, python-sdk, performance-tests] 50 | if: always() && !contains(needs.build-template.result, 'failure') && !contains(needs.build-template.result, 'cancelled') 51 | secrets: 52 | E2B_TESTS_ACCESS_TOKEN: ${{ secrets.E2B_TESTS_ACCESS_TOKEN }} 53 | with: 54 | E2B_DOMAIN: ${{ vars.E2B_DOMAIN }} 55 | E2B_TESTS_TEMPLATE: ${{ needs.build-template.outputs.template_id }} 56 | charts-tests: 57 | uses: ./.github/workflows/charts_tests.yml 58 | -------------------------------------------------------------------------------- /js/tests/charts/scatter.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'vitest' 2 | 3 | import { sandboxTest } from '../setup' 4 | 5 | sandboxTest('scatter', async ({ sandbox }) => { 6 | const code = ` 7 | import matplotlib.pyplot as plt 8 | import numpy as np 9 | 10 | # Create data 11 | N = 5 12 | x1 = np.random.rand(N) 13 | y1 = np.random.rand(N) 14 | x2 = np.random.rand(2*N) 15 | y2 = np.random.rand(2*N) 16 | 17 | plt.xlabel("A") 18 | plt.ylabel("B") 19 | 20 | plt.scatter(x1, y1, c='blue', label='Dataset 1') 21 | plt.scatter(x2, y2, c='red', label='Dataset 2') 22 | 23 | plt.show() 24 | ` 25 | const result = await sandbox.runCode(code) 26 | const chart = result.results[0].chart 27 | 28 | expect(chart).toBeDefined() 29 | expect(chart.type).toBe('scatter') 30 | 31 | expect(chart.title).toBeNull() 32 | expect(chart.x_label).toBe('A') 33 | expect(chart.y_label).toBe('B') 34 | 35 | expect(chart.x_ticks.every((tick: number) => typeof tick === 'number')).toBe( 36 | true 37 | ) 38 | expect(chart.y_ticks.every((tick: number) => typeof tick === 'number')).toBe( 39 | true 40 | ) 41 | 42 | expect( 43 | chart.x_tick_labels.every((label: string) => typeof label === 'string') 44 | ).toBe(true) 45 | expect( 46 | chart.y_tick_labels.every((label: string) => typeof label === 'string') 47 | ).toBe(true) 48 | 49 | expect(chart.elements.length).toBe(2) 50 | 51 | const [firstData, secondData] = chart.elements 52 | 53 | expect(firstData.label).toBe('Dataset 1') 54 | expect(firstData.points.length).toBe(5) 55 | expect( 56 | firstData.points.every( 57 | (point: [number, number]) => 58 | typeof point[0] === 'number' && typeof point[1] === 'number' 59 | ) 60 | ).toBe(true) 61 | 62 | expect(secondData.label).toBe('Dataset 2') 63 | expect(secondData.points.length).toBe(10) 64 | expect( 65 | secondData.points.every( 66 | (point: [number, number]) => 67 | typeof point[0] === 'number' && typeof point[1] === 'number' 68 | ) 69 | ).toBe(true) 70 | }) 71 | -------------------------------------------------------------------------------- /python/tests/async/env_vars/test_python.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from e2b_code_interpreter.code_interpreter_async import AsyncSandbox 3 | 4 | 5 | @pytest.mark.skip_debug() 6 | async def test_env_vars_on_sandbox(template): 7 | sandbox = await AsyncSandbox.create( 8 | template=template, envs={"TEST_ENV_VAR": "supertest"} 9 | ) 10 | try: 11 | result = await sandbox.run_code( 12 | "import os; os.getenv('TEST_ENV_VAR')", language="python" 13 | ) 14 | assert result.text is not None 15 | assert result.text.strip() == "supertest" 16 | finally: 17 | await sandbox.kill() 18 | 19 | 20 | async def test_env_vars_per_execution(async_sandbox: AsyncSandbox): 21 | result = await async_sandbox.run_code( 22 | "import os; os.getenv('FOO')", envs={"FOO": "bar"}, language="python" 23 | ) 24 | 25 | result_empty = await async_sandbox.run_code( 26 | "import os; os.getenv('FOO', 'default')", language="python" 27 | ) 28 | 29 | assert result.text is not None 30 | assert result.text.strip() == "bar" 31 | assert result_empty.text is not None 32 | assert result_empty.text.strip() == "default" 33 | 34 | 35 | @pytest.mark.skip_debug() 36 | async def test_env_vars_overwrite(template): 37 | sandbox = await AsyncSandbox.create( 38 | template=template, envs={"TEST_ENV_VAR": "supertest"} 39 | ) 40 | try: 41 | result = await sandbox.run_code( 42 | "import os; os.getenv('TEST_ENV_VAR')", 43 | language="python", 44 | envs={"TEST_ENV_VAR": "overwrite"}, 45 | ) 46 | result_global_default = await sandbox.run_code( 47 | "import os; os.getenv('TEST_ENV_VAR')", language="python" 48 | ) 49 | assert result.text is not None 50 | assert result.text.strip() == "overwrite" 51 | assert result_global_default.text is not None 52 | assert result_global_default.text.strip() == "supertest" 53 | finally: 54 | await sandbox.kill() 55 | -------------------------------------------------------------------------------- /js/tests/env_vars/java.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'vitest' 2 | 3 | import { isDebug, sandboxTest } from '../setup' 4 | import { Sandbox } from '../../src' 5 | 6 | // Java Env Vars 7 | sandboxTest.skipIf(isDebug)( 8 | 'env vars on sandbox (java)', 9 | async ({ template }) => { 10 | const sandbox = await Sandbox.create(template, { 11 | envs: { TEST_ENV_VAR: 'supertest' }, 12 | }) 13 | 14 | try { 15 | const result = await sandbox.runCode( 16 | 'System.getProperty("TEST_ENV_VAR")', 17 | { 18 | language: 'java', 19 | } 20 | ) 21 | 22 | expect(result.results[0]?.text.trim()).toEqual('supertest') 23 | } finally { 24 | await sandbox.kill() 25 | } 26 | } 27 | ) 28 | 29 | sandboxTest('env vars per execution (java)', async ({ sandbox }) => { 30 | const result = await sandbox.runCode('System.getProperty("FOO")', { 31 | envs: { FOO: 'bar' }, 32 | language: 'java', 33 | }) 34 | 35 | const result_empty = await sandbox.runCode( 36 | 'System.getProperty("FOO", "default")', 37 | { 38 | language: 'java', 39 | } 40 | ) 41 | 42 | expect(result.results[0]?.text.trim()).toEqual('bar') 43 | expect(result_empty.results[0]?.text.trim()).toEqual('default') 44 | }) 45 | 46 | sandboxTest.skipIf(isDebug)('env vars overwrite', async ({ template }) => { 47 | const sandbox = await Sandbox.create(template, { 48 | envs: { TEST_ENV_VAR: 'supertest' }, 49 | }) 50 | 51 | try { 52 | const result = await sandbox.runCode('System.getProperty("TEST_ENV_VAR")', { 53 | language: 'java', 54 | envs: { TEST_ENV_VAR: 'overwrite' }, 55 | }) 56 | 57 | const result_global_default = await sandbox.runCode( 58 | 'System.getProperty("TEST_ENV_VAR")', 59 | { 60 | language: 'java', 61 | } 62 | ) 63 | 64 | expect(result.results[0]?.text.trim()).toEqual('overwrite') 65 | expect(result_global_default.results[0]?.text.trim()).toEqual('supertest') 66 | } finally { 67 | await sandbox.kill() 68 | } 69 | }) 70 | -------------------------------------------------------------------------------- /python/tests/async/env_vars/test_r.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from e2b_code_interpreter.code_interpreter_async import AsyncSandbox 3 | 4 | 5 | @pytest.mark.skip_debug() 6 | async def test_env_vars_on_sandbox(template): 7 | sandbox = await AsyncSandbox.create( 8 | template=template, envs={"TEST_ENV_VAR": "supertest"} 9 | ) 10 | try: 11 | result = await sandbox.run_code('Sys.getenv("TEST_ENV_VAR")', language="r") 12 | assert result.results[0].text is not None 13 | assert result.results[0].text.strip() == '[1] "supertest"' 14 | finally: 15 | await sandbox.kill() 16 | 17 | 18 | async def test_env_vars_per_execution(async_sandbox: AsyncSandbox): 19 | result = await async_sandbox.run_code( 20 | 'Sys.getenv("FOO")', envs={"FOO": "bar"}, language="r" 21 | ) 22 | 23 | result_empty = await async_sandbox.run_code( 24 | 'Sys.getenv("FOO", unset = "default")', language="r" 25 | ) 26 | 27 | assert result.results[0].text is not None 28 | assert result.results[0].text.strip() == '[1] "bar"' 29 | assert result_empty.results[0].text is not None 30 | assert result_empty.results[0].text.strip() == '[1] "default"' 31 | 32 | 33 | @pytest.mark.skip_debug() 34 | async def test_env_vars_overwrite(template): 35 | sandbox = await AsyncSandbox.create( 36 | template=template, envs={"TEST_ENV_VAR": "supertest"} 37 | ) 38 | try: 39 | result = await sandbox.run_code( 40 | 'Sys.getenv("TEST_ENV_VAR")', 41 | language="r", 42 | envs={"TEST_ENV_VAR": "overwrite"}, 43 | ) 44 | result_global_default = await sandbox.run_code( 45 | 'Sys.getenv("TEST_ENV_VAR")', language="r" 46 | ) 47 | assert result.results[0].text is not None 48 | assert result.results[0].text.strip() == '[1] "overwrite"' 49 | assert result_global_default.results[0].text is not None 50 | assert result_global_default.results[0].text.strip() == '[1] "supertest"' 51 | finally: 52 | await sandbox.kill() 53 | -------------------------------------------------------------------------------- /chart_data_extractor/tests/charts/test_supergraph.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import numpy as np 3 | 4 | from e2b_charts import chart_figure_to_chart 5 | from e2b_charts.charts import ( 6 | ChartType, 7 | LineChart, 8 | ScatterChart, 9 | ) 10 | from e2b_charts.main import SuperChart 11 | 12 | 13 | def _prep_chart_figure(): 14 | # Data for plotting 15 | x1 = np.linspace(0, 10, 100) 16 | y1 = np.sin(x1) 17 | 18 | # Create a figure with multiple subplots 19 | fig, axs = plt.subplots(1, 2, figsize=(10, 8)) 20 | fig.suptitle("Multiple Charts Example", fontsize=16) 21 | 22 | # Plotting on the different axes 23 | axs[0].plot(x1, y1, "r") 24 | axs[0].set_title("Sine Wave") 25 | axs[0].grid(True) 26 | 27 | N = 5 28 | x2 = np.random.rand(N) 29 | y2 = np.random.rand(N) 30 | 31 | axs[1].scatter(x2, y2, c="blue", label="Dataset 1") 32 | axs[1].set_xlabel("X") 33 | axs[1].set_ylabel("Y") 34 | axs[1].set_title("Scatter Plot") 35 | axs[1].grid(True) 36 | 37 | return plt.gcf() 38 | 39 | 40 | def test_super_chart(): 41 | figure = _prep_chart_figure() 42 | chart = chart_figure_to_chart(figure) 43 | assert chart 44 | 45 | assert isinstance(chart, SuperChart) 46 | assert chart.type == ChartType.SUPERCHART 47 | assert chart.title == "Multiple Charts Example" 48 | 49 | charts = chart.elements 50 | assert len(charts) == 2 51 | 52 | first_chart = charts[0] 53 | assert first_chart.title == "Sine Wave" 54 | assert isinstance(first_chart, LineChart) 55 | assert first_chart.x_label is None 56 | assert first_chart.y_label is None 57 | assert len(first_chart.elements) == 1 58 | assert len(first_chart.elements[0].points) == 100 59 | 60 | second_chart = charts[1] 61 | assert second_chart.title == "Scatter Plot" 62 | assert isinstance(second_chart, ScatterChart) 63 | assert second_chart.x_label == "X" 64 | assert second_chart.y_label == "Y" 65 | assert len(second_chart.elements) == 1 66 | assert len(second_chart.elements[0].points) == 5 67 | -------------------------------------------------------------------------------- /template/jupyter_server_config.py: -------------------------------------------------------------------------------- 1 | # Configuration file for jupyter-server. 2 | 3 | c = get_config() # noqa 4 | 5 | 6 | # Set the Access-Control-Allow-Origin header 7 | # 8 | # Use '*' to allow any origin to access your server. 9 | # 10 | # Takes precedence over allow_origin_pat. 11 | # Default: '' 12 | c.ServerApp.allow_origin = "*" 13 | 14 | 15 | # Allow requests where the Host header doesn't point to a local server 16 | # 17 | # By default, requests get a 403 forbidden response if the 'Host' header 18 | # shows that the browser thinks it's on a non-local domain. 19 | # Setting this option to True disables this check. 20 | # 21 | # This protects against 'DNS rebinding' attacks, where a remote web server 22 | # serves you a page and then changes its DNS to send later requests to a 23 | # local IP, bypassing same-origin checks. 24 | # 25 | # Local IP addresses (such as 127.0.0.1 and ::1) are allowed as local, 26 | # along with hostnames configured in local_hostnames. 27 | # Default: False 28 | c.ServerApp.allow_remote_access = True 29 | 30 | # Disable cross-site-request-forgery protection 31 | # 32 | # Jupyter server includes protection from cross-site request forgeries, 33 | # requiring API requests to either: 34 | # 35 | # - originate from pages served by this server (validated with XSRF cookie and token), or 36 | # - authenticate with a token 37 | # 38 | # Some anonymous compute resources still desire the ability to run code, 39 | # completely without authentication. 40 | # These services can disable all authentication and security checks, 41 | # with the full knowledge of what that implies. 42 | # Default: False 43 | c.ServerApp.disable_check_xsrf = True 44 | 45 | # Whether to allow the user to run the server as root. 46 | # Default: False 47 | c.ServerApp.allow_root = True 48 | 49 | # (bytes/sec) Maximum rate at which messages can be sent on iopub before they are limited. 50 | # Default: 1000000 51 | c.ServerApp.iopub_data_rate_limit = 1000000000 52 | -------------------------------------------------------------------------------- /js/tests/env_vars/python.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'vitest' 2 | 3 | import { isDebug, sandboxTest } from '../setup' 4 | import { Sandbox } from '../../src' 5 | 6 | // Python Env Vars 7 | sandboxTest.skipIf(isDebug)( 8 | 'env vars on sandbox (python)', 9 | async ({ template }) => { 10 | const sandbox = await Sandbox.create(template, { 11 | envs: { TEST_ENV_VAR: 'supertest' }, 12 | }) 13 | 14 | try { 15 | const result = await sandbox.runCode( 16 | 'import os; os.getenv("TEST_ENV_VAR")', 17 | { 18 | language: 'python', 19 | } 20 | ) 21 | 22 | expect(result.results[0]?.text.trim()).toEqual('supertest') 23 | } finally { 24 | await sandbox.kill() 25 | } 26 | } 27 | ) 28 | 29 | sandboxTest('env vars per execution (python)', async ({ sandbox }) => { 30 | const result = await sandbox.runCode('import os; os.getenv("FOO")', { 31 | envs: { FOO: 'bar' }, 32 | language: 'python', 33 | }) 34 | 35 | const result_empty = await sandbox.runCode( 36 | "import os; os.getenv('FOO', 'default')", 37 | { 38 | language: 'python', 39 | } 40 | ) 41 | 42 | expect(result.results[0]?.text.trim()).toEqual('bar') 43 | expect(result_empty.results[0]?.text.trim()).toEqual('default') 44 | }) 45 | 46 | sandboxTest.skipIf(isDebug)('env vars overwrite', async ({ template }) => { 47 | const sandbox = await Sandbox.create(template, { 48 | envs: { TEST_ENV_VAR: 'supertest' }, 49 | }) 50 | 51 | try { 52 | const result = await sandbox.runCode( 53 | 'import os; os.getenv("TEST_ENV_VAR")', 54 | { 55 | language: 'python', 56 | envs: { TEST_ENV_VAR: 'overwrite' }, 57 | } 58 | ) 59 | 60 | const result_global_default = await sandbox.runCode( 61 | 'import os; os.getenv("TEST_ENV_VAR")', 62 | { 63 | language: 'python', 64 | } 65 | ) 66 | 67 | expect(result.results[0]?.text.trim()).toEqual('overwrite') 68 | expect(result_global_default.results[0]?.text.trim()).toEqual('supertest') 69 | } finally { 70 | await sandbox.kill() 71 | } 72 | }) 73 | -------------------------------------------------------------------------------- /template/server/contexts.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import uuid 3 | from typing import Optional 4 | 5 | from api.models.context import Context 6 | from fastapi.responses import PlainTextResponse 7 | 8 | from consts import JUPYTER_BASE_URL 9 | from errors import ExecutionError 10 | from messaging import ContextWebSocket 11 | 12 | logger = logging.Logger(__name__) 13 | 14 | 15 | def get_kernel_for_language(language: str) -> str: 16 | if language == "typescript": 17 | return "javascript" 18 | 19 | return language 20 | 21 | 22 | def normalize_language(language: Optional[str]) -> str: 23 | if not language: 24 | return "python" 25 | 26 | language = language.lower().strip() 27 | 28 | if language == "js": 29 | return "javascript" 30 | 31 | if language == "ts": 32 | return "typescript" 33 | 34 | return language 35 | 36 | 37 | async def create_context(client, websockets: dict, language: str, cwd: str) -> Context: 38 | data = { 39 | "path": str(uuid.uuid4()), 40 | "kernel": {"name": get_kernel_for_language(language)}, 41 | "type": "notebook", 42 | "name": str(uuid.uuid4()), 43 | } 44 | logger.debug(f"Creating new {language} context") 45 | 46 | response = await client.post(f"{JUPYTER_BASE_URL}/api/sessions", json=data) 47 | 48 | if not response.is_success: 49 | raise Exception( 50 | f"Failed to create context: {response.text}", 51 | ) 52 | 53 | session_data = response.json() 54 | session_id = session_data["id"] 55 | context_id = session_data["kernel"]["id"] 56 | 57 | logger.debug(f"Created context {context_id}") 58 | 59 | ws = ContextWebSocket(context_id, session_id, language, cwd) 60 | await ws.connect() 61 | websockets[context_id] = ws 62 | 63 | logger.info(f"Setting working directory to {cwd}") 64 | try: 65 | await ws.change_current_directory(cwd, language) 66 | except ExecutionError: 67 | return PlainTextResponse( 68 | "Failed to set working directory", 69 | status_code=500, 70 | ) 71 | 72 | return Context(language=language, id=context_id, cwd=cwd) 73 | -------------------------------------------------------------------------------- /js/scripts/CustomMarkdownTheme.js: -------------------------------------------------------------------------------- 1 | const { MarkdownTheme, MarkdownPageEvent } = require('typedoc-plugin-markdown') 2 | 3 | function load(app) { 4 | // Listen to the render event 5 | app.renderer.on(MarkdownPageEvent.END, (page) => { 6 | // Remove Markdown links from the document contents 7 | page.contents = removeMarkdownLinks( 8 | removeFirstNLines( 9 | convertH5toH3(removeLinesWithConditions(page.contents)), 10 | 6 11 | ) 12 | ) 13 | }) 14 | } 15 | 16 | // this is a hacky way to make methods in the js-sdk sdk reference look more prominent 17 | function convertH5toH3(text) { 18 | return text.replace(/^##### (.*)$/gm, '### $1') 19 | } 20 | 21 | // Function to remove Markdown-style links 22 | function removeMarkdownLinks(text) { 23 | // Regular expression to match Markdown links [text](url) 24 | return text.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '$1') // Replace with just the link text 25 | } 26 | 27 | function removeFirstNLines(text, n, condition) { 28 | // Split the text into lines, then join back excluding the first four lines 29 | return text.split('\n').slice(n).join('\n') 30 | } 31 | 32 | // Function to remove lines based on conditions 33 | function removeLinesWithConditions(text) { 34 | const lines = text.split('\n') 35 | const filteredLines = [] 36 | 37 | for (let i = 0; i < lines.length; i++) { 38 | // Check if the current line starts with "#### Extends" or "###### Overrides" 39 | if ( 40 | lines[i].startsWith('#### Extends') || 41 | lines[i].startsWith('###### Overrides') || 42 | lines[i].startsWith('###### Inherited from') 43 | ) { 44 | // If it does, skip this line and the next three lines 45 | i += 3 // Skip this line and the next three 46 | continue 47 | } 48 | 49 | if (lines[i].startsWith('##### new')) { 50 | // avoid promoting constructors 51 | i += 1 52 | continue 53 | } 54 | 55 | // If not removed, add the line to filteredLines 56 | filteredLines.push(convertH5toH3(lines[i])) 57 | } 58 | 59 | // Join the filtered lines back into a single string 60 | return filteredLines.join('\n') 61 | } 62 | 63 | // Export the load function 64 | module.exports = { load } 65 | -------------------------------------------------------------------------------- /chart_data_extractor/e2b_charts/charts/base.py: -------------------------------------------------------------------------------- 1 | import enum 2 | import re 3 | from typing import Optional, List, Any 4 | 5 | from matplotlib.axes import Axes 6 | from pydantic import BaseModel, Field 7 | 8 | 9 | class ChartType(str, enum.Enum): 10 | LINE = "line" 11 | SCATTER = "scatter" 12 | BAR = "bar" 13 | PIE = "pie" 14 | BOX_AND_WHISKER = "box_and_whisker" 15 | SUPERCHART = "superchart" 16 | UNKNOWN = "unknown" 17 | 18 | 19 | class Chart(BaseModel): 20 | type: ChartType 21 | title: Optional[str] = None 22 | 23 | elements: List[Any] = Field(default_factory=list) 24 | 25 | def __init__(self, ax: Optional[Axes] = None, **kwargs): 26 | super().__init__(**kwargs) 27 | if ax: 28 | self._extract_info(ax) 29 | 30 | def _extract_info(self, ax: Axes) -> None: 31 | """ 32 | Function to extract information for Chart 33 | """ 34 | title = ax.get_title() 35 | if title == "": 36 | title = None 37 | 38 | self.title = title 39 | 40 | 41 | class Chart2D(Chart): 42 | x_label: Optional[str] = None 43 | y_label: Optional[str] = None 44 | x_unit: Optional[str] = None 45 | y_unit: Optional[str] = None 46 | 47 | def _extract_info(self, ax: Axes) -> None: 48 | """ 49 | Function to extract information for Chart2D 50 | """ 51 | super()._extract_info(ax) 52 | x_label = ax.get_xlabel() 53 | if x_label == "": 54 | x_label = None 55 | self.x_label = x_label 56 | 57 | y_label = ax.get_ylabel() 58 | if y_label == "": 59 | y_label = None 60 | self.y_label = y_label 61 | 62 | regex = r"\s\((.*?)\)|\[(.*?)\]" 63 | if self.x_label: 64 | match = re.search(regex, self.x_label) 65 | if match: 66 | self.x_unit = match.group(1) or match.group(2) 67 | 68 | if self.y_label: 69 | match = re.search(regex, self.y_label) 70 | if match: 71 | self.y_unit = match.group(1) or match.group(2) 72 | 73 | def _change_orientation(self): 74 | self.x_label, self.y_label = self.y_label, self.x_label 75 | self.x_unit, self.y_unit = self.y_unit, self.x_unit 76 | -------------------------------------------------------------------------------- /js/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@e2b/code-interpreter", 3 | "version": "2.3.3", 4 | "packageManager": "pnpm@9.15.5", 5 | "description": "E2B Code Interpreter - Stateful code execution", 6 | "homepage": "https://e2b.dev", 7 | "license": "MIT", 8 | "author": { 9 | "name": "FoundryLabs, Inc.", 10 | "email": "hello@e2b.dev", 11 | "url": "https://e2b.dev" 12 | }, 13 | "bugs": "https://github.com/e2b-dev/code-interpreter/issues", 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/e2b-dev/code-interpreter", 17 | "directory": "js" 18 | }, 19 | "publishConfig": { 20 | "access": "public" 21 | }, 22 | "sideEffects": false, 23 | "main": "dist/index.js", 24 | "module": "dist/index.mjs", 25 | "types": "dist/index.d.ts", 26 | "scripts": { 27 | "prepublishOnly": "pnpm build", 28 | "build": "tsc --noEmit && tsup", 29 | "dev": "tsup --watch", 30 | "test": "vitest run", 31 | "test:coverage": "vitest run --coverage", 32 | "check-deps": "knip", 33 | "update-deps": "ncu -u && pnpm i", 34 | "example": "npx tsx example.mts", 35 | "test:bun": "bun test tests/runtimes/bun --env-file=.env", 36 | "test:deno": "deno test tests/runtimes/deno/ --allow-net --allow-read --allow-env --unstable-sloppy-imports --trace-leaks", 37 | "generate-ref": "./scripts/generate_sdk_ref.sh", 38 | "lint": "eslint src/ tests/", 39 | "format": "prettier --write src/ tests/ example.mts" 40 | }, 41 | "devDependencies": { 42 | "@types/node": "^20.19.19", 43 | "dotenv": "^16.4.5", 44 | "knip": "^5.25.1", 45 | "npm-check-updates": "^17.1.14", 46 | "tsup": "^8.5.1", 47 | "typedoc": "0.26.8", 48 | "typedoc-plugin-markdown": "4.2.7", 49 | "typescript": "^5.5.3", 50 | "vitest": "^3.2.4" 51 | }, 52 | "files": [ 53 | "dist", 54 | "README.md", 55 | "package.json" 56 | ], 57 | "keywords": [ 58 | "e2b", 59 | "ai-agents", 60 | "agents", 61 | "ai", 62 | "code-interpreter", 63 | "stateful-sandbox", 64 | "stateful-serverrless", 65 | "sandbox", 66 | "code", 67 | "runtime", 68 | "vm" 69 | ], 70 | "engines": { 71 | "node": ">=20" 72 | }, 73 | "browserslist": [ 74 | "defaults" 75 | ], 76 | "dependencies": { 77 | "e2b": "^2.8.4" 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /.github/workflows/js_tests.yml: -------------------------------------------------------------------------------- 1 | name: Test JS SDK 2 | 3 | on: 4 | workflow_call: 5 | secrets: 6 | E2B_API_KEY: 7 | required: true 8 | inputs: 9 | E2B_DOMAIN: 10 | required: false 11 | type: string 12 | E2B_TESTS_TEMPLATE: 13 | required: false 14 | type: string 15 | 16 | permissions: 17 | contents: read 18 | 19 | jobs: 20 | test: 21 | defaults: 22 | run: 23 | working-directory: ./js 24 | name: JS SDK - Build and test 25 | runs-on: ubuntu-22.04 26 | steps: 27 | - name: Checkout repository 28 | uses: actions/checkout@v4 29 | 30 | - name: Install pnpm 31 | uses: pnpm/action-setup@v3 32 | id: pnpm-install 33 | with: 34 | version: 9.5 35 | 36 | - name: Setup Node 37 | uses: actions/setup-node@v3 38 | with: 39 | node-version: "20.x" 40 | registry-url: "https://registry.npmjs.org" 41 | cache: pnpm 42 | cache-dependency-path: pnpm-lock.yaml 43 | 44 | - name: Configure pnpm 45 | run: | 46 | pnpm config set auto-install-peers true 47 | pnpm config set exclude-links-from-lockfile true 48 | 49 | - name: Install dependencies 50 | run: pnpm install --frozen-lockfile 51 | 52 | - name: Test build 53 | run: pnpm build 54 | 55 | - name: Run Node tests 56 | run: pnpm test 57 | env: 58 | E2B_API_KEY: ${{ secrets.E2B_API_KEY }} 59 | E2B_DOMAIN: ${{ vars.E2B_DOMAIN }} 60 | E2B_TESTS_TEMPLATE: ${{ inputs.E2B_TESTS_TEMPLATE }} 61 | 62 | - name: Install Bun 63 | uses: oven-sh/setup-bun@v2 64 | with: 65 | bun-version: 1.2.15 66 | 67 | - name: Run Bun tests 68 | run: pnpm test:bun 69 | env: 70 | E2B_API_KEY: ${{ secrets.E2B_API_KEY }} 71 | E2B_DOMAIN: ${{ vars.E2B_DOMAIN }} 72 | E2B_TESTS_TEMPLATE: ${{ inputs.E2B_TESTS_TEMPLATE }} 73 | 74 | - name: Install Deno 75 | uses: denoland/setup-deno@v2 76 | with: 77 | deno-version: v2.x 78 | 79 | - name: Run Deno tests 80 | run: pnpm test:deno 81 | env: 82 | E2B_API_KEY: ${{ secrets.E2B_API_KEY }} 83 | E2B_DOMAIN: ${{ vars.E2B_DOMAIN }} 84 | E2B_TESTS_TEMPLATE: ${{ inputs.E2B_TESTS_TEMPLATE }} 85 | -------------------------------------------------------------------------------- /chart_data_extractor/tests/charts/test_line.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | import datetime 4 | 5 | from e2b_charts import chart_figure_to_chart 6 | from e2b_charts.charts import LineChart 7 | 8 | 9 | def _prep_chart_figure(): 10 | # Generate x values 11 | dates = [ 12 | datetime.date(2023, 9, 1) + datetime.timedelta(seconds=i) for i in range(100) 13 | ] 14 | 15 | x = np.linspace(0, 2 * np.pi, 100) 16 | # Calculate y values 17 | y_sin = np.sin(x) 18 | y_cos = np.cos(x) 19 | 20 | # Create the plot 21 | plt.figure(figsize=(10, 6)) 22 | plt.plot(dates, y_sin, label="sin(x)") 23 | plt.plot(dates, y_cos, label="cos(x)") 24 | 25 | # Add labels and title 26 | plt.xlabel("Time (s)") 27 | plt.ylabel("Amplitude (Hz)") 28 | plt.title("Plot of sin(x) and cos(x)") 29 | 30 | return plt.gcf() 31 | 32 | 33 | def test_line_chart(): 34 | figure = _prep_chart_figure() 35 | chart = chart_figure_to_chart(figure) 36 | assert chart 37 | 38 | assert isinstance(chart, LineChart) 39 | assert chart.title == "Plot of sin(x) and cos(x)" 40 | 41 | assert chart.x_label == "Time (s)" 42 | assert chart.y_label == "Amplitude (Hz)" 43 | 44 | assert chart.x_unit == "s" 45 | assert chart.y_unit == "Hz" 46 | 47 | assert chart.x_scale == "datetime" 48 | assert chart.y_scale == "linear" 49 | 50 | assert all(isinstance(x, str) for x in chart.x_ticks) 51 | parsed_date = datetime.datetime.fromisoformat(chart.x_ticks[0]) 52 | assert isinstance(parsed_date, datetime.datetime) 53 | assert all(isinstance(y, float) for y in chart.y_ticks) 54 | 55 | assert all(isinstance(x, str) for x in chart.y_tick_labels) 56 | assert all(isinstance(y, str) for y in chart.y_tick_labels) 57 | 58 | lines = chart.elements 59 | assert len(lines) == 2 60 | 61 | first_line = lines[0] 62 | assert first_line.label == "sin(x)" 63 | assert len(first_line.points) == 100 64 | assert all(isinstance(point, tuple) for point in first_line.points) 65 | assert all( 66 | isinstance(x, str) and isinstance(y, float) for x, y in first_line.points 67 | ) 68 | 69 | parsed_date = datetime.datetime.fromisoformat(first_line.points[0][0]) 70 | assert isinstance(parsed_date, datetime.datetime) 71 | 72 | second_line = lines[1] 73 | assert second_line.label == "cos(x)" 74 | assert len(second_line.points) == 100 75 | -------------------------------------------------------------------------------- /python/tests/charts/test_line.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | 3 | from e2b_code_interpreter.code_interpreter_async import AsyncSandbox 4 | from e2b_code_interpreter.charts import LineChart 5 | 6 | code = """ 7 | import numpy as np 8 | import matplotlib.pyplot as plt 9 | import datetime 10 | 11 | # Generate x values 12 | dates = [datetime.date(2023, 9, 1) + datetime.timedelta(seconds=i) for i in range(100)] 13 | 14 | x = np.linspace(0, 2*np.pi, 100) 15 | # Calculate y values 16 | y_sin = np.sin(x) 17 | y_cos = np.cos(x) 18 | 19 | # Create the plot 20 | plt.figure(figsize=(10, 6)) 21 | plt.plot(dates, y_sin, label='sin(x)') 22 | plt.plot(dates, y_cos, label='cos(x)') 23 | 24 | # Add labels and title 25 | plt.xlabel("Time (s)") 26 | plt.ylabel("Amplitude (Hz)") 27 | plt.title('Plot of sin(x) and cos(x)') 28 | 29 | # Display the plot 30 | plt.show() 31 | """ 32 | 33 | 34 | async def test_line_chart(async_sandbox: AsyncSandbox): 35 | result = await async_sandbox.run_code(code) 36 | 37 | chart = result.results[0].chart 38 | assert chart 39 | 40 | assert isinstance(chart, LineChart) 41 | assert chart.title == "Plot of sin(x) and cos(x)" 42 | 43 | assert chart.x_label == "Time (s)" 44 | assert chart.y_label == "Amplitude (Hz)" 45 | 46 | assert chart.x_unit == "s" 47 | assert chart.y_unit == "Hz" 48 | 49 | assert chart.x_scale == "datetime" 50 | assert chart.y_scale == "linear" 51 | 52 | assert all(isinstance(x, str) for x in chart.x_ticks) 53 | parsed_date = datetime.datetime.fromisoformat(chart.x_ticks[0]) 54 | assert isinstance(parsed_date, datetime.datetime) 55 | assert all(isinstance(y, float) for y in chart.y_ticks) 56 | 57 | assert all(isinstance(x, str) for x in chart.y_tick_labels) 58 | assert all(isinstance(y, str) for y in chart.y_tick_labels) 59 | 60 | lines = chart.elements 61 | assert len(lines) == 2 62 | 63 | first_line = lines[0] 64 | assert first_line.label == "sin(x)" 65 | assert len(first_line.points) == 100 66 | assert all(isinstance(point, tuple) for point in first_line.points) 67 | assert all( 68 | isinstance(x, str) and isinstance(y, float) for x, y in first_line.points 69 | ) 70 | 71 | parsed_date = datetime.datetime.fromisoformat(first_line.points[0][0]) 72 | assert isinstance(parsed_date, datetime.datetime) 73 | 74 | second_line = lines[1] 75 | assert second_line.label == "cos(x)" 76 | assert len(second_line.points) == 100 77 | -------------------------------------------------------------------------------- /python/tests/conftest.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import os 3 | 4 | import pytest 5 | 6 | from e2b_code_interpreter import ( 7 | AsyncSandbox, 8 | Sandbox, 9 | ) 10 | import uuid 11 | 12 | 13 | @pytest.fixture(scope="session") 14 | def sandbox_test_id(): 15 | return f"test_{uuid.uuid4()}" 16 | 17 | 18 | @pytest.fixture() 19 | def template(): 20 | return os.getenv("E2B_TESTS_TEMPLATE") or "code-interpreter-v1" 21 | 22 | 23 | @pytest.fixture() 24 | def sandbox_factory(request, template, sandbox_test_id): 25 | def factory(*, template_name: str = template, **kwargs): 26 | kwargs.setdefault("secure", False) 27 | kwargs.setdefault("timeout", 60) 28 | 29 | metadata = kwargs.setdefault("metadata", dict()) 30 | metadata.setdefault("sandbox_test_id", sandbox_test_id) 31 | 32 | sandbox = Sandbox.create(template_name, **kwargs) 33 | 34 | request.addfinalizer(lambda: sandbox.kill()) 35 | 36 | return sandbox 37 | 38 | return factory 39 | 40 | 41 | @pytest.fixture() 42 | def sandbox(sandbox_factory): 43 | return sandbox_factory() 44 | 45 | 46 | # override the event loop so it never closes 47 | # this helps us with the global-scoped async http transport 48 | @pytest.fixture(scope="session") 49 | def event_loop(): 50 | try: 51 | loop = asyncio.get_running_loop() 52 | except RuntimeError: 53 | loop = asyncio.new_event_loop() 54 | yield loop 55 | loop.close() 56 | 57 | 58 | @pytest.fixture 59 | def async_sandbox_factory(request, template, sandbox_test_id, event_loop): 60 | async def factory(*, template_name: str = template, **kwargs): 61 | kwargs.setdefault("timeout", 60) 62 | 63 | metadata = kwargs.setdefault("metadata", dict()) 64 | metadata.setdefault("sandbox_test_id", sandbox_test_id) 65 | 66 | sandbox = await AsyncSandbox.create(template_name, **kwargs) 67 | 68 | def kill(): 69 | async def _kill(): 70 | await sandbox.kill() 71 | 72 | event_loop.run_until_complete(_kill()) 73 | 74 | request.addfinalizer(kill) 75 | 76 | return sandbox 77 | 78 | return factory 79 | 80 | 81 | @pytest.fixture 82 | async def async_sandbox(async_sandbox_factory): 83 | return await async_sandbox_factory() 84 | 85 | 86 | @pytest.fixture 87 | def debug(): 88 | return os.getenv("E2B_DEBUG") is not None 89 | 90 | 91 | @pytest.fixture(autouse=True) 92 | def skip_by_debug(request, debug): 93 | if request.node.get_closest_marker("skip_debug"): 94 | if debug: 95 | pytest.skip("skipped because E2B_DEBUG is set") 96 | -------------------------------------------------------------------------------- /js/tests/charts/line.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'vitest' 2 | 3 | import { sandboxTest } from '../setup' 4 | 5 | sandboxTest('line', async ({ sandbox }) => { 6 | const code = ` 7 | import numpy as np 8 | import matplotlib.pyplot as plt 9 | import datetime 10 | 11 | # Generate x values 12 | dates = [datetime.date(2023, 9, 1) + datetime.timedelta(seconds=i) for i in range(100)] 13 | 14 | x = np.linspace(0, 2*np.pi, 100) 15 | # Calculate y values 16 | y_sin = np.sin(x) 17 | y_cos = np.cos(x) 18 | 19 | # Create the plot 20 | plt.figure(figsize=(10, 6)) 21 | plt.plot(dates, y_sin, label='sin(x)') 22 | plt.plot(dates, y_cos, label='cos(x)') 23 | 24 | # Add labels and title 25 | plt.xlabel("Time (s)") 26 | plt.ylabel("Amplitude (Hz)") 27 | plt.title('Plot of sin(x) and cos(x)') 28 | 29 | # Display the plot 30 | plt.show() 31 | ` 32 | const result = await sandbox.runCode(code) 33 | const chart = result.results[0].chart 34 | 35 | expect(chart).toBeDefined() 36 | expect(chart.type).toBe('line') 37 | 38 | expect(chart.title).toBe('Plot of sin(x) and cos(x)') 39 | expect(chart.x_label).toBe('Time (s)') 40 | expect(chart.y_label).toBe('Amplitude (Hz)') 41 | 42 | expect(chart.x_scale).toBe('datetime') 43 | expect(chart.y_scale).toBe('linear') 44 | 45 | expect(chart.x_unit).toBe('s') 46 | expect(chart.y_unit).toBe('Hz') 47 | 48 | expect(chart.x_ticks.every((tick: number) => typeof tick === 'string')).toBe( 49 | true 50 | ) 51 | expect(new Date(chart.x_ticks[0])).toBeInstanceOf(Date) 52 | expect(chart.y_ticks.every((tick: number) => typeof tick === 'number')).toBe( 53 | true 54 | ) 55 | 56 | expect( 57 | chart.y_tick_labels.every((label: string) => typeof label === 'string') 58 | ).toBe(true) 59 | expect( 60 | chart.x_tick_labels.every((label: string) => typeof label === 'string') 61 | ).toBe(true) 62 | 63 | const lines = chart.elements 64 | expect(lines.length).toBe(2) 65 | 66 | const [firstLine, secondLine] = lines 67 | 68 | expect(firstLine.label).toBe('sin(x)') 69 | expect(firstLine.points.length).toBe(100) 70 | expect( 71 | firstLine.points.every( 72 | (point: [number, number]) => 73 | typeof point[0] === 'string' && typeof point[1] === 'number' 74 | ) 75 | ).toBe(true) 76 | expect(new Date(firstLine.points[0][0])).toEqual( 77 | new Date('2023-09-01T00:00:00.000Z') 78 | ) 79 | 80 | expect(secondLine.label).toBe('cos(x)') 81 | expect(secondLine.points.length).toBe(100) 82 | expect( 83 | secondLine.points.every( 84 | (point: [number, number]) => 85 | typeof point[0] === 'string' && typeof point[1] === 'number' 86 | ) 87 | ).toBe(true) 88 | }) 89 | --------------------------------------------------------------------------------