├── .changeset ├── README.md └── config.json ├── .github ├── scripts │ ├── is_new_sdk_ref.sh │ ├── is_release.sh │ └── is_release_for_package.sh └── workflows │ ├── charts_tests.yml │ ├── js_tests.yml │ ├── pull_request.yml │ ├── python_tests.yml │ ├── release.yml │ └── release_candidates.yml ├── .gitignore ├── .npmrc ├── .prettierignore ├── .prettierrc ├── CODEOWNERS ├── LICENSE ├── Makefile ├── README.md ├── chart_data_extractor ├── README.md ├── e2b_charts │ ├── __init__.py │ ├── charts │ │ ├── __init__.py │ │ ├── bars.py │ │ ├── base.py │ │ ├── pie.py │ │ └── planar.py │ ├── main.py │ └── utils │ │ ├── __init__.py │ │ ├── filtering.py │ │ └── rounding.py ├── package.json ├── poetry.lock ├── pyproject.toml └── tests │ ├── charts │ ├── test_bar.py │ ├── test_blank.py │ ├── test_box_and_whiskers.py │ ├── test_categorical_scale.py │ ├── test_datetime_scale.py │ ├── test_line.py │ ├── test_log_graph.py │ ├── test_pie.py │ ├── test_scatter.py │ ├── test_supergraph.py │ └── test_unknown.py │ └── utils │ ├── test_detect_scale.py │ └── test_is_grid_line.py ├── js ├── .gitignore ├── README.md ├── example.mts ├── package.json ├── scripts │ ├── CustomMarkdownTheme.js │ └── generate_sdk_ref.sh ├── src │ ├── charts.ts │ ├── consts.ts │ ├── index.ts │ ├── messaging.ts │ ├── sandbox.ts │ └── utils.ts ├── tests │ ├── bash.test.ts │ ├── basic.test.ts │ ├── benchmarking.js │ ├── callbacks.test.ts │ ├── charts │ │ ├── bar.test.ts │ │ ├── boxAndWhisker.test.ts │ │ ├── line.test.ts │ │ ├── log.test.ts │ │ ├── pie.test.ts │ │ ├── scales.test.ts │ │ ├── scatter.test.ts │ │ ├── superchart.test.ts │ │ └── unknown.test.ts │ ├── data.test.ts │ ├── defaultKernels.test.ts │ ├── displayData.test.ts │ ├── envVars.test.ts │ ├── executionCount.test.ts │ ├── images │ │ └── bar.test.ts │ ├── kernels.test.ts │ ├── languages │ │ └── deno.test.ts │ ├── reconnect.test.ts │ ├── runtimes │ │ ├── bun │ │ │ └── run.test.ts │ │ └── deno │ │ │ └── run.test.ts │ ├── setup.ts │ ├── statefulness.test.ts │ └── streaming.test.ts ├── tsconfig.json ├── tsup.config.js ├── typedoc.json └── vitest.config.mts ├── package.json ├── pnpm-lock.yaml ├── pnpm-workspace.yaml ├── python ├── README.md ├── async_example.py ├── e2b_code_interpreter │ ├── __init__.py │ ├── charts.py │ ├── code_interpreter_async.py │ ├── code_interpreter_sync.py │ ├── constants.py │ ├── exceptions.py │ └── models.py ├── example.py ├── package.json ├── poetry.lock ├── pyproject.toml ├── pytest.ini ├── scripts │ └── generate_sdk_ref.sh └── tests │ ├── async │ ├── test_async_bash.py │ ├── test_async_basic.py │ ├── test_async_callbacks.py │ ├── test_async_custom_repr_object.py │ ├── test_async_data.py │ ├── test_async_default_kernels.py │ ├── test_async_display_data.py │ ├── test_async_env_vars.py │ ├── test_async_execution_count.py │ ├── test_async_kernels.py │ ├── test_async_reconnect.py │ ├── test_async_statefulness.py │ └── test_async_streaming.py │ ├── benchmarking.py │ ├── charts │ ├── test_bar.py │ ├── test_box_and_whiskers.py │ ├── test_json.py │ ├── test_line.py │ ├── test_log_chart.py │ ├── test_pie.py │ ├── test_scale.py │ ├── test_scatter.py │ ├── test_superchart.py │ └── test_unknown.py │ ├── conftest.py │ ├── images │ └── test_images.py │ ├── languages │ └── test_deno.py │ └── sync │ ├── test_bash.py │ ├── test_basic.py │ ├── test_callbacks.py │ ├── test_custom_repr_object.py │ ├── test_data.py │ ├── test_default_kernels.py │ ├── test_display_data.py │ ├── test_env_vars.py │ ├── test_execution_count.py │ ├── test_kernels.py │ ├── test_reconnect.py │ ├── test_statefulness.py │ └── test_streaming.py ├── readme-assets ├── e2b-code-interpreter-dark.png ├── e2b-code-interpreter-light.png └── logo-circle.png ├── sdk-reference ├── code-interpreter-js-sdk │ ├── v1.0.4 │ │ ├── charts │ │ │ └── page.mdx │ │ ├── consts │ │ │ └── page.mdx │ │ ├── index │ │ │ └── page.mdx │ │ ├── messaging │ │ │ └── page.mdx │ │ └── sandbox │ │ │ └── page.mdx │ ├── v1.1.0 │ │ ├── charts │ │ │ └── page.mdx │ │ ├── consts │ │ │ └── page.mdx │ │ ├── index │ │ │ └── page.mdx │ │ ├── messaging │ │ │ └── page.mdx │ │ └── sandbox │ │ │ └── page.mdx │ ├── v1.1.1 │ │ ├── charts │ │ │ └── page.mdx │ │ ├── consts │ │ │ └── page.mdx │ │ ├── index │ │ │ └── page.mdx │ │ ├── messaging │ │ │ └── page.mdx │ │ └── sandbox │ │ │ └── page.mdx │ ├── v1.2.0 │ │ ├── charts │ │ │ └── page.mdx │ │ ├── consts │ │ │ └── page.mdx │ │ ├── index │ │ │ └── page.mdx │ │ ├── messaging │ │ │ └── page.mdx │ │ └── sandbox │ │ │ └── page.mdx │ └── v1.5.0 │ │ ├── charts │ │ └── page.mdx │ │ ├── consts │ │ └── page.mdx │ │ ├── index │ │ └── page.mdx │ │ ├── messaging │ │ └── page.mdx │ │ └── sandbox │ │ └── page.mdx └── code-interpreter-python-sdk │ ├── v1.0.1 │ └── sandbox │ │ └── page.mdx │ ├── v1.0.2 │ └── sandbox │ │ └── page.mdx │ ├── v1.0.3 │ └── sandbox │ │ └── page.mdx │ ├── v1.0.4 │ └── sandbox │ │ └── page.mdx │ ├── v1.0.5 │ └── sandbox │ │ └── page.mdx │ ├── v1.1.0 │ └── sandbox │ │ └── page.mdx │ ├── v1.1.1 │ └── sandbox │ │ └── page.mdx │ ├── v1.2.0 │ └── sandbox │ │ └── page.mdx │ ├── v1.2.1 │ └── sandbox │ │ └── page.mdx │ └── v1.5.0 │ └── sandbox │ └── page.mdx └── template ├── Dockerfile ├── README.md ├── deno.json ├── e2b.Dockerfile ├── e2b.toml ├── ipython_kernel_config.py ├── jupyter_server_config.py ├── matplotlibrc ├── package.json ├── requirements.txt ├── server ├── api │ └── models │ │ ├── __init__.py │ │ ├── context.py │ │ ├── create_context.py │ │ ├── env_vars.py │ │ ├── error.py │ │ ├── execution_request.py │ │ ├── logs.py │ │ ├── output.py │ │ └── result.py ├── consts.py ├── contexts.py ├── envs.py ├── errors.py ├── main.py ├── messaging.py ├── requirements.txt ├── stream.py └── utils │ └── locks.py ├── start-up.sh ├── startup_scripts ├── 0001_envs.py ├── 0002_data.py └── 0003_images.py └── test.Dockerfile /.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. -------------------------------------------------------------------------------- /.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 | } -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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@v3 19 | 20 | - name: Set up Python 21 | uses: actions/setup-python@v4 22 | with: 23 | python-version: '3.10' 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 | -------------------------------------------------------------------------------- /.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 | 9 | permissions: 10 | contents: read 11 | 12 | jobs: 13 | test: 14 | defaults: 15 | run: 16 | working-directory: ./js 17 | name: JS SDK - Build and test 18 | runs-on: ubuntu-22.04 19 | steps: 20 | - name: Checkout repository 21 | uses: actions/checkout@v3 22 | 23 | - name: Install pnpm 24 | uses: pnpm/action-setup@v3 25 | id: pnpm-install 26 | with: 27 | version: 9.5 28 | 29 | - name: Setup Node 30 | uses: actions/setup-node@v3 31 | with: 32 | node-version: '18.x' 33 | registry-url: 'https://registry.npmjs.org' 34 | cache: pnpm 35 | cache-dependency-path: pnpm-lock.yaml 36 | 37 | - name: Configure pnpm 38 | run: | 39 | pnpm config set auto-install-peers true 40 | pnpm config set exclude-links-from-lockfile true 41 | 42 | - name: Install dependencies 43 | run: pnpm install --frozen-lockfile 44 | 45 | - name: Test build 46 | run: pnpm build 47 | 48 | - name: Run Node tests 49 | run: pnpm test 50 | env: 51 | E2B_API_KEY: ${{ secrets.E2B_API_KEY }} 52 | 53 | - name: Install Bun 54 | uses: oven-sh/setup-bun@v2 55 | with: 56 | version: 1.1.x 57 | 58 | - name: Run Bun tests 59 | run: pnpm test:bun 60 | env: 61 | E2B_API_KEY: ${{ secrets.E2B_API_KEY }} 62 | 63 | - name: Install Deno 64 | uses: denoland/setup-deno@v1 65 | with: 66 | deno-version: v1.x 67 | 68 | - name: Run Deno tests 69 | run: pnpm test:deno 70 | env: 71 | E2B_API_KEY: ${{ secrets.E2B_API_KEY }} 72 | -------------------------------------------------------------------------------- /.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 | js-sdk: 18 | uses: ./.github/workflows/js_tests.yml 19 | secrets: 20 | E2B_API_KEY: ${{ secrets.E2B_API_KEY }} 21 | python-sdk: 22 | uses: ./.github/workflows/python_tests.yml 23 | secrets: 24 | E2B_API_KEY: ${{ secrets.E2B_API_KEY }} 25 | charts-tests: 26 | uses: ./.github/workflows/charts_tests.yml 27 | -------------------------------------------------------------------------------- /.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 | 9 | permissions: 10 | contents: read 11 | 12 | jobs: 13 | publish: 14 | defaults: 15 | run: 16 | working-directory: ./python 17 | name: Python SDK - Build and test 18 | runs-on: ubuntu-22.04 19 | steps: 20 | - name: Checkout repository 21 | uses: actions/checkout@v3 22 | 23 | - name: Set up Python 24 | uses: actions/setup-python@v4 25 | with: 26 | python-version: '3.9' 27 | 28 | - name: Install and configure Poetry 29 | uses: snok/install-poetry@v1 30 | with: 31 | version: 1.5.1 32 | virtualenvs-create: true 33 | virtualenvs-in-project: true 34 | installer-parallel: true 35 | 36 | - name: Install dependencies 37 | run: poetry install 38 | 39 | - name: Test build 40 | run: poetry build 41 | 42 | - name: Run tests 43 | run: poetry run pytest --verbose -x 44 | env: 45 | E2B_API_KEY: ${{ secrets.E2B_API_KEY }} 46 | -------------------------------------------------------------------------------- /.github/workflows/release_candidates.yml: -------------------------------------------------------------------------------- 1 | name: Release Candidates 2 | 3 | on: 4 | pull_request: 5 | 6 | permissions: 7 | contents: write 8 | 9 | jobs: 10 | release: 11 | name: Release Candidate 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - name: Checkout Repo 16 | uses: actions/checkout@v4 17 | with: 18 | ref: ${{ github.head_ref }} 19 | 20 | - uses: pnpm/action-setup@v3 21 | if: ${{ contains( github.event.pull_request.labels.*.name, 'js-rc') }} 22 | with: 23 | version: 9.5 24 | 25 | - name: Setup Node.js 18 26 | uses: actions/setup-node@v4 27 | if: ${{ contains( github.event.pull_request.labels.*.name, 'js-rc') }} 28 | with: 29 | node-version: '18.x' 30 | registry-url: https://registry.npmjs.org 31 | cache: pnpm 32 | 33 | - name: Configure pnpm 34 | if: ${{ contains( github.event.pull_request.labels.*.name, 'js-rc') }} 35 | run: | 36 | pnpm config set auto-install-peers true 37 | pnpm config set exclude-links-from-lockfile true 38 | 39 | - name: Install dependencies 40 | if: ${{ contains( github.event.pull_request.labels.*.name, 'js-rc') }} 41 | run: pnpm install --frozen-lockfile 42 | 43 | - name: Test JS SDK 44 | working-directory: js 45 | if: ${{ contains( github.event.pull_request.labels.*.name, 'js-rc') }} 46 | run: | 47 | pnpm run test 48 | env: 49 | E2B_API_KEY: ${{ secrets.E2B_API_KEY }} 50 | 51 | - name: Release JS Candidate 52 | working-directory: js 53 | if: ${{ contains( github.event.pull_request.labels.*.name, 'js-rc') }} 54 | run: | 55 | npm version prerelease --preid=${{ github.head_ref }} 56 | npm publish --tag rc || true 57 | env: 58 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 59 | 60 | - name: Set up Python 61 | uses: actions/setup-python@v4 62 | if: ${{ contains( github.event.pull_request.labels.*.name, 'python-rc') }} 63 | with: 64 | python-version: "3.9" 65 | 66 | - name: Install and configure Poetry 67 | uses: snok/install-poetry@v1 68 | if: ${{ contains( github.event.pull_request.labels.*.name, 'python-rc') }} 69 | with: 70 | version: 1.8.1 71 | virtualenvs-create: true 72 | virtualenvs-in-project: true 73 | installer-parallel: true 74 | 75 | - name: Test Python SDK 76 | if: ${{ contains( github.event.pull_request.labels.*.name, 'python-rc') }} 77 | working-directory: python 78 | run: | 79 | poetry install 80 | poetry run pytest -n 4 --verbose -x 81 | env: 82 | E2B_API_KEY: ${{ secrets.E2B_API_KEY }} 83 | 84 | - name: Release Candidate 85 | if: ${{ contains( github.event.pull_request.labels.*.name, 'python-rc') }} 86 | working-directory: python 87 | run: | 88 | poetry version prerelease 89 | poetry build 90 | poetry config pypi-token.pypi ${PYPI_TOKEN} && poetry publish --skip-existing 91 | env: 92 | PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }} 93 | 94 | - name: Commit new versions 95 | if: ${{ contains( github.event.pull_request.labels.*.name, 'js-rc') || contains( github.event.pull_request.labels.*.name, 'python-rc') }} 96 | run: | 97 | git config user.name "github-actions[bot]" 98 | git config user.email "github-actions[bot]@users.noreply.github.com" 99 | git commit -am "[skip ci] Release new versions" || exit 0 100 | git push 101 | env: 102 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 103 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "semi": false, 4 | "trailingComma": "es5" 5 | } 6 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | # These owners will be the default owners for everything in 2 | # the repo. Unless a later match takes precedence. 3 | * @jakubno @ValentaTomas @0div @mishushakov 4 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | start-template-server: 2 | docker run --rm -e E2B_LOCAL=true -p 49999:49999 -it $$(docker build . -q -f ./template/test.Dockerfile) 3 | 4 | kill-template-server: 5 | docker kill $(shell docker ps --filter expose=49999 --format {{.ID}}) 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 4 | 5 | ![E2B Code Interpreter Preview](/readme-assets/e2b-code-interpreter-light.png#gh-light-mode-only) 6 | ![E2B Code Interpreter Preview](/readme-assets/e2b-code-interpreter-dark.png#gh-dark-mode-only) 7 | 8 |

