├── .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 | 
6 | 
7 |
8 |
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 |
3 |
4 |
5 |
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 |
3 |
4 |
5 |
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 |
--------------------------------------------------------------------------------