9 | 10 | Last 1 month downloads for the Python SDK 12 | 13 | 14 | Last 1 month downloads for the JavaScript SDK 16 | 17 |

18 | 19 | 22 | ## What is E2B? 23 | [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). 24 | 25 | ## Run your first Sandbox 26 | 27 | ### 1. Install SDK 28 | 29 | JavaScript / TypeScript 30 | ``` 31 | npm i @e2b/code-interpreter 32 | ``` 33 | 34 | Python 35 | ``` 36 | pip install e2b-code-interpreter 37 | ``` 38 | 39 | ### 2. Get your E2B API key 40 | 1. Sign up to E2B [here](https://e2b.dev). 41 | 2. Get your API key [here](https://e2b.dev/dashboard?tab=keys). 42 | 3. Set environment variable with your API key. 43 | ``` 44 | E2B_API_KEY=e2b_*** 45 | ``` 46 | 47 | ### 3. Execute code with code interpreter inside Sandbox 48 | 49 | JavaScript / TypeScript 50 | ```ts 51 | import { Sandbox } from '@e2b/code-interpreter' 52 | 53 | const sbx = await Sandbox.create() 54 | await sbx.runCode('x = 1') 55 | 56 | const execution = await sbx.runCode('x+=1; x') 57 | console.log(execution.text) // outputs 2 58 | ``` 59 | 60 | Python 61 | ```py 62 | from e2b_code_interpreter import Sandbox 63 | 64 | with Sandbox() as sandbox: 65 | sandbox.run_code("x = 1") 66 | execution = sandbox.run_code("x+=1; x") 67 | print(execution.text) # outputs 2 68 | ``` 69 | 70 | ### 4. Check docs 71 | Visit [E2B documentation](https://e2b.dev/docs). 72 | 73 | ### 5. E2B cookbook 74 | Visit our [Cookbook](https://github.com/e2b-dev/e2b-cookbook/tree/main) to get inspired by examples with different LLMs and AI frameworks. 75 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /chart_data_extractor/e2b_charts/__init__.py: -------------------------------------------------------------------------------- 1 | from .main import chart_figure_to_chart, chart_figure_to_dict 2 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /chart_data_extractor/e2b_charts/main.py: -------------------------------------------------------------------------------- 1 | from typing import Optional, List, Literal 2 | 3 | from matplotlib.axes import Axes 4 | from matplotlib.collections import PathCollection 5 | from matplotlib.lines import Line2D 6 | from matplotlib.patches import Rectangle, Wedge, PathPatch 7 | from matplotlib.pyplot import Figure 8 | 9 | from matplotlib.text import Text 10 | from pydantic import Field 11 | 12 | from .charts import ( 13 | ChartType, 14 | Chart, 15 | LineChart, 16 | BarChart, 17 | BoxAndWhiskerChart, 18 | PieChart, 19 | ScatterChart, 20 | ) 21 | from .utils.filtering import is_grid_line 22 | 23 | 24 | class SuperChart(Chart): 25 | type: Literal[ChartType.SUPERCHART] = ChartType.SUPERCHART 26 | elements: List[ 27 | LineChart | ScatterChart | BarChart | PieChart | BoxAndWhiskerChart 28 | ] = Field(default_factory=list) 29 | 30 | def __init__(self, figure: Figure): 31 | title = figure.get_suptitle() 32 | super().__init__(title=title) 33 | 34 | self.elements = [get_chart_from_ax(ax) for ax in figure.axes] 35 | 36 | 37 | def _get_type_of_chart(ax: Axes) -> ChartType: 38 | objects = list(filter(lambda obj: not isinstance(obj, Text), ax._children)) 39 | 40 | # Check for Line plots 41 | if all(isinstance(line, Line2D) for line in objects): 42 | return ChartType.LINE 43 | 44 | if all(isinstance(box_or_path, (PathPatch, Line2D)) for box_or_path in objects): 45 | return ChartType.BOX_AND_WHISKER 46 | 47 | filtered = [] 48 | for obj in objects: 49 | if isinstance(obj, Line2D) and is_grid_line(obj): 50 | continue 51 | filtered.append(obj) 52 | 53 | objects = filtered 54 | 55 | # Check for Scatter plots 56 | if all(isinstance(path, PathCollection) for path in objects): 57 | return ChartType.SCATTER 58 | 59 | # Check for Pie plots 60 | if all(isinstance(artist, Wedge) for artist in objects): 61 | return ChartType.PIE 62 | 63 | # Check for Bar plots 64 | if all(isinstance(rect, Rectangle) for rect in objects): 65 | return ChartType.BAR 66 | 67 | return ChartType.UNKNOWN 68 | 69 | 70 | def get_chart_from_ax( 71 | ax: Axes, 72 | ) -> LineChart | ScatterChart | BarChart | PieChart | BoxAndWhiskerChart | Chart: 73 | chart_type = _get_type_of_chart(ax) 74 | 75 | if chart_type == ChartType.LINE: 76 | chart = LineChart(ax=ax) 77 | elif chart_type == ChartType.SCATTER: 78 | chart = ScatterChart(ax=ax) 79 | elif chart_type == ChartType.BAR: 80 | chart = BarChart(ax=ax) 81 | elif chart_type == ChartType.PIE: 82 | chart = PieChart(ax=ax) 83 | elif chart_type == ChartType.BOX_AND_WHISKER: 84 | chart = BoxAndWhiskerChart(ax=ax) 85 | else: 86 | chart = Chart(ax=ax, type=chart_type) 87 | 88 | return chart 89 | 90 | 91 | def is_figure_blank(axes: List[Axes]) -> bool: 92 | """Check if a Matplotlib figure is blank (has no user-added artists).""" 93 | for ax in axes: 94 | if ax.has_data(): 95 | return False # The figure contains user-added data 96 | return True # No data found, figure is blank 97 | 98 | 99 | def chart_figure_to_chart(figure: Figure) -> Optional[Chart]: 100 | """ 101 | This method is used to extract data from the figure object to a dictionary 102 | """ 103 | # Get all Axes objects from the Figure 104 | axes = figure.get_axes() 105 | 106 | if not axes or is_figure_blank(axes): 107 | return 108 | elif len(axes) > 1: 109 | return SuperChart(figure=figure) 110 | else: 111 | ax = axes[0] 112 | return get_chart_from_ax(ax) 113 | 114 | 115 | def chart_figure_to_dict(figure: Figure) -> dict: 116 | chart = chart_figure_to_chart(figure) 117 | if chart: 118 | return chart.model_dump() 119 | return {} 120 | -------------------------------------------------------------------------------- /chart_data_extractor/e2b_charts/utils/__init__.py: -------------------------------------------------------------------------------- 1 | from .filtering import is_grid_line 2 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /chart_data_extractor/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@e2b/data-extractor", 3 | "private": true, 4 | "version": "0.0.3", 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 | } 11 | } 12 | -------------------------------------------------------------------------------- /chart_data_extractor/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "e2b-charts" 3 | version = "0.0.3" 4 | description = "Package for extracting data for E2B Code Interpreter" 5 | authors = ["e2b "] 6 | license = "Apache-2.0" 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 | 24 | [build-system] 25 | requires = ["poetry-core"] 26 | build-backend = "poetry.core.masonry.api" 27 | 28 | [tool.poetry.urls] 29 | "Bug Tracker" = "https://github.com/e2b-dev/code-interpreter/issues" 30 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | from e2b_charts.charts import BarChart, ChartType 5 | 6 | 7 | def test_blank_chart(): 8 | figure, _ = plt.subplots() 9 | chart = chart_figure_to_chart(figure) 10 | assert chart is None 11 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /chart_data_extractor/tests/charts/test_categorical_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 | x = [1, 2, 3, 4, 5] 11 | y = ["A", "B", "C", "D", "E"] 12 | 13 | # Create the plot 14 | plt.figure(figsize=(10, 6)) 15 | plt.plot(x, y) 16 | 17 | return plt.gcf() 18 | 19 | 20 | def test_categorical_scale(): 21 | figure = _prep_chart_figure() 22 | chart = chart_figure_to_chart(figure) 23 | assert chart 24 | 25 | assert isinstance(chart, LineChart) 26 | assert chart.x_scale == "linear" 27 | assert chart.y_scale == "categorical" 28 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 == 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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/.gitignore: -------------------------------------------------------------------------------- 1 | deno.lock 2 | -------------------------------------------------------------------------------- /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 sandbox = 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 | -------------------------------------------------------------------------------- /js/example.mts: -------------------------------------------------------------------------------- 1 | import dotenv from 'dotenv' 2 | 3 | import { Sandbox } from './dist' 4 | 5 | dotenv.config() 6 | 7 | const code = ` 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 | x = np.linspace(0, 10, 100) 18 | plt.plot(x, y) 19 | plt.show() 20 | 21 | import pandas 22 | pandas.DataFrame({"a": [1, 2, 3]}) 23 | ` 24 | 25 | const sandbox = await Sandbox.create() 26 | console.log(sandbox.sandboxId) 27 | 28 | const execution = await sandbox.runCode(code, { 29 | onStdout(msg) { 30 | console.log('stdout', msg) 31 | }, 32 | onStderr(msg) { 33 | console.log('stderr', msg) 34 | }, 35 | }) 36 | console.log(execution.results[0].formats()) 37 | console.log(execution.results[0].data) 38 | console.log(execution.results.length) 39 | -------------------------------------------------------------------------------- /js/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@e2b/code-interpreter", 3 | "version": "1.5.0", 4 | "packageManager": "pnpm@8.7.6", 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 | }, 39 | "devDependencies": { 40 | "@types/node": "^18.18.6", 41 | "dotenv": "^16.4.5", 42 | "knip": "^5.25.1", 43 | "npm-check-updates": "^17.1.14", 44 | "tsup": "^8.4.0", 45 | "typedoc": "0.26.8", 46 | "typedoc-plugin-markdown": "4.2.7", 47 | "typescript": "^5.5.3", 48 | "vitest": "^3.0.9" 49 | }, 50 | "files": [ 51 | "dist", 52 | "README.md", 53 | "package.json" 54 | ], 55 | "keywords": [ 56 | "e2b", 57 | "ai-agents", 58 | "agents", 59 | "ai", 60 | "code-interpreter", 61 | "stateful-sandbox", 62 | "stateful-serverrless", 63 | "sandbox", 64 | "code", 65 | "runtime", 66 | "vm" 67 | ], 68 | "dependencies": { 69 | "e2b": "^1.4.0" 70 | }, 71 | "engines": { 72 | "node": ">=18" 73 | }, 74 | "browserslist": [ 75 | "defaults" 76 | ] 77 | } 78 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/src/charts.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Chart types 3 | */ 4 | export enum ChartType { 5 | LINE = 'line', 6 | SCATTER = 'scatter', 7 | BAR = 'bar', 8 | PIE = 'pie', 9 | BOX_AND_WHISKER = 'box_and_whisker', 10 | SUPERCHART = 'superchart', 11 | UNKNOWN = 'unknown', 12 | } 13 | 14 | 15 | /** 16 | * Ax scale types 17 | */ 18 | export enum ScaleType { 19 | LINEAR = "linear", 20 | DATETIME = "datetime", 21 | CATEGORICAL = "categorical", 22 | LOG = "log", 23 | SYMLOG = "symlog", 24 | LOGIT = "logit", 25 | FUNCTION = "function", 26 | FUNCTIONLOG = "functionlog", 27 | ASINH = "asinh", 28 | } 29 | 30 | /** 31 | * Represents a chart. 32 | */ 33 | export type Chart = { 34 | type: ChartType 35 | title: string 36 | elements: any[] 37 | } 38 | 39 | type Chart2D = Chart & { 40 | x_label?: string 41 | y_label?: string 42 | x_unit?: string 43 | y_unit?: string 44 | } 45 | 46 | export type PointData = { 47 | label: string 48 | points: [number | string, number | string][] 49 | } 50 | 51 | type PointChart = Chart2D & { 52 | x_ticks: (number | string)[] 53 | x_scale: ScaleType 54 | x_tick_labels: string[] 55 | y_ticks: (number | string)[] 56 | y_scale: ScaleType 57 | y_tick_labels: string[] 58 | elements: PointData[] 59 | } 60 | 61 | export type LineChart = PointChart & { 62 | type: ChartType.LINE 63 | } 64 | 65 | export type ScatterChart = PointChart & { 66 | type: ChartType.SCATTER 67 | } 68 | 69 | export type BarData = { 70 | label: string 71 | value: string 72 | group: string 73 | } 74 | 75 | export type BarChart = Chart2D & { 76 | type: ChartType.BAR 77 | elements: BarData[] 78 | } 79 | 80 | export type PieData = { 81 | label: string 82 | angle: number 83 | radius: number 84 | } 85 | 86 | export type PieChart = Chart & { 87 | type: ChartType.PIE 88 | elements: PieData[] 89 | } 90 | 91 | export type BoxAndWhiskerData = { 92 | label: string 93 | min: number 94 | first_quartile: number 95 | median: number 96 | third_quartile: number 97 | max: number 98 | outliers: number[] 99 | } 100 | 101 | export type BoxAndWhiskerChart = Chart2D & { 102 | type: ChartType.BOX_AND_WHISKER 103 | elements: BoxAndWhiskerData[] 104 | } 105 | 106 | export type SuperChart = Chart & { 107 | type: ChartType.SUPERCHART 108 | elements: Chart[] 109 | } 110 | 111 | export type ChartTypes = 112 | | LineChart 113 | | ScatterChart 114 | | BarChart 115 | | PieChart 116 | | BoxAndWhiskerChart 117 | | SuperChart 118 | export function deserializeChart(data: any): Chart { 119 | switch (data.type) { 120 | case ChartType.LINE: 121 | return { ...data } as LineChart 122 | case ChartType.SCATTER: 123 | return { ...data } as ScatterChart 124 | case ChartType.BAR: 125 | return { ...data } as BarChart 126 | case ChartType.PIE: 127 | return { ...data } as PieChart 128 | case ChartType.BOX_AND_WHISKER: 129 | return { ...data } as BoxAndWhiskerChart 130 | case ChartType.SUPERCHART: 131 | const charts = data.data.map((g: any) => deserializeChart(g)) 132 | delete data.data 133 | return { 134 | ...data, 135 | data: charts, 136 | } as SuperChart 137 | default: 138 | return { ...data, type: ChartType.UNKNOWN } as Chart 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /js/src/consts.ts: -------------------------------------------------------------------------------- 1 | export const DEFAULT_TIMEOUT_MS = 60_000 // 1 minute 2 | export const JUPYTER_PORT = 49999 3 | -------------------------------------------------------------------------------- /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/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('Request timed out — the \'requestTimeoutMs\' option can be used to increase this timeout') 6 | } 7 | 8 | return error 9 | } 10 | 11 | export function formatExecutionTimeoutError(error: unknown) { 12 | if (error instanceof Error && error.name === 'AbortError') { 13 | return new TimeoutError('Execution timed out — the \'timeoutMs\' option can be used to increase this timeout') 14 | } 15 | 16 | return error 17 | } 18 | 19 | export async function* readLines(stream: ReadableStream) { 20 | const reader = stream.getReader(); 21 | let buffer = '' 22 | 23 | try { 24 | while (true) { 25 | const { done, value } = await reader.read(); 26 | 27 | if (value !== undefined) { 28 | buffer += new TextDecoder().decode(value) 29 | } 30 | 31 | if (done) { 32 | if (buffer.length > 0) { 33 | yield buffer 34 | } 35 | break 36 | } 37 | 38 | let newlineIdx = -1 39 | 40 | do { 41 | newlineIdx = buffer.indexOf('\n') 42 | if (newlineIdx !== -1) { 43 | yield buffer.slice(0, newlineIdx) 44 | buffer = buffer.slice(newlineIdx + 1) 45 | } 46 | } while (newlineIdx !== -1) 47 | } 48 | } finally { 49 | reader.releaseLock() 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /js/tests/basic.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'vitest' 2 | 3 | import { sandboxTest } from './setup' 4 | 5 | sandboxTest('basic', async ({ sandbox }) => { 6 | const result = await sandbox.runCode('x =1; x') 7 | 8 | expect(result.text).toEqual('1') 9 | }) 10 | -------------------------------------------------------------------------------- /js/tests/benchmarking.js: -------------------------------------------------------------------------------- 1 | const { Sandbox } = require('../dist') 2 | const dotenv = require('dotenv') 3 | dotenv.config() 4 | 5 | const iterations = 10 6 | let createSandboxTime = 0 7 | let fistExecTime = 0 8 | let secondExecTime = 0 9 | 10 | async function main() { 11 | for (let i = 0; i < iterations; i++) { 12 | console.log('Iteration:', i + 1) 13 | let startTime = new Date() 14 | const sandbox = await Sandbox.create() 15 | createSandboxTime += new Date() - startTime 16 | 17 | startTime = new Date() 18 | await sandbox.runCode('x = 1') 19 | fistExecTime += new Date() - startTime 20 | 21 | startTime = new Date() 22 | const result = await sandbox.runCode('x+=1; x') 23 | secondExecTime += new Date() - startTime 24 | 25 | await sandbox.kill() 26 | } 27 | console.log('Average create sandbox time:', createSandboxTime / iterations) 28 | console.log('Average first exec time:', fistExecTime / iterations) 29 | console.log('Average second exec time:', secondExecTime / iterations) 30 | } 31 | main().catch(console.error) 32 | -------------------------------------------------------------------------------- /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 | 16 | sandboxTest('callback error', async ({ sandbox }) => { 17 | const errors = [] 18 | const result = await sandbox.runCode('xyz', { 19 | onError: (error) => errors.push(error), 20 | }) 21 | 22 | expect(errors.length).toBe(1) 23 | expect(result.error.name).toBe('NameError') 24 | }) 25 | 26 | sandboxTest('callback stdout', async ({ sandbox }) => { 27 | const stdout = [] 28 | const result = await sandbox.runCode('print("hello")', { 29 | onStdout: (out) => stdout.push(out), 30 | }) 31 | 32 | expect(stdout.length).toBe(1) 33 | expect(result.logs.stdout).toEqual(['hello\n']) 34 | }) 35 | 36 | sandboxTest('callback stderr', async ({ sandbox }) => { 37 | const stderr = [] 38 | const result = await sandbox.runCode('import sys;print("This is an error message", file=sys.stderr)', { 39 | onStderr: (err) => stderr.push(err), 40 | }) 41 | 42 | expect(stderr.length).toBe(1) 43 | expect(result.logs.stderr).toEqual(['This is an error message\n']) 44 | }) 45 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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(['Class A', 'Class B', 'Class C']) 53 | expect(bars.map((bar) => bar.outliers)).toEqual([[], [76], []]) 54 | expect(bars.map((bar) => bar.min)).toEqual([78, 84, 75]) 55 | expect(bars.map((bar) => bar.first_quartile)).toEqual([85, 84.75, 79]) 56 | expect(bars.map((bar) => bar.median)).toEqual([88, 88, 82]) 57 | expect(bars.map((bar) => bar.third_quartile)).toEqual([90, 90.5, 86]) 58 | expect(bars.map((bar) => bar.max)).toEqual([92, 95, 88]) 59 | }) 60 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /js/tests/envVars.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'vitest' 2 | 3 | import { isDebug, sandboxTest } from './setup' 4 | import { Sandbox } from '../src' 5 | 6 | // 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. 7 | sandboxTest.skipIf(isDebug)('env vars', async () => { 8 | const sandbox = await Sandbox.create({ 9 | envs: { TEST_ENV_VAR: 'supertest' }, 10 | }) 11 | 12 | try { 13 | const result = await sandbox.runCode( 14 | `import os; x = os.getenv('TEST_ENV_VAR'); x` 15 | ) 16 | 17 | expect(result.results[0].text.trim()).toEqual('supertest') 18 | } finally { 19 | await sandbox.kill() 20 | } 21 | }) 22 | 23 | sandboxTest('env vars on sandbox', async ({ sandbox }) => { 24 | const result = await sandbox.runCode( 25 | "import os; os.getenv('FOO')", 26 | { envs: { FOO: 'bar' } } 27 | ) 28 | 29 | expect(result.results[0].text.trim()).toEqual('bar') 30 | }) 31 | 32 | sandboxTest('env vars on sandbox override', async () => { 33 | const sandbox = await Sandbox.create({ 34 | envs: { FOO: 'bar', SBX: 'value' }, 35 | }) 36 | 37 | try { 38 | await sandbox.runCode( 39 | "import os; os.environ['FOO'] = 'bar'; os.environ['RUNTIME_ENV'] = 'js_runtime'" 40 | ) 41 | const result = await sandbox.runCode( 42 | "import os; os.getenv('FOO')", 43 | { envs: { FOO: 'baz' } } 44 | ) 45 | 46 | expect(result.results[0].text.trim()).toEqual('baz') 47 | 48 | const result2 = await sandbox.runCode( 49 | "import os; os.getenv('RUNTIME_ENV')" 50 | ) 51 | expect(result2.results[0].text.trim()).toEqual('js_runtime') 52 | 53 | if (!isDebug) { 54 | const result3 = await sandbox.runCode( 55 | "import os; os.getenv('SBX')" 56 | ) 57 | expect(result3.results[0].text.trim()).toEqual('value') 58 | } 59 | 60 | const result4 = await sandbox.runCode("import os; os.getenv('FOO')") 61 | expect(result4.results[0].text.trim()).toEqual('bar') 62 | } finally { 63 | await sandbox.kill() 64 | } 65 | }) 66 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | 41 | sandboxTest('get image on save', async ({ sandbox }) => { 42 | const code = ` 43 | import numpy 44 | from PIL import Image 45 | 46 | imarray = numpy.random.rand(16,16,3) * 255 47 | image = Image.fromarray(imarray.astype('uint8')).convert('RGBA') 48 | 49 | image.save("test.png") 50 | ` 51 | 52 | const execution = await sandbox.runCode(code) 53 | 54 | const image = execution.results[0].png 55 | expect(image).toBeDefined() 56 | }) 57 | -------------------------------------------------------------------------------- /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(sandbox.runCode({context, language: 'python'})).rejects.toThrowError() 20 | }) 21 | -------------------------------------------------------------------------------- /js/tests/languages/deno.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'vitest' 2 | 3 | import { sandboxTest } from '../setup' 4 | 5 | sandboxTest.skip('js simple', async ({ sandbox }) => { 6 | const result = await sandbox.runCode('console.log("Hello, World!")', { language: "deno" }) 7 | 8 | expect(result.logs.stdout.join().trim()).toEqual('Hello, World!') 9 | }) 10 | 11 | sandboxTest.skip('js import', async ({ sandbox }) => { 12 | const result = await sandbox.runCode('import isOdd from "npm:is-odd"\nisOdd(3)', { language: "deno" }) 13 | 14 | expect(result.results[0].text).toEqual('true') 15 | }) 16 | 17 | sandboxTest.skip('js top level await', async ({ sandbox }) => { 18 | const result = await sandbox.runCode(` 19 | async function main() { 20 | return 'Hello, World!' 21 | } 22 | 23 | await main() 24 | `, { language: "deno" }) 25 | expect(result.results[0].text).toEqual('Hello, World!') 26 | }) 27 | 28 | sandboxTest.skip('js es6', async ({ sandbox }) => { 29 | const result = await sandbox.runCode(` 30 | const add = (x, y) => x + y; 31 | add(1, 2)`, { language: "deno" }) 32 | expect(result.results[0].text).toEqual('3') 33 | }) 34 | 35 | 36 | sandboxTest.skip('js context', async ({ sandbox }) => { 37 | await sandbox.runCode('const z = 1', { language: "deno" }) 38 | const result = await sandbox.runCode('z', { language: "deno" }) 39 | expect(result.results[0].text).toEqual('1') 40 | }) 41 | 42 | sandboxTest.skip('js cwd', async ({ sandbox }) => { 43 | const result = await sandbox.runCode('process.cwd()', { language: "deno" }) 44 | expect(result.results[0].text).toEqual('/home/user') 45 | 46 | const ctx = await sandbox.createCodeContext({ cwd: '/home', language: "deno" }) 47 | const result2 = await sandbox.runCode('process.cwd()', { context: ctx }) 48 | expect(result2.results[0].text).toEqual('/home') 49 | }) 50 | 51 | sandboxTest.skip('ts simple', async ({ sandbox }) => { 52 | const result = await sandbox.runCode(` 53 | function subtract(x: number, y: number): number { 54 | return x - y; 55 | } 56 | 57 | subtract(1, 2) 58 | `, { language: "deno" }) 59 | 60 | expect(result.results[0].text).toEqual('-1') 61 | }) 62 | 63 | sandboxTest.skip('test display', async ({ sandbox }) => { 64 | const result = await sandbox.runCode(` 65 | { 66 | [Symbol.for("Jupyter.display")]() { 67 | return { 68 | // Plain text content 69 | "text/plain": "Hello world!", 70 | 71 | // HTML output 72 | "text/html": "

Hello world!

", 73 | } 74 | } 75 | } 76 | `, { language: "deno" }) 77 | 78 | expect(result.results[0].html).toBe('

Hello world!

') 79 | expect(result.results[0].text).toBe('Hello world!') 80 | }) 81 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /js/tests/runtimes/bun/run.test.ts: -------------------------------------------------------------------------------- 1 | import { expect, test } from 'bun:test' 2 | 3 | import { Sandbox } from '../../../src' 4 | 5 | test('Bun test', async () => { 6 | const sbx = await Sandbox.create({ timeoutMs: 5_000 }) 7 | 8 | try { 9 | const result = await sbx.runCode('print("Hello, World!")') 10 | expect(result.logs.stdout.join('')).toEqual('Hello, World!\n') 11 | } finally { 12 | await sbx.kill() 13 | } 14 | }, { timeout: 30_000 }) 15 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /js/tests/setup.ts: -------------------------------------------------------------------------------- 1 | import { Sandbox } from '../src' 2 | import { test as base } from 'vitest' 3 | 4 | const timeoutMs = 60_000 5 | 6 | interface SandboxFixture { 7 | sandbox: Sandbox 8 | } 9 | 10 | export const sandboxTest = base.extend({ 11 | sandbox: [ 12 | async ({}, use) => { 13 | const sandbox = await Sandbox.create({ timeoutMs }) 14 | try { 15 | await use(sandbox) 16 | } finally { 17 | try { 18 | await sandbox.kill() 19 | } catch (err) { 20 | if (!isDebug) { 21 | console.warn( 22 | 'Failed to kill sandbox — this is expected if the test runs with local envd.' 23 | ) 24 | } 25 | } 26 | } 27 | }, 28 | { auto: true }, 29 | ], 30 | }) 31 | 32 | export const isDebug = process.env.E2B_DEBUG !== undefined 33 | 34 | export async function wait(ms: number) { 35 | return new Promise((resolve) => setTimeout(resolve, ms)) 36 | } 37 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "e2b-code-interpreter-root", 3 | "private": true, 4 | "scripts": { 5 | "version": "changeset version && pnpm run -r postVersion", 6 | "publish": "changeset publish && pnpm run -r postPublish", 7 | "rm-node-modules": "find . -name 'node_modules' -type d -prune -exec rm -rf '{}' +" 8 | }, 9 | "packageManager": "pnpm@8.7.6", 10 | "devDependencies": { 11 | "@changesets/cli": "^2.27.12", 12 | "@changesets/read": "^0.6.2", 13 | "changeset": "^0.2.6" 14 | }, 15 | "engines": { 16 | "pnpm": ">=9.0.0 <10" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - js 3 | - python 4 | - chart_data_extractor 5 | - template 6 | -------------------------------------------------------------------------------- /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() 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/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(f"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/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/e2b_code_interpreter/constants.py: -------------------------------------------------------------------------------- 1 | DEFAULT_TEMPLATE = "code-interpreter-v1" 2 | JUPYTER_PORT = 49999 3 | DEFAULT_TIMEOUT = 300 4 | -------------------------------------------------------------------------------- /python/e2b_code_interpreter/exceptions.py: -------------------------------------------------------------------------------- 1 | from e2b import TimeoutException 2 | 3 | 4 | def format_request_timeout_error() -> Exception: 5 | return TimeoutException( 6 | f"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 | f"Execution timed out — the 'timeout' option can be used to increase this timeout", 13 | ) 14 | -------------------------------------------------------------------------------- /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(timeout=60) 38 | e = sbx.run_code(code) 39 | print(e.results[0].chart) 40 | 41 | 42 | asyncio.run(run()) 43 | -------------------------------------------------------------------------------- /python/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@e2b/code-interpreter-python", 3 | "private": true, 4 | "version": "1.5.0", 5 | "packageManager": "pnpm@8.7.6", 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 | } 15 | } 16 | -------------------------------------------------------------------------------- /python/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "e2b-code-interpreter" 3 | version = "1.5.0" 4 | description = "E2B Code Interpreter - Stateful code execution" 5 | authors = ["e2b "] 6 | license = "Apache-2.0" 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 = "^1.4.0" 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 | pytest-asyncio = "^0.23.7" 24 | pytest-xdist = "^3.6.1" 25 | black = "23.12.1" 26 | pydoc-markdown = "^4.8.2" 27 | 28 | [build-system] 29 | requires = ["poetry-core"] 30 | build-backend = "poetry.core.masonry.api" 31 | 32 | [tool.poetry.urls] 33 | "Bug Tracker" = "https://github.com/e2b-dev/code-interpreter/issues" 34 | -------------------------------------------------------------------------------- /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=1" 8 | -------------------------------------------------------------------------------- /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/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/async/test_async_basic.py: -------------------------------------------------------------------------------- 1 | from e2b_code_interpreter.code_interpreter_async import AsyncSandbox 2 | 3 | 4 | async def test_basic(async_sandbox: AsyncSandbox): 5 | result = await async_sandbox.run_code("x =1; x") 6 | assert result.text == "1" 7 | -------------------------------------------------------------------------------- /python/tests/async/test_async_callbacks.py: -------------------------------------------------------------------------------- 1 | from e2b_code_interpreter.code_interpreter_async import AsyncSandbox 2 | 3 | 4 | async def test_resuls(async_sandbox: AsyncSandbox): 5 | results = [] 6 | execution = await async_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 | async def test_error(async_sandbox: AsyncSandbox): 14 | errors = [] 15 | execution = await async_sandbox.run_code( 16 | "xyz", on_error=lambda error: errors.append(error) 17 | ) 18 | assert len(errors) == 1 19 | assert execution.error.name == "NameError" 20 | 21 | 22 | async def test_stdout(async_sandbox: AsyncSandbox): 23 | stdout = [] 24 | execution = await async_sandbox.run_code( 25 | "print('Hello from e2b')", on_stdout=lambda out: stdout.append(out) 26 | ) 27 | assert len(stdout) == 1 28 | assert execution.logs.stdout == ["Hello from e2b\n"] 29 | 30 | 31 | async def test_stderr(async_sandbox: AsyncSandbox): 32 | stderr = [] 33 | execution = await async_sandbox.run_code( 34 | 'import sys;print("This is an error message", file=sys.stderr)', 35 | on_stderr=lambda err: stderr.append(err), 36 | ) 37 | assert len(stderr) == 1 38 | assert execution.logs.stderr == ["This is an error message\n"] 39 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | async def test_js_esm_imports(async_sandbox: AsyncSandbox): 11 | execution = await async_sandbox.run_code(""" 12 | import { readFileSync } from 'fs' 13 | console.log(typeof readFileSync) 14 | """, language="js") 15 | assert execution.logs.stdout == ["function\n"] 16 | 17 | 18 | async def test_js_top_level_await(async_sandbox: AsyncSandbox): 19 | execution = await async_sandbox.run_code(""" 20 | await Promise.resolve('Hello World!') 21 | """, language="js") 22 | assert execution.text == "Hello World!" 23 | 24 | 25 | async def test_ts_kernel(async_sandbox: AsyncSandbox): 26 | execution = await async_sandbox.run_code( 27 | "const message: string = 'Hello, World!'; console.log(message);", language="ts" 28 | ) 29 | assert execution.logs.stdout == ["Hello, World!\n"] 30 | -------------------------------------------------------------------------------- /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/async/test_async_env_vars.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_env_vars_sandbox(): 8 | # sbx = await AsyncSandbox.create(envs={"FOO": "bar"}) 9 | # try: 10 | # result = await sbx.run_code("import os; os.getenv('FOO')") 11 | # assert result.text == "bar" 12 | # finally: 13 | # await sbx.kill() 14 | 15 | 16 | async def test_env_vars_in_run_code(async_sandbox: AsyncSandbox): 17 | result = await async_sandbox.run_code( 18 | "import os; os.getenv('FOO')", envs={"FOO": "bar"} 19 | ) 20 | assert result.text == "bar" 21 | 22 | 23 | # 24 | # async def test_env_vars_override(debug: bool): 25 | # sbx = await AsyncSandbox.create(envs={"FOO": "bar", "SBX": "value"}) 26 | # 27 | # try: 28 | # await sbx.run_code( 29 | # "import os; os.environ['FOO'] = 'bar'; os.environ['RUNTIME_ENV'] = 'async_python_runtime'" 30 | # ) 31 | # result = await sbx.run_code("import os; os.getenv('FOO')", envs={"FOO": "baz"}) 32 | # assert result.text == "baz" 33 | # 34 | # # This can fail if running in debug mode (there's a race condition with the restart kernel test) 35 | # result = await sbx.run_code("import os; os.getenv('RUNTIME_ENV')") 36 | # assert result.text == "async_python_runtime" 37 | # 38 | # if not debug: 39 | # result = await sbx.run_code("import os; os.getenv('SBX')") 40 | # assert result.text == "value" 41 | # 42 | # # This can fail if running in debug mode (there's a race condition with the restart kernel test) 43 | # result = await sbx.run_code("import os; os.getenv('FOO')") 44 | # assert result.text == "bar" 45 | # finally: 46 | # await sbx.kill() 47 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /python/tests/benchmarking.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | from dotenv import load_dotenv 4 | 5 | from e2b_code_interpreter.code_interpreter_sync import Sandbox 6 | 7 | load_dotenv() 8 | 9 | iterations = 10 10 | create_sandbox_time = 0 11 | first_exec_time = 0 12 | second_exec_time = 0 13 | 14 | for i in range(iterations): 15 | print("Iteration:", i + 1) 16 | start_time = time.time() 17 | sandbox = Sandbox() 18 | create_sandbox_time += time.time() - start_time 19 | 20 | start_time = time.time() 21 | sandbox.run_code("x = 1") 22 | first_exec_time += time.time() - start_time 23 | 24 | start_time = time.time() 25 | result = sandbox.run_code("x+=1; x") 26 | second_exec_time += time.time() - start_time 27 | 28 | sandbox.kill() 29 | 30 | 31 | print(f"Average Create Sandbox Time: {create_sandbox_time / iterations}s") 32 | print(f"Average Execute Python x = 1 Time: {first_exec_time / iterations}s") 33 | print(f"Average Execute Python x+=1; x Time: {second_exec_time / iterations}s") 34 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 == 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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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_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/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/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/conftest.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import pytest_asyncio 3 | import os 4 | 5 | from logging import warning 6 | 7 | from e2b_code_interpreter.code_interpreter_async import AsyncSandbox 8 | from e2b_code_interpreter.code_interpreter_sync import Sandbox 9 | 10 | timeout = 60 11 | 12 | 13 | @pytest.fixture() 14 | def sandbox(debug): 15 | sandbox = Sandbox(timeout=timeout) 16 | 17 | try: 18 | yield sandbox 19 | finally: 20 | try: 21 | sandbox.kill() 22 | except: 23 | if not debug: 24 | warning( 25 | "Failed to kill sandbox — this is expected if the test runs with local envd." 26 | ) 27 | 28 | 29 | @pytest_asyncio.fixture 30 | async def async_sandbox(debug): 31 | sandbox = await AsyncSandbox.create(timeout=timeout) 32 | 33 | try: 34 | yield sandbox 35 | finally: 36 | try: 37 | await sandbox.kill() 38 | except: 39 | if not debug: 40 | warning( 41 | "Failed to kill sandbox — this is expected if the test runs with local envd." 42 | ) 43 | 44 | 45 | @pytest.fixture 46 | def debug(): 47 | return os.getenv("E2B_DEBUG") is not None 48 | 49 | 50 | @pytest.fixture(autouse=True) 51 | def skip_by_debug(request, debug): 52 | if request.node.get_closest_marker("skip_debug"): 53 | if debug: 54 | pytest.skip("skipped because E2B_DEBUG is set") 55 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /python/tests/languages/test_deno.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from e2b_code_interpreter import AsyncSandbox 4 | 5 | 6 | @pytest.mark.skip(reason="Deno is not supported yet") 7 | async def test_javascript(async_sandbox: AsyncSandbox): 8 | code = """ 9 | console.log('Hello, World!') 10 | """ 11 | execution = await async_sandbox.run_code(code, language="deno") 12 | assert execution.logs.stdout == ["Hello, World!\n"] 13 | 14 | 15 | @pytest.mark.skip(reason="Deno is not supported yet") 16 | async def test_import(async_sandbox: AsyncSandbox): 17 | code = """ 18 | import isOdd from 'npm:is-odd' 19 | isOdd(3) 20 | """ 21 | execution = await async_sandbox.run_code(code, language="deno") 22 | assert execution.results[0].text == "true" 23 | 24 | 25 | @pytest.mark.skip(reason="Deno is not supported yet") 26 | async def test_toplevel_await(async_sandbox: AsyncSandbox): 27 | code = """ 28 | async function main() { 29 | return 'Hello, World!' 30 | } 31 | 32 | await main() 33 | """ 34 | execution = await async_sandbox.run_code(code, language="deno") 35 | assert execution.results[0].text == "Hello, World!" 36 | 37 | 38 | @pytest.mark.skip(reason="Deno is not supported yet") 39 | async def test_es6(async_sandbox: AsyncSandbox): 40 | code = """ 41 | const add = (x, y) => x + y; 42 | add(1, 2); 43 | """ 44 | execution = await async_sandbox.run_code(code, language="deno") 45 | assert execution.results[0].text == "3" 46 | 47 | 48 | @pytest.mark.skip(reason="Deno is not supported yet") 49 | async def test_context(async_sandbox: AsyncSandbox): 50 | await async_sandbox.run_code("const x = 1", language="deno") 51 | execution = await async_sandbox.run_code("x", language="deno") 52 | assert execution.results[0].text == "1" 53 | 54 | 55 | @pytest.mark.skip(reason="Deno is not supported yet") 56 | async def test_cwd(async_sandbox: AsyncSandbox): 57 | execution = await async_sandbox.run_code("process.cwd()", language="deno") 58 | assert execution.results[0].text == "/home/user" 59 | 60 | ctx = await async_sandbox.create_code_context("/home", language="deno") 61 | execution = await async_sandbox.run_code("process.cwd()", context=ctx) 62 | assert execution.results[0].text == "/home" 63 | 64 | 65 | @pytest.mark.skip(reason="Deno is not supported yet") 66 | async def test_typescript(async_sandbox: AsyncSandbox): 67 | execution = await async_sandbox.run_code( 68 | """ 69 | function subtract(x: number, y: number): number { 70 | return x - y; 71 | } 72 | 73 | subtract(1, 2); 74 | """, 75 | language="deno", 76 | ) 77 | assert execution.results[0].text == "-1" 78 | 79 | 80 | @pytest.mark.skip(reason="Deno is not supported yet") 81 | async def test_display(async_sandbox: AsyncSandbox): 82 | code = """ 83 | { 84 | [Symbol.for("Jupyter.display")]() { 85 | return { 86 | // Plain text content 87 | "text/plain": "Hello world!", 88 | 89 | // HTML output 90 | "text/html": "

Hello world!

", 91 | } 92 | } 93 | } 94 | """ 95 | execution = await async_sandbox.run_code(code, language="deno") 96 | assert execution.results[0].text == "Hello world!" 97 | assert execution.results[0].html == "

Hello world!

" 98 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /python/tests/sync/test_basic.py: -------------------------------------------------------------------------------- 1 | from e2b_code_interpreter.code_interpreter_sync import Sandbox 2 | 3 | 4 | def test_basic(sandbox: Sandbox): 5 | result = sandbox.run_code("x =1; x") 6 | assert result.text == "1" 7 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | import { readFileSync } from 'fs' 26 | console.log(typeof readFileSync) 27 | """, language="js") 28 | assert execution.logs.stdout == ["function\n"] 29 | 30 | 31 | def test_js_top_level_await(sandbox: Sandbox): 32 | execution = sandbox.run_code(""" 33 | await Promise.resolve('Hello World!') 34 | """, language="js") 35 | assert execution.text == "Hello World!" 36 | 37 | 38 | @pytest.mark.skip_debug() 39 | def test_ts_kernel(sandbox: Sandbox): 40 | execution = sandbox.run_code("const message: string = 'Hello, World!'; console.log(message)", language="ts") 41 | assert execution.logs.stdout == ["Hello, World!\n"] 42 | 43 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /python/tests/sync/test_env_vars.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from e2b_code_interpreter.code_interpreter_sync import Sandbox 4 | 5 | 6 | # @pytest.mark.skip_debug() 7 | # async def test_env_vars_sandbox(): 8 | # sbx = Sandbox(envs={"FOO": "bar"}) 9 | # result = sbx.run_code("import os; os.getenv('FOO')") 10 | # assert result.text == "bar" 11 | # sbx.kill() 12 | 13 | 14 | async def test_env_vars_in_run_code(sandbox: Sandbox): 15 | result = sandbox.run_code("import os; os.getenv('FOO')", envs={"FOO": "bar"}) 16 | assert result.text == "bar" 17 | 18 | 19 | # 20 | # async def test_env_vars_override(debug: bool): 21 | # sbx = Sandbox(envs={"FOO": "bar", "SBX": "value"}) 22 | # sbx.run_code( 23 | # "import os; os.environ['FOO'] = 'bar'; os.environ['RUNTIME_ENV'] = 'python_runtime'" 24 | # ) 25 | # result = sbx.run_code("import os; os.getenv('FOO')", envs={"FOO": "baz"}) 26 | # assert result.text == "baz" 27 | # 28 | # # This can fail if running in debug mode (there's a race condition with the restart kernel test) 29 | # result = sbx.run_code("import os; os.getenv('RUNTIME_ENV')") 30 | # assert result.text == "python_runtime" 31 | # 32 | # if not debug: 33 | # result = sbx.run_code("import os; os.getenv('SBX')") 34 | # assert result.text == "value" 35 | # 36 | # # This can fail if running in debug mode (there's a race condition with the restart kernel test) 37 | # result = sbx.run_code("import os; os.getenv('FOO')") 38 | # assert result.text == "bar" 39 | # 40 | # sbx.kill() 41 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /readme-assets/e2b-code-interpreter-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e2b-dev/code-interpreter/85cac9199b9ed5e4b59a4eb9afb7117ccb142640/readme-assets/e2b-code-interpreter-dark.png -------------------------------------------------------------------------------- /readme-assets/e2b-code-interpreter-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e2b-dev/code-interpreter/85cac9199b9ed5e4b59a4eb9afb7117ccb142640/readme-assets/e2b-code-interpreter-light.png -------------------------------------------------------------------------------- /readme-assets/logo-circle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e2b-dev/code-interpreter/85cac9199b9ed5e4b59a4eb9afb7117ccb142640/readme-assets/logo-circle.png -------------------------------------------------------------------------------- /sdk-reference/code-interpreter-js-sdk/v1.0.4/charts/page.mdx: -------------------------------------------------------------------------------- 1 | ### ChartType 2 | 3 | Chart types 4 | 5 | #### Enumeration Members 6 | 7 | | Enumeration Member | Value | 8 | | ------ | ------ | 9 | | `BAR` | `"bar"` | 10 | | `BOX_AND_WHISKER` | `"box_and_whisker"` | 11 | | `LINE` | `"line"` | 12 | | `PIE` | `"pie"` | 13 | | `SCATTER` | `"scatter"` | 14 | | `SUPERCHART` | `"superchart"` | 15 | | `UNKNOWN` | `"unknown"` | 16 | 17 | *** 18 | 19 | ### ScaleType 20 | 21 | Ax scale types 22 | 23 | #### Enumeration Members 24 | 25 | | Enumeration Member | Value | 26 | | ------ | ------ | 27 | | `ASINH` | `"asinh"` | 28 | | `CATEGORICAL` | `"categorical"` | 29 | | `DATETIME` | `"datetime"` | 30 | | `FUNCTION` | `"function"` | 31 | | `FUNCTIONLOG` | `"functionlog"` | 32 | | `LINEAR` | `"linear"` | 33 | | `LOG` | `"log"` | 34 | | `LOGIT` | `"logit"` | 35 | | `SYMLOG` | `"symlog"` | 36 | 37 | ## Type Aliases 38 | 39 | ### BarChart 40 | 41 | ```ts 42 | type BarChart: Chart2D & object; 43 | ``` 44 | 45 | #### Type declaration 46 | 47 | | Name | Type | 48 | | ------ | ------ | 49 | | `elements` | `BarData`[] | 50 | | `type` | `ChartType.BAR` | 51 | 52 | *** 53 | 54 | ### BarData 55 | 56 | ```ts 57 | type BarData: object; 58 | ``` 59 | 60 | #### Type declaration 61 | 62 | | Name | Type | 63 | | ------ | ------ | 64 | | `group` | `string` | 65 | | `label` | `string` | 66 | | `value` | `string` | 67 | 68 | *** 69 | 70 | ### BoxAndWhiskerChart 71 | 72 | ```ts 73 | type BoxAndWhiskerChart: Chart2D & object; 74 | ``` 75 | 76 | #### Type declaration 77 | 78 | | Name | Type | 79 | | ------ | ------ | 80 | | `elements` | `BoxAndWhiskerData`[] | 81 | | `type` | `ChartType.BOX_AND_WHISKER` | 82 | 83 | *** 84 | 85 | ### BoxAndWhiskerData 86 | 87 | ```ts 88 | type BoxAndWhiskerData: object; 89 | ``` 90 | 91 | #### Type declaration 92 | 93 | | Name | Type | 94 | | ------ | ------ | 95 | | `first_quartile` | `number` | 96 | | `label` | `string` | 97 | | `max` | `number` | 98 | | `median` | `number` | 99 | | `min` | `number` | 100 | | `outliers` | `number`[] | 101 | | `third_quartile` | `number` | 102 | 103 | *** 104 | 105 | ### Chart 106 | 107 | ```ts 108 | type Chart: object; 109 | ``` 110 | 111 | Represents a chart. 112 | 113 | #### Type declaration 114 | 115 | | Name | Type | 116 | | ------ | ------ | 117 | | `elements` | `any`[] | 118 | | `title` | `string` | 119 | | `type` | `ChartType` | 120 | 121 | *** 122 | 123 | ### ChartTypes 124 | 125 | ```ts 126 | type ChartTypes: 127 | | LineChart 128 | | ScatterChart 129 | | BarChart 130 | | PieChart 131 | | BoxAndWhiskerChart 132 | | SuperChart; 133 | ``` 134 | 135 | *** 136 | 137 | ### LineChart 138 | 139 | ```ts 140 | type LineChart: PointChart & object; 141 | ``` 142 | 143 | #### Type declaration 144 | 145 | | Name | Type | 146 | | ------ | ------ | 147 | | `type` | `ChartType.LINE` | 148 | 149 | *** 150 | 151 | ### PieChart 152 | 153 | ```ts 154 | type PieChart: Chart & object; 155 | ``` 156 | 157 | #### Type declaration 158 | 159 | | Name | Type | 160 | | ------ | ------ | 161 | | `elements` | `PieData`[] | 162 | | `type` | `ChartType.PIE` | 163 | 164 | *** 165 | 166 | ### PieData 167 | 168 | ```ts 169 | type PieData: object; 170 | ``` 171 | 172 | #### Type declaration 173 | 174 | | Name | Type | 175 | | ------ | ------ | 176 | | `angle` | `number` | 177 | | `label` | `string` | 178 | | `radius` | `number` | 179 | 180 | *** 181 | 182 | ### PointData 183 | 184 | ```ts 185 | type PointData: object; 186 | ``` 187 | 188 | #### Type declaration 189 | 190 | | Name | Type | 191 | | ------ | ------ | 192 | | `label` | `string` | 193 | | `points` | [`number` \| `string`, `number` \| `string`][] | 194 | 195 | *** 196 | 197 | ### ScatterChart 198 | 199 | ```ts 200 | type ScatterChart: PointChart & object; 201 | ``` 202 | 203 | #### Type declaration 204 | 205 | | Name | Type | 206 | | ------ | ------ | 207 | | `type` | `ChartType.SCATTER` | 208 | 209 | *** 210 | 211 | ### SuperChart 212 | 213 | ```ts 214 | type SuperChart: Chart & object; 215 | ``` 216 | 217 | #### Type declaration 218 | 219 | | Name | Type | 220 | | ------ | ------ | 221 | | `elements` | `Chart`[] | 222 | | `type` | `ChartType.SUPERCHART` | 223 | 224 | ## Functions 225 | 226 | ### deserializeChart() 227 | 228 | ```ts 229 | function deserializeChart(data: any): Chart 230 | ``` 231 | 232 | #### Parameters 233 | 234 | | Parameter | Type | 235 | | ------ | ------ | 236 | | `data` | `any` | 237 | 238 | #### Returns 239 | 240 | `Chart` 241 | -------------------------------------------------------------------------------- /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.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/charts/page.mdx: -------------------------------------------------------------------------------- 1 | ### ChartType 2 | 3 | Chart types 4 | 5 | #### Enumeration Members 6 | 7 | | Enumeration Member | Value | 8 | | ------ | ------ | 9 | | `BAR` | `"bar"` | 10 | | `BOX_AND_WHISKER` | `"box_and_whisker"` | 11 | | `LINE` | `"line"` | 12 | | `PIE` | `"pie"` | 13 | | `SCATTER` | `"scatter"` | 14 | | `SUPERCHART` | `"superchart"` | 15 | | `UNKNOWN` | `"unknown"` | 16 | 17 | *** 18 | 19 | ### ScaleType 20 | 21 | Ax scale types 22 | 23 | #### Enumeration Members 24 | 25 | | Enumeration Member | Value | 26 | | ------ | ------ | 27 | | `ASINH` | `"asinh"` | 28 | | `CATEGORICAL` | `"categorical"` | 29 | | `DATETIME` | `"datetime"` | 30 | | `FUNCTION` | `"function"` | 31 | | `FUNCTIONLOG` | `"functionlog"` | 32 | | `LINEAR` | `"linear"` | 33 | | `LOG` | `"log"` | 34 | | `LOGIT` | `"logit"` | 35 | | `SYMLOG` | `"symlog"` | 36 | 37 | ## Type Aliases 38 | 39 | ### BarChart 40 | 41 | ```ts 42 | type BarChart: Chart2D & object; 43 | ``` 44 | 45 | #### Type declaration 46 | 47 | | Name | Type | 48 | | ------ | ------ | 49 | | `elements` | `BarData`[] | 50 | | `type` | `ChartType.BAR` | 51 | 52 | *** 53 | 54 | ### BarData 55 | 56 | ```ts 57 | type BarData: object; 58 | ``` 59 | 60 | #### Type declaration 61 | 62 | | Name | Type | 63 | | ------ | ------ | 64 | | `group` | `string` | 65 | | `label` | `string` | 66 | | `value` | `string` | 67 | 68 | *** 69 | 70 | ### BoxAndWhiskerChart 71 | 72 | ```ts 73 | type BoxAndWhiskerChart: Chart2D & object; 74 | ``` 75 | 76 | #### Type declaration 77 | 78 | | Name | Type | 79 | | ------ | ------ | 80 | | `elements` | `BoxAndWhiskerData`[] | 81 | | `type` | `ChartType.BOX_AND_WHISKER` | 82 | 83 | *** 84 | 85 | ### BoxAndWhiskerData 86 | 87 | ```ts 88 | type BoxAndWhiskerData: object; 89 | ``` 90 | 91 | #### Type declaration 92 | 93 | | Name | Type | 94 | | ------ | ------ | 95 | | `first_quartile` | `number` | 96 | | `label` | `string` | 97 | | `max` | `number` | 98 | | `median` | `number` | 99 | | `min` | `number` | 100 | | `outliers` | `number`[] | 101 | | `third_quartile` | `number` | 102 | 103 | *** 104 | 105 | ### Chart 106 | 107 | ```ts 108 | type Chart: object; 109 | ``` 110 | 111 | Represents a chart. 112 | 113 | #### Type declaration 114 | 115 | | Name | Type | 116 | | ------ | ------ | 117 | | `elements` | `any`[] | 118 | | `title` | `string` | 119 | | `type` | `ChartType` | 120 | 121 | *** 122 | 123 | ### ChartTypes 124 | 125 | ```ts 126 | type ChartTypes: 127 | | LineChart 128 | | ScatterChart 129 | | BarChart 130 | | PieChart 131 | | BoxAndWhiskerChart 132 | | SuperChart; 133 | ``` 134 | 135 | *** 136 | 137 | ### LineChart 138 | 139 | ```ts 140 | type LineChart: PointChart & object; 141 | ``` 142 | 143 | #### Type declaration 144 | 145 | | Name | Type | 146 | | ------ | ------ | 147 | | `type` | `ChartType.LINE` | 148 | 149 | *** 150 | 151 | ### PieChart 152 | 153 | ```ts 154 | type PieChart: Chart & object; 155 | ``` 156 | 157 | #### Type declaration 158 | 159 | | Name | Type | 160 | | ------ | ------ | 161 | | `elements` | `PieData`[] | 162 | | `type` | `ChartType.PIE` | 163 | 164 | *** 165 | 166 | ### PieData 167 | 168 | ```ts 169 | type PieData: object; 170 | ``` 171 | 172 | #### Type declaration 173 | 174 | | Name | Type | 175 | | ------ | ------ | 176 | | `angle` | `number` | 177 | | `label` | `string` | 178 | | `radius` | `number` | 179 | 180 | *** 181 | 182 | ### PointData 183 | 184 | ```ts 185 | type PointData: object; 186 | ``` 187 | 188 | #### Type declaration 189 | 190 | | Name | Type | 191 | | ------ | ------ | 192 | | `label` | `string` | 193 | | `points` | [`number` \| `string`, `number` \| `string`][] | 194 | 195 | *** 196 | 197 | ### ScatterChart 198 | 199 | ```ts 200 | type ScatterChart: PointChart & object; 201 | ``` 202 | 203 | #### Type declaration 204 | 205 | | Name | Type | 206 | | ------ | ------ | 207 | | `type` | `ChartType.SCATTER` | 208 | 209 | *** 210 | 211 | ### SuperChart 212 | 213 | ```ts 214 | type SuperChart: Chart & object; 215 | ``` 216 | 217 | #### Type declaration 218 | 219 | | Name | Type | 220 | | ------ | ------ | 221 | | `elements` | `Chart`[] | 222 | | `type` | `ChartType.SUPERCHART` | 223 | 224 | ## Functions 225 | 226 | ### deserializeChart() 227 | 228 | ```ts 229 | function deserializeChart(data: any): Chart 230 | ``` 231 | 232 | #### Parameters 233 | 234 | | Parameter | Type | 235 | | ------ | ------ | 236 | | `data` | `any` | 237 | 238 | #### Returns 239 | 240 | `Chart` 241 | -------------------------------------------------------------------------------- /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.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/charts/page.mdx: -------------------------------------------------------------------------------- 1 | ### ChartType 2 | 3 | Chart types 4 | 5 | #### Enumeration Members 6 | 7 | | Enumeration Member | Value | 8 | | ------ | ------ | 9 | | `BAR` | `"bar"` | 10 | | `BOX_AND_WHISKER` | `"box_and_whisker"` | 11 | | `LINE` | `"line"` | 12 | | `PIE` | `"pie"` | 13 | | `SCATTER` | `"scatter"` | 14 | | `SUPERCHART` | `"superchart"` | 15 | | `UNKNOWN` | `"unknown"` | 16 | 17 | *** 18 | 19 | ### ScaleType 20 | 21 | Ax scale types 22 | 23 | #### Enumeration Members 24 | 25 | | Enumeration Member | Value | 26 | | ------ | ------ | 27 | | `ASINH` | `"asinh"` | 28 | | `CATEGORICAL` | `"categorical"` | 29 | | `DATETIME` | `"datetime"` | 30 | | `FUNCTION` | `"function"` | 31 | | `FUNCTIONLOG` | `"functionlog"` | 32 | | `LINEAR` | `"linear"` | 33 | | `LOG` | `"log"` | 34 | | `LOGIT` | `"logit"` | 35 | | `SYMLOG` | `"symlog"` | 36 | 37 | ## Type Aliases 38 | 39 | ### BarChart 40 | 41 | ```ts 42 | type BarChart: Chart2D & object; 43 | ``` 44 | 45 | #### Type declaration 46 | 47 | | Name | Type | 48 | | ------ | ------ | 49 | | `elements` | `BarData`[] | 50 | | `type` | `ChartType.BAR` | 51 | 52 | *** 53 | 54 | ### BarData 55 | 56 | ```ts 57 | type BarData: object; 58 | ``` 59 | 60 | #### Type declaration 61 | 62 | | Name | Type | 63 | | ------ | ------ | 64 | | `group` | `string` | 65 | | `label` | `string` | 66 | | `value` | `string` | 67 | 68 | *** 69 | 70 | ### BoxAndWhiskerChart 71 | 72 | ```ts 73 | type BoxAndWhiskerChart: Chart2D & object; 74 | ``` 75 | 76 | #### Type declaration 77 | 78 | | Name | Type | 79 | | ------ | ------ | 80 | | `elements` | `BoxAndWhiskerData`[] | 81 | | `type` | `ChartType.BOX_AND_WHISKER` | 82 | 83 | *** 84 | 85 | ### BoxAndWhiskerData 86 | 87 | ```ts 88 | type BoxAndWhiskerData: object; 89 | ``` 90 | 91 | #### Type declaration 92 | 93 | | Name | Type | 94 | | ------ | ------ | 95 | | `first_quartile` | `number` | 96 | | `label` | `string` | 97 | | `max` | `number` | 98 | | `median` | `number` | 99 | | `min` | `number` | 100 | | `outliers` | `number`[] | 101 | | `third_quartile` | `number` | 102 | 103 | *** 104 | 105 | ### Chart 106 | 107 | ```ts 108 | type Chart: object; 109 | ``` 110 | 111 | Represents a chart. 112 | 113 | #### Type declaration 114 | 115 | | Name | Type | 116 | | ------ | ------ | 117 | | `elements` | `any`[] | 118 | | `title` | `string` | 119 | | `type` | `ChartType` | 120 | 121 | *** 122 | 123 | ### ChartTypes 124 | 125 | ```ts 126 | type ChartTypes: 127 | | LineChart 128 | | ScatterChart 129 | | BarChart 130 | | PieChart 131 | | BoxAndWhiskerChart 132 | | SuperChart; 133 | ``` 134 | 135 | *** 136 | 137 | ### LineChart 138 | 139 | ```ts 140 | type LineChart: PointChart & object; 141 | ``` 142 | 143 | #### Type declaration 144 | 145 | | Name | Type | 146 | | ------ | ------ | 147 | | `type` | `ChartType.LINE` | 148 | 149 | *** 150 | 151 | ### PieChart 152 | 153 | ```ts 154 | type PieChart: Chart & object; 155 | ``` 156 | 157 | #### Type declaration 158 | 159 | | Name | Type | 160 | | ------ | ------ | 161 | | `elements` | `PieData`[] | 162 | | `type` | `ChartType.PIE` | 163 | 164 | *** 165 | 166 | ### PieData 167 | 168 | ```ts 169 | type PieData: object; 170 | ``` 171 | 172 | #### Type declaration 173 | 174 | | Name | Type | 175 | | ------ | ------ | 176 | | `angle` | `number` | 177 | | `label` | `string` | 178 | | `radius` | `number` | 179 | 180 | *** 181 | 182 | ### PointData 183 | 184 | ```ts 185 | type PointData: object; 186 | ``` 187 | 188 | #### Type declaration 189 | 190 | | Name | Type | 191 | | ------ | ------ | 192 | | `label` | `string` | 193 | | `points` | [`number` \| `string`, `number` \| `string`][] | 194 | 195 | *** 196 | 197 | ### ScatterChart 198 | 199 | ```ts 200 | type ScatterChart: PointChart & object; 201 | ``` 202 | 203 | #### Type declaration 204 | 205 | | Name | Type | 206 | | ------ | ------ | 207 | | `type` | `ChartType.SCATTER` | 208 | 209 | *** 210 | 211 | ### SuperChart 212 | 213 | ```ts 214 | type SuperChart: Chart & object; 215 | ``` 216 | 217 | #### Type declaration 218 | 219 | | Name | Type | 220 | | ------ | ------ | 221 | | `elements` | `Chart`[] | 222 | | `type` | `ChartType.SUPERCHART` | 223 | 224 | ## Functions 225 | 226 | ### deserializeChart() 227 | 228 | ```ts 229 | function deserializeChart(data: any): Chart 230 | ``` 231 | 232 | #### Parameters 233 | 234 | | Parameter | Type | 235 | | ------ | ------ | 236 | | `data` | `any` | 237 | 238 | #### Returns 239 | 240 | `Chart` 241 | -------------------------------------------------------------------------------- /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.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/charts/page.mdx: -------------------------------------------------------------------------------- 1 | ### ChartType 2 | 3 | Chart types 4 | 5 | #### Enumeration Members 6 | 7 | | Enumeration Member | Value | 8 | | ------ | ------ | 9 | | `BAR` | `"bar"` | 10 | | `BOX_AND_WHISKER` | `"box_and_whisker"` | 11 | | `LINE` | `"line"` | 12 | | `PIE` | `"pie"` | 13 | | `SCATTER` | `"scatter"` | 14 | | `SUPERCHART` | `"superchart"` | 15 | | `UNKNOWN` | `"unknown"` | 16 | 17 | *** 18 | 19 | ### ScaleType 20 | 21 | Ax scale types 22 | 23 | #### Enumeration Members 24 | 25 | | Enumeration Member | Value | 26 | | ------ | ------ | 27 | | `ASINH` | `"asinh"` | 28 | | `CATEGORICAL` | `"categorical"` | 29 | | `DATETIME` | `"datetime"` | 30 | | `FUNCTION` | `"function"` | 31 | | `FUNCTIONLOG` | `"functionlog"` | 32 | | `LINEAR` | `"linear"` | 33 | | `LOG` | `"log"` | 34 | | `LOGIT` | `"logit"` | 35 | | `SYMLOG` | `"symlog"` | 36 | 37 | ## Type Aliases 38 | 39 | ### BarChart 40 | 41 | ```ts 42 | type BarChart: Chart2D & object; 43 | ``` 44 | 45 | #### Type declaration 46 | 47 | | Name | Type | 48 | | ------ | ------ | 49 | | `elements` | `BarData`[] | 50 | | `type` | `ChartType.BAR` | 51 | 52 | *** 53 | 54 | ### BarData 55 | 56 | ```ts 57 | type BarData: object; 58 | ``` 59 | 60 | #### Type declaration 61 | 62 | | Name | Type | 63 | | ------ | ------ | 64 | | `group` | `string` | 65 | | `label` | `string` | 66 | | `value` | `string` | 67 | 68 | *** 69 | 70 | ### BoxAndWhiskerChart 71 | 72 | ```ts 73 | type BoxAndWhiskerChart: Chart2D & object; 74 | ``` 75 | 76 | #### Type declaration 77 | 78 | | Name | Type | 79 | | ------ | ------ | 80 | | `elements` | `BoxAndWhiskerData`[] | 81 | | `type` | `ChartType.BOX_AND_WHISKER` | 82 | 83 | *** 84 | 85 | ### BoxAndWhiskerData 86 | 87 | ```ts 88 | type BoxAndWhiskerData: object; 89 | ``` 90 | 91 | #### Type declaration 92 | 93 | | Name | Type | 94 | | ------ | ------ | 95 | | `first_quartile` | `number` | 96 | | `label` | `string` | 97 | | `max` | `number` | 98 | | `median` | `number` | 99 | | `min` | `number` | 100 | | `outliers` | `number`[] | 101 | | `third_quartile` | `number` | 102 | 103 | *** 104 | 105 | ### Chart 106 | 107 | ```ts 108 | type Chart: object; 109 | ``` 110 | 111 | Represents a chart. 112 | 113 | #### Type declaration 114 | 115 | | Name | Type | 116 | | ------ | ------ | 117 | | `elements` | `any`[] | 118 | | `title` | `string` | 119 | | `type` | `ChartType` | 120 | 121 | *** 122 | 123 | ### ChartTypes 124 | 125 | ```ts 126 | type ChartTypes: 127 | | LineChart 128 | | ScatterChart 129 | | BarChart 130 | | PieChart 131 | | BoxAndWhiskerChart 132 | | SuperChart; 133 | ``` 134 | 135 | *** 136 | 137 | ### LineChart 138 | 139 | ```ts 140 | type LineChart: PointChart & object; 141 | ``` 142 | 143 | #### Type declaration 144 | 145 | | Name | Type | 146 | | ------ | ------ | 147 | | `type` | `ChartType.LINE` | 148 | 149 | *** 150 | 151 | ### PieChart 152 | 153 | ```ts 154 | type PieChart: Chart & object; 155 | ``` 156 | 157 | #### Type declaration 158 | 159 | | Name | Type | 160 | | ------ | ------ | 161 | | `elements` | `PieData`[] | 162 | | `type` | `ChartType.PIE` | 163 | 164 | *** 165 | 166 | ### PieData 167 | 168 | ```ts 169 | type PieData: object; 170 | ``` 171 | 172 | #### Type declaration 173 | 174 | | Name | Type | 175 | | ------ | ------ | 176 | | `angle` | `number` | 177 | | `label` | `string` | 178 | | `radius` | `number` | 179 | 180 | *** 181 | 182 | ### PointData 183 | 184 | ```ts 185 | type PointData: object; 186 | ``` 187 | 188 | #### Type declaration 189 | 190 | | Name | Type | 191 | | ------ | ------ | 192 | | `label` | `string` | 193 | | `points` | [`number` \| `string`, `number` \| `string`][] | 194 | 195 | *** 196 | 197 | ### ScatterChart 198 | 199 | ```ts 200 | type ScatterChart: PointChart & object; 201 | ``` 202 | 203 | #### Type declaration 204 | 205 | | Name | Type | 206 | | ------ | ------ | 207 | | `type` | `ChartType.SCATTER` | 208 | 209 | *** 210 | 211 | ### SuperChart 212 | 213 | ```ts 214 | type SuperChart: Chart & object; 215 | ``` 216 | 217 | #### Type declaration 218 | 219 | | Name | Type | 220 | | ------ | ------ | 221 | | `elements` | `Chart`[] | 222 | | `type` | `ChartType.SUPERCHART` | 223 | 224 | ## Functions 225 | 226 | ### deserializeChart() 227 | 228 | ```ts 229 | function deserializeChart(data: any): Chart 230 | ``` 231 | 232 | #### Parameters 233 | 234 | | Parameter | Type | 235 | | ------ | ------ | 236 | | `data` | `any` | 237 | 238 | #### Returns 239 | 240 | `Chart` 241 | -------------------------------------------------------------------------------- /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.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/charts/page.mdx: -------------------------------------------------------------------------------- 1 | ### ChartType 2 | 3 | Chart types 4 | 5 | #### Enumeration Members 6 | 7 | | Enumeration Member | Value | 8 | | ------ | ------ | 9 | | `BAR` | `"bar"` | 10 | | `BOX_AND_WHISKER` | `"box_and_whisker"` | 11 | | `LINE` | `"line"` | 12 | | `PIE` | `"pie"` | 13 | | `SCATTER` | `"scatter"` | 14 | | `SUPERCHART` | `"superchart"` | 15 | | `UNKNOWN` | `"unknown"` | 16 | 17 | *** 18 | 19 | ### ScaleType 20 | 21 | Ax scale types 22 | 23 | #### Enumeration Members 24 | 25 | | Enumeration Member | Value | 26 | | ------ | ------ | 27 | | `ASINH` | `"asinh"` | 28 | | `CATEGORICAL` | `"categorical"` | 29 | | `DATETIME` | `"datetime"` | 30 | | `FUNCTION` | `"function"` | 31 | | `FUNCTIONLOG` | `"functionlog"` | 32 | | `LINEAR` | `"linear"` | 33 | | `LOG` | `"log"` | 34 | | `LOGIT` | `"logit"` | 35 | | `SYMLOG` | `"symlog"` | 36 | 37 | ## Type Aliases 38 | 39 | ### BarChart 40 | 41 | ```ts 42 | type BarChart: Chart2D & object; 43 | ``` 44 | 45 | #### Type declaration 46 | 47 | | Name | Type | 48 | | ------ | ------ | 49 | | `elements` | `BarData`[] | 50 | | `type` | `ChartType.BAR` | 51 | 52 | *** 53 | 54 | ### BarData 55 | 56 | ```ts 57 | type BarData: object; 58 | ``` 59 | 60 | #### Type declaration 61 | 62 | | Name | Type | 63 | | ------ | ------ | 64 | | `group` | `string` | 65 | | `label` | `string` | 66 | | `value` | `string` | 67 | 68 | *** 69 | 70 | ### BoxAndWhiskerChart 71 | 72 | ```ts 73 | type BoxAndWhiskerChart: Chart2D & object; 74 | ``` 75 | 76 | #### Type declaration 77 | 78 | | Name | Type | 79 | | ------ | ------ | 80 | | `elements` | `BoxAndWhiskerData`[] | 81 | | `type` | `ChartType.BOX_AND_WHISKER` | 82 | 83 | *** 84 | 85 | ### BoxAndWhiskerData 86 | 87 | ```ts 88 | type BoxAndWhiskerData: object; 89 | ``` 90 | 91 | #### Type declaration 92 | 93 | | Name | Type | 94 | | ------ | ------ | 95 | | `first_quartile` | `number` | 96 | | `label` | `string` | 97 | | `max` | `number` | 98 | | `median` | `number` | 99 | | `min` | `number` | 100 | | `outliers` | `number`[] | 101 | | `third_quartile` | `number` | 102 | 103 | *** 104 | 105 | ### Chart 106 | 107 | ```ts 108 | type Chart: object; 109 | ``` 110 | 111 | Represents a chart. 112 | 113 | #### Type declaration 114 | 115 | | Name | Type | 116 | | ------ | ------ | 117 | | `elements` | `any`[] | 118 | | `title` | `string` | 119 | | `type` | `ChartType` | 120 | 121 | *** 122 | 123 | ### ChartTypes 124 | 125 | ```ts 126 | type ChartTypes: 127 | | LineChart 128 | | ScatterChart 129 | | BarChart 130 | | PieChart 131 | | BoxAndWhiskerChart 132 | | SuperChart; 133 | ``` 134 | 135 | *** 136 | 137 | ### LineChart 138 | 139 | ```ts 140 | type LineChart: PointChart & object; 141 | ``` 142 | 143 | #### Type declaration 144 | 145 | | Name | Type | 146 | | ------ | ------ | 147 | | `type` | `ChartType.LINE` | 148 | 149 | *** 150 | 151 | ### PieChart 152 | 153 | ```ts 154 | type PieChart: Chart & object; 155 | ``` 156 | 157 | #### Type declaration 158 | 159 | | Name | Type | 160 | | ------ | ------ | 161 | | `elements` | `PieData`[] | 162 | | `type` | `ChartType.PIE` | 163 | 164 | *** 165 | 166 | ### PieData 167 | 168 | ```ts 169 | type PieData: object; 170 | ``` 171 | 172 | #### Type declaration 173 | 174 | | Name | Type | 175 | | ------ | ------ | 176 | | `angle` | `number` | 177 | | `label` | `string` | 178 | | `radius` | `number` | 179 | 180 | *** 181 | 182 | ### PointData 183 | 184 | ```ts 185 | type PointData: object; 186 | ``` 187 | 188 | #### Type declaration 189 | 190 | | Name | Type | 191 | | ------ | ------ | 192 | | `label` | `string` | 193 | | `points` | [`number` \| `string`, `number` \| `string`][] | 194 | 195 | *** 196 | 197 | ### ScatterChart 198 | 199 | ```ts 200 | type ScatterChart: PointChart & object; 201 | ``` 202 | 203 | #### Type declaration 204 | 205 | | Name | Type | 206 | | ------ | ------ | 207 | | `type` | `ChartType.SCATTER` | 208 | 209 | *** 210 | 211 | ### SuperChart 212 | 213 | ```ts 214 | type SuperChart: Chart & object; 215 | ``` 216 | 217 | #### Type declaration 218 | 219 | | Name | Type | 220 | | ------ | ------ | 221 | | `elements` | `Chart`[] | 222 | | `type` | `ChartType.SUPERCHART` | 223 | 224 | ## Functions 225 | 226 | ### deserializeChart() 227 | 228 | ```ts 229 | function deserializeChart(data: any): Chart 230 | ``` 231 | 232 | #### Parameters 233 | 234 | | Parameter | Type | 235 | | ------ | ------ | 236 | | `data` | `any` | 237 | 238 | #### Returns 239 | 240 | `Chart` 241 | -------------------------------------------------------------------------------- /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.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 | -------------------------------------------------------------------------------- /template/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.12 2 | 3 | RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y --no-install-recommends \ 4 | build-essential curl git util-linux jq sudo fonts-noto-cjk 5 | 6 | # Install Node.js 20.x from NodeSource 7 | RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - && \ 8 | apt-get install -y nodejs 9 | 10 | ENV PIP_DEFAULT_TIMEOUT=100 \ 11 | PIP_DISABLE_PIP_VERSION_CHECK=1 \ 12 | PIP_NO_CACHE_DIR=1 \ 13 | JUPYTER_CONFIG_PATH="/root/.jupyter" \ 14 | IPYTHON_CONFIG_PATH="/root/.ipython" \ 15 | SERVER_PATH="/root/.server" \ 16 | R_VERSION=4.4.2 17 | 18 | ENV R_HOME=/opt/R/${R_VERSION} \ 19 | JAVA_HOME=/opt/java/openjdk 20 | 21 | # Install Jupyter 22 | COPY ./requirements.txt requirements.txt 23 | RUN pip install --no-cache-dir -r requirements.txt && ipython kernel install --name "python3" --user 24 | 25 | # R Kernel 26 | RUN curl -O https://cdn.rstudio.com/r/debian-12/pkgs/r-${R_VERSION}_1_amd64.deb && sudo apt-get update && sudo apt-get install -y ./r-${R_VERSION}_1_amd64.deb && ln -s ${R_HOME}/bin/R /usr/bin/R 27 | RUN R -e "install.packages('IRkernel', repos='https://cloud.r-project.org')" 28 | RUN R -e "IRkernel::installspec(user = FALSE, name = 'r', displayname = 'R')" 29 | 30 | # Javascript Kernel 31 | RUN npm install -g --unsafe-perm git+https://github.com/e2b-dev/ijavascript.git 32 | RUN ijsinstall --install=global 33 | 34 | # Deno Kernel 35 | COPY --from=denoland/deno:bin-2.0.4 /deno /usr/bin/deno 36 | RUN chmod +x /usr/bin/deno 37 | RUN deno jupyter --unstable --install 38 | COPY ./deno.json /root/.local/share/jupyter/kernels/deno/kernel.json 39 | 40 | # Bash Kernel 41 | RUN pip install bash_kernel 42 | RUN python -m bash_kernel.install 43 | 44 | # Create separate virtual environment for server 45 | RUN python -m venv $SERVER_PATH/.venv 46 | 47 | # Copy server and its requirements 48 | RUN mkdir -p $SERVER_PATH/ 49 | COPY ./server/requirements.txt $SERVER_PATH 50 | RUN $SERVER_PATH/.venv/bin/pip install --no-cache-dir -r $SERVER_PATH/requirements.txt 51 | COPY ./server $SERVER_PATH 52 | 53 | # Copy matplotlibrc 54 | COPY matplotlibrc /root/.config/matplotlib/.matplotlibrc 55 | 56 | # Copy Jupyter configuration 57 | COPY ./start-up.sh $JUPYTER_CONFIG_PATH/ 58 | RUN chmod +x $JUPYTER_CONFIG_PATH/start-up.sh 59 | 60 | COPY ./jupyter_server_config.py $JUPYTER_CONFIG_PATH/ 61 | 62 | RUN mkdir -p $IPYTHON_CONFIG_PATH/profile_default 63 | COPY ipython_kernel_config.py $IPYTHON_CONFIG_PATH/profile_default/ 64 | 65 | RUN mkdir -p $IPYTHON_CONFIG_PATH/profile_default/startup 66 | COPY startup_scripts/* $IPYTHON_CONFIG_PATH/profile_default/startup 67 | 68 | 69 | COPY --from=eclipse-temurin:11-jdk $JAVA_HOME $JAVA_HOME 70 | RUN ln -s ${JAVA_HOME}/bin/java /usr/bin/java 71 | 72 | # Java Kernel 73 | RUN wget https://github.com/SpencerPark/IJava/releases/download/v1.3.0/ijava-1.3.0.zip && \ 74 | unzip ijava-1.3.0.zip && \ 75 | python install.py --sys-prefix 76 | 77 | # Setup entrypoint for local development 78 | ENTRYPOINT $JUPYTER_CONFIG_PATH/start-up.sh 79 | -------------------------------------------------------------------------------- /template/README.md: -------------------------------------------------------------------------------- 1 | # Using custom sandbox with Code Interpreter SDK 2 | 3 | If you want to customize the Code Interprerter sandbox (e.g.: add a preinstalled package) you can do that by using a [custom sandbox template](https://e2b.dev/docs/sandbox-template). 4 | 5 | 6 | ## Step-by-step guide 7 | 1. Create custom sandbox by following [this guide](https://e2b.dev/docs/sandbox-template) 8 | 9 | 2. Use prebuilt [E2B Code Interpreter image](https://hub.docker.com/r/e2bdev/code-interpreter) by replacing the `FROM` command in your `e2b.Dockerfile` with following 10 | 11 | ```Dockerfile 12 | FROM e2bdev/code-interpreter:latest 13 | ``` 14 | 15 | 3. Copy [`start-up.sh`](./start-up.sh) to the same directory where's your `e2b.toml` 16 | 17 | 4. Run the following in the same directory where's your `e2b.toml` 18 | ```sh 19 | e2b template build -c "/root/.jupyter/start-up.sh" 20 | ``` 21 | 22 | 5. Use your custom sandbox with Code Interpreter SDK 23 | 24 | **Python** 25 | ```python 26 | from e2b_code_interpreter import Sandbox 27 | sandbox = Sandbox(template="your-custom-sandbox-name") 28 | execution = sandbox.run_code("print('hello')") 29 | sandbox.kill() 30 | 31 | # Or you can use `with` which handles closing the sandbox for you 32 | with Sandbox(template="your-custom-sandbox-name") as sandbox: 33 | execution = sandbox.run_code("print('hello')") 34 | ``` 35 | 36 | 37 | **JavaScript/TypeScript** 38 | 39 | ```js 40 | import {Sandbox} from '@e2b/code-interpreter' 41 | 42 | const sandbox = await Sandbox.create({template: 'your-custom-sandbox-name'}) 43 | const execution = await sandbox.runCode('print("hello")') 44 | await sandbox.kill() 45 | ``` 46 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /template/e2b.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM e2bdev/code-interpreter:latest 2 | -------------------------------------------------------------------------------- /template/e2b.toml: -------------------------------------------------------------------------------- 1 | # This is a config for E2B sandbox template. 2 | # You can use template ID (nlhz8vlwyupq845jsdg9) or template name (code-interpreter-v1) to create a sandbox: 3 | 4 | # Python SDK 5 | # from e2b import Sandbox, AsyncSandbox 6 | # sandbox = Sandbox("code-interpreter-v1") # Sync sandbox 7 | # sandbox = await AsyncSandbox.create("code-interpreter-v1") # Async sandbox 8 | 9 | # JS SDK 10 | # import { Sandbox } from 'e2b' 11 | # const sandbox = await Sandbox.create('code-interpreter-v1') 12 | 13 | team_id = "460355b3-4f64-48f9-9a16-4442817f79f5" 14 | memory_mb = 1_024 15 | start_cmd = "/root/.jupyter/start-up.sh" 16 | dockerfile = "e2b.Dockerfile" 17 | template_name = "code-interpreter-v1" 18 | template_id = "nlhz8vlwyupq845jsdg9" 19 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /template/matplotlibrc: -------------------------------------------------------------------------------- 1 | font.family: sans-serif, Noto Sans CJK JP 2 | -------------------------------------------------------------------------------- /template/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@e2b/code-interpreter-template", 3 | "private": true, 4 | "version": "0.0.11" 5 | } 6 | -------------------------------------------------------------------------------- /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.2.1 10 | 11 | # Latest version for 12 | e2b_charts 13 | 14 | # Other packages 15 | aiohttp==3.11.18 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 | pytest==8.3.5 29 | python-docx==1.1.2 30 | pytz==2025.2 31 | requests==2.32.3 32 | scikit-image==0.25.2 33 | scikit-learn==1.6.1 34 | scipy==1.13.1 # bump blocked by gensim 35 | seaborn==0.13.2 36 | soundfile==0.13.1 37 | spacy==3.8.2 # doesn't work on 3.13.x 38 | textblob==0.19.0 39 | tornado==6.5.1 40 | urllib3==2.4.0 41 | xarray==2025.4.0 42 | xlrd==2.0.1 43 | sympy==1.14.0 44 | -------------------------------------------------------------------------------- /template/server/api/models/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e2b-dev/code-interpreter/85cac9199b9ed5e4b59a4eb9afb7117ccb142640/template/server/api/models/__init__.py -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /template/server/api/models/env_vars.py: -------------------------------------------------------------------------------- 1 | from typing import Dict 2 | from pydantic import StrictStr 3 | 4 | EnvVars = Dict[StrictStr, str] 5 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /template/server/api/models/result.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import warnings 4 | 5 | from typing import Optional, Iterable 6 | from pydantic import BaseModel 7 | 8 | from api.models.output import OutputType 9 | 10 | warnings.filterwarnings("ignore", category=UserWarning) 11 | 12 | 13 | class Result(BaseModel): 14 | """ 15 | Represents the data to be displayed as a result of executing a cell in a Jupyter notebook. 16 | The result is similar to the structure returned by ipython kernel: https://ipython.readthedocs.io/en/stable/development/execution.html#execution-semantics 17 | 18 | The result can contain multiple types of data, such as text, images, plots, etc. Each type of data is represented 19 | as a string, and the result can contain multiple types of data. The display calls don't have to have text representation, 20 | for the actual result the representation is always present for the result, the other representations are always optional. 21 | """ 22 | 23 | type: OutputType = OutputType.RESULT 24 | 25 | text: Optional[str] = None 26 | html: Optional[str] = None 27 | markdown: Optional[str] = None 28 | svg: Optional[str] = None 29 | png: Optional[str] = None 30 | jpeg: Optional[str] = None 31 | pdf: Optional[str] = None 32 | latex: Optional[str] = None 33 | json: Optional[dict] = None 34 | javascript: Optional[str] = None 35 | data: Optional[dict] = None 36 | chart: Optional[dict] = None 37 | extra: Optional[dict] = None 38 | "Extra data that can be included. Not part of the standard types." 39 | 40 | is_main_result: Optional[bool] = None 41 | "Whether this data is the result of the execetution. Data can be produced by display calls of which can be multiple in a cell." 42 | 43 | def __init__(self, is_main_result: bool, data: [str, str]): 44 | super().__init__() 45 | self.is_main_result = is_main_result 46 | 47 | self.text = data.pop("text/plain", None) 48 | if self.text and ( 49 | (self.text.startswith("'") and self.text.endswith("'")) 50 | or (self.text.startswith('"') and self.text.endswith('"')) 51 | ): 52 | self.text = self.text[1:-1] 53 | 54 | self.html = data.pop("text/html", None) 55 | self.markdown = data.pop("text/markdown", None) 56 | self.svg = data.pop("image/svg+xml", None) 57 | self.png = data.pop("image/png", None) 58 | self.jpeg = data.pop("image/jpeg", None) 59 | self.pdf = data.pop("application/pdf", None) 60 | self.latex = data.pop("text/latex", None) 61 | self.json = data.pop("application/json", None) 62 | self.javascript = data.pop("application/javascript", None) 63 | self.data = data.pop("e2b/data", None) 64 | self.chart = data.pop("e2b/chart", None) 65 | self.extra = data 66 | 67 | def formats(self) -> Iterable[str]: 68 | formats = [] 69 | 70 | for key in [ 71 | "text", 72 | "html", 73 | "markdown", 74 | "svg", 75 | "png", 76 | "jpeg", 77 | "pdf", 78 | "latex", 79 | "json", 80 | "javascript", 81 | "data", 82 | "chart", 83 | ]: 84 | if getattr(self, key): 85 | formats.append(key) 86 | 87 | if self.extra: 88 | for key in self.extra: 89 | formats.append(key) 90 | 91 | return formats 92 | 93 | def __str__(self) -> str: 94 | """ 95 | Returns the text representation of the data. 96 | 97 | :return: The text representation of the data. 98 | """ 99 | return self.__repr__() 100 | 101 | def __repr__(self) -> str: 102 | if self.text: 103 | return f"Result({self.text})" 104 | formats = self.formats() 105 | return f"Result with formats: {formats}" 106 | -------------------------------------------------------------------------------- /template/server/consts.py: -------------------------------------------------------------------------------- 1 | JUPYTER_BASE_URL = "http://localhost:8888" 2 | -------------------------------------------------------------------------------- /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 | def get_kernel_for_language(language: str) -> str: 15 | if language == "typescript": 16 | return "javascript" 17 | 18 | return language 19 | 20 | def normalize_language(language: Optional[str]) -> str: 21 | if not language: 22 | return "python" 23 | 24 | language = language.lower().strip() 25 | 26 | if language == "js": 27 | return "javascript" 28 | 29 | if language == "ts": 30 | return "typescript" 31 | 32 | return language 33 | 34 | 35 | async def create_context(client, websockets: dict, language: str, cwd: str) -> Context: 36 | data = { 37 | "path": str(uuid.uuid4()), 38 | "kernel": {"name": get_kernel_for_language(language)}, 39 | "type": "notebook", 40 | "name": str(uuid.uuid4()), 41 | } 42 | logger.debug(f"Creating new {language} context") 43 | 44 | response = await client.post(f"{JUPYTER_BASE_URL}/api/sessions", json=data) 45 | 46 | if not response.is_success: 47 | raise Exception( 48 | f"Failed to create context: {response.text}", 49 | ) 50 | 51 | session_data = response.json() 52 | session_id = session_data["id"] 53 | context_id = session_data["kernel"]["id"] 54 | 55 | logger.debug(f"Created context {context_id}") 56 | 57 | ws = ContextWebSocket(context_id, session_id, language, cwd) 58 | await ws.connect() 59 | websockets[context_id] = ws 60 | 61 | logger.info(f"Setting working directory to {cwd}") 62 | try: 63 | await ws.change_current_directory(cwd, language) 64 | except ExecutionError as e: 65 | return PlainTextResponse( 66 | "Failed to set working directory", 67 | status_code=500, 68 | ) 69 | 70 | return Context(language=language, id=context_id, cwd=cwd) 71 | -------------------------------------------------------------------------------- /template/server/envs.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | import requests 4 | 5 | LOCAL = os.getenv("E2B_LOCAL", False) 6 | ENVD_PORT = 49983 7 | 8 | 9 | def get_envs() -> dict: 10 | if LOCAL: 11 | return {} 12 | return requests.get(f"http://localhost:{ENVD_PORT}/envs").json() 13 | -------------------------------------------------------------------------------- /template/server/errors.py: -------------------------------------------------------------------------------- 1 | class ExecutionError(Exception): 2 | pass 3 | -------------------------------------------------------------------------------- /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.2 6 | pydantic==2.9.1 7 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | response=$(curl -s -X POST "localhost:8888/api/sessions" -H "Content-Type: application/json" -d '{"path": "/home/user", "kernel": {"name": "python3"}, "type": "notebook", "name": "default"}') 17 | status=$(echo "${response}" | jq -r '.kernel.execution_state') 18 | if [[ ${status} != "starting" ]]; then 19 | echo "Error creating kernel: ${response} ${status}" 20 | exit 1 21 | fi 22 | 23 | sudo mkdir -p /root/.jupyter 24 | kernel_id=$(echo "${response}" | jq -r '.kernel.id') 25 | sudo echo "${kernel_id}" | sudo tee /root/.jupyter/kernel_id >/dev/null 26 | sudo echo "${response}" | sudo tee /root/.jupyter/.session_info >/dev/null 27 | 28 | cd /root/.server/ 29 | /root/.server/.venv/bin/uvicorn main:app --host 0.0.0.0 --port 49999 --workers 1 --no-access-log --no-use-colors --timeout-keep-alive 640 30 | } 31 | 32 | echo "Starting Code Interpreter server..." 33 | start_jupyter_server & 34 | MATPLOTLIBRC=/root/.config/matplotlib/.matplotlibrc jupyter server --IdentityProvider.token="" >/dev/null 2>&1 35 | -------------------------------------------------------------------------------- /template/startup_scripts/0001_envs.py: -------------------------------------------------------------------------------- 1 | import copy 2 | import os 3 | import IPython 4 | 5 | 6 | class E2BEnviron(os._Environ): 7 | return_values = {} 8 | keys_to_remove = set() 9 | 10 | def __setitem__(self, key, value): 11 | super().__setitem__(key, value) 12 | self.return_values.pop(key, None) 13 | self.keys_to_remove.discard(key) 14 | 15 | def __delitem__(self, key): 16 | super().__delitem__(key) 17 | self.return_values.pop(key, None) 18 | self.keys_to_remove.discard(key) 19 | 20 | def set_envs_for_execution(self, update=None): 21 | update = update or {} 22 | 23 | return_values = { 24 | key: self[key] for key in set(self.keys()).intersection(update.keys()) 25 | } 26 | keys_to_remove = set(update.keys()).difference(self.keys()) 27 | 28 | self.update(update) 29 | 30 | self.return_values = return_values 31 | self.keys_to_remove = keys_to_remove 32 | 33 | def reset_envs_for_execution(self): 34 | keys_to_remove = copy.copy(self.keys_to_remove) 35 | for key in keys_to_remove: 36 | self.pop(key) 37 | 38 | return_values = copy.copy(self.return_values) 39 | self.update(return_values) 40 | 41 | self.keys_to_remove.clear() 42 | self.return_values.clear() 43 | 44 | 45 | e2b_environ = E2BEnviron( 46 | {}, 47 | os.environ.encodekey, 48 | os.environ.decodekey, 49 | os.environ.encodekey, 50 | os.environ.decodekey, 51 | ) 52 | e2b_environ.update(os.environ) 53 | os.environ = e2b_environ 54 | 55 | 56 | def reset_envs(*args, **kwargs): 57 | try: 58 | if isinstance(os.environ, E2BEnviron): 59 | os.environ.reset_envs_for_execution() 60 | except Exception as e: 61 | print(f"Failed to reset envs: {e}") 62 | 63 | 64 | ip = IPython.get_ipython() 65 | ip.events.register("post_run_cell", reset_envs) 66 | -------------------------------------------------------------------------------- /template/startup_scripts/0002_data.py: -------------------------------------------------------------------------------- 1 | import pandas 2 | from matplotlib.pyplot import Figure 3 | import IPython 4 | from IPython.core.formatters import BaseFormatter, JSONFormatter 5 | from traitlets.traitlets import Unicode, ObjectName 6 | 7 | from e2b_charts import chart_figure_to_dict 8 | import orjson 9 | 10 | 11 | def _figure_repr_e2b_chart_(self: Figure): 12 | """ 13 | This method is used to extract data from the figure object to a dictionary 14 | """ 15 | # Get all Axes objects from the Figure 16 | try: 17 | return chart_figure_to_dict(self) 18 | except: 19 | return {} 20 | 21 | 22 | def _dataframe_repr_e2b_data_(self: pandas.DataFrame): 23 | result = self.to_dict(orient="list") 24 | for key, value in result.items(): 25 | # Check each column's values 26 | result[key] = [ 27 | v.isoformat() if isinstance(v, pandas.Timestamp) else v for v in value 28 | ] 29 | return result 30 | 31 | 32 | class E2BDataFormatter(BaseFormatter): 33 | format_type = Unicode("e2b/data") 34 | 35 | print_method = ObjectName("_repr_e2b_data_") 36 | _return_type = (dict, str) 37 | 38 | type_printers = {pandas.DataFrame: _dataframe_repr_e2b_data_} 39 | 40 | 41 | class E2BChartFormatter(BaseFormatter): 42 | format_type = Unicode("e2b/chart") 43 | 44 | print_method = ObjectName("_repr_e2b_chart_") 45 | _return_type = (dict, str) 46 | 47 | def __call__(self, obj): 48 | # Figure object is for some reason removed on execution of the cell, 49 | # so it can't be used in type_printers or with top-level import 50 | from matplotlib.pyplot import Figure 51 | 52 | if isinstance(obj, Figure): 53 | return _figure_repr_e2b_chart_(obj) 54 | return super().__call__(obj) 55 | 56 | 57 | class E2BJSONFormatter(JSONFormatter): 58 | def __call__(self, obj): 59 | if isinstance(obj, (list, dict)): 60 | try: 61 | return orjson.loads( 62 | orjson.dumps( 63 | obj, option=orjson.OPT_SERIALIZE_NUMPY | orjson.OPT_NON_STR_KEYS 64 | ) 65 | ), {"expanded": True} 66 | except TypeError: 67 | pass 68 | 69 | return super().__call__(obj) 70 | 71 | 72 | ip = IPython.get_ipython() 73 | ip.display_formatter.formatters["e2b/data"] = E2BDataFormatter( 74 | parent=ip.display_formatter 75 | ) 76 | ip.display_formatter.formatters["e2b/chart"] = E2BChartFormatter( 77 | parent=ip.display_formatter 78 | ) 79 | 80 | ip.display_formatter.formatters["application/json"] = E2BJSONFormatter( 81 | parent=ip.display_formatter 82 | ) 83 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /template/test.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.12 2 | 3 | ENV JAVA_HOME=/opt/java/openjdk 4 | COPY --from=eclipse-temurin:11-jdk $JAVA_HOME $JAVA_HOME 5 | ENV PATH="${JAVA_HOME}/bin:${PATH}" 6 | 7 | RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y --no-install-recommends \ 8 | build-essential curl git util-linux jq sudo fonts-noto-cjk 9 | 10 | # Install Node.js 20.x from NodeSource 11 | RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - && \ 12 | apt-get install -y nodejs 13 | 14 | ENV PIP_DEFAULT_TIMEOUT=100 \ 15 | PIP_DISABLE_PIP_VERSION_CHECK=1 \ 16 | PIP_NO_CACHE_DIR=1 \ 17 | JUPYTER_CONFIG_PATH="/root/.jupyter" \ 18 | IPYTHON_CONFIG_PATH="/root/.ipython" \ 19 | SERVER_PATH="/root/.server" 20 | 21 | # Install Jupyter 22 | COPY ./template/requirements.txt requirements.txt 23 | RUN pip install --no-cache-dir -r requirements.txt && ipython kernel install --name "python3" --user 24 | 25 | # Javascript Kernel 26 | RUN npm install -g --unsafe-perm git+https://github.com/e2b-dev/ijavascript.git 27 | RUN ijsinstall --install=global 28 | 29 | # Deno Kernel 30 | COPY --from=denoland/deno:bin-2.0.4 /deno /usr/bin/deno 31 | RUN chmod +x /usr/bin/deno 32 | RUN deno jupyter --unstable --install 33 | COPY ./template/deno.json /root/.local/share/jupyter/kernels/deno/kernel.json 34 | 35 | # Create separate virtual environment for server 36 | RUN python -m venv $SERVER_PATH/.venv 37 | 38 | # Copy server and its requirements 39 | RUN mkdir -p $SERVER_PATH/ 40 | COPY ./template/server/requirements.txt $SERVER_PATH 41 | RUN $SERVER_PATH/.venv/bin/pip install --no-cache-dir -r $SERVER_PATH/requirements.txt 42 | COPY ./template/server $SERVER_PATH 43 | 44 | # Copy matplotlibrc 45 | COPY ./template/matplotlibrc /root/.config/matplotlib/matplotlibrc 46 | 47 | # Copy Jupyter configuration 48 | COPY ./template/start-up.sh $JUPYTER_CONFIG_PATH/ 49 | RUN chmod +x $JUPYTER_CONFIG_PATH/start-up.sh 50 | 51 | COPY ./template/jupyter_server_config.py $JUPYTER_CONFIG_PATH/ 52 | 53 | RUN mkdir -p $IPYTHON_CONFIG_PATH/profile_default 54 | COPY ./template/ipython_kernel_config.py $IPYTHON_CONFIG_PATH/profile_default/ 55 | 56 | RUN mkdir -p $IPYTHON_CONFIG_PATH/profile_default/startup 57 | COPY ./template/startup_scripts/* $IPYTHON_CONFIG_PATH/profile_default/startup 58 | 59 | # Setup entrypoint for local development 60 | WORKDIR /home/user 61 | COPY ./chart_data_extractor ./chart_data_extractor 62 | RUN pip install -e ./chart_data_extractor 63 | ENTRYPOINT $JUPYTER_CONFIG_PATH/start-up.sh 64 | --------------------------------------------------------------------------------