Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/lazy-impalas-accept.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@e2b/code-interpreter-template': patch
---

Add [Deno kernel](https://docs.deno.com/runtime/reference/cli/jupyter/)
80 changes: 80 additions & 0 deletions js/tests/languages/deno.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { expect } from 'vitest'

import { sandboxTest } from '../setup'

sandboxTest('js simple', async ({ sandbox }) => {
const result = await sandbox.runCode('console.log("Hello, World!")', {language: "deno"})

expect(result.logs.stdout.join().trim()).toEqual('Hello, World!')
})

sandboxTest('js import', async ({ sandbox }) => {
const result = await sandbox.runCode('import isOdd from "npm:is-odd"\nisOdd(3)', {language: "deno"})

expect(result.results[0].text).toEqual('true')
})

sandboxTest('js top level await', async ({ sandbox }) => {
const result = await sandbox.runCode(`
async function main() {
return 'Hello, World!'
}

await main()
`, {language: "deno"})
expect(result.results[0].text).toEqual('Hello, World!')
})

sandboxTest('js es6', async ({ sandbox }) => {
const result = await sandbox.runCode(`
const add = (x, y) => x + y;
add(1, 2)`, {language: "deno"})
expect(result.results[0].text).toEqual('3')
})


sandboxTest('js context', async ({ sandbox }) => {
await sandbox.runCode('const z = 1', {language: "deno"})
const result = await sandbox.runCode('z', {language: "deno"})
expect(result.results[0].text).toEqual('1')
})

sandboxTest('js cwd', async ({ sandbox }) => {
const result = await sandbox.runCode('process.cwd()', {language: "deno"})
expect(result.results[0].text).toEqual('/home/user')

const ctx = await sandbox.createCodeContext( {cwd: '/home', language: "deno"})
const result2 = await sandbox.runCode('process.cwd()', {context: ctx})
expect(result2.results[0].text).toEqual('/home')
})

sandboxTest('ts simple', async ({ sandbox }) => {
const result = await sandbox.runCode(`
function subtract(x: number, y: number): number {
return x - y;
}

subtract(1, 2)
`, {language: "deno"})

expect(result.results[0].text).toEqual('-1')
})

sandboxTest('test display', async ({ sandbox }) => {
const result = await sandbox.runCode(`
{
[Symbol.for("Jupyter.display")]() {
return {
// Plain text content
"text/plain": "Hello world!",

// HTML output
"text/html": "<h1>Hello world!</h1>",
}
}
}
`, {language: "deno"})

expect(result.results[0].html).toBe('<h1>Hello world!</h1>')
expect(result.results[0].text).toBe('Hello world!')
})
87 changes: 87 additions & 0 deletions python/tests/languages/test_deno.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
from e2b_code_interpreter import AsyncSandbox


async def test_javascript(async_sandbox: AsyncSandbox):
code = """
console.log('Hello, World!')
"""
execution = await async_sandbox.run_code(code, language="deno")
assert execution.logs.stdout == ["Hello, World!\n"]


async def test_import(async_sandbox: AsyncSandbox):
code = """
import isOdd from 'npm:is-odd'
isOdd(3)
"""
execution = await async_sandbox.run_code(code, language="deno")
assert execution.results[0].text == "true"


async def test_toplevel_await(async_sandbox: AsyncSandbox):
code = """
async function main() {
return 'Hello, World!'
}

await main()
"""
execution = await async_sandbox.run_code(code, language="deno")
assert execution.results[0].text == "Hello, World!"


async def test_es6(async_sandbox: AsyncSandbox):
code = """
const add = (x, y) => x + y;
add(1, 2);
"""
execution = await async_sandbox.run_code(code, language="deno")
assert execution.results[0].text == "3"


async def test_context(async_sandbox: AsyncSandbox):
await async_sandbox.run_code("const x = 1", language="deno")
execution = await async_sandbox.run_code("x", language="deno")
assert execution.results[0].text == "1"


async def test_cwd(async_sandbox: AsyncSandbox):
execution = await async_sandbox.run_code("process.cwd()", language="deno")
assert execution.results[0].text == "/home/user"

ctx = await async_sandbox.create_code_context("/home", language="deno")
execution = await async_sandbox.run_code("process.cwd()", context=ctx)
assert execution.results[0].text == "/home"


async def test_typescript(async_sandbox: AsyncSandbox):
execution = await async_sandbox.run_code(
"""
function subtract(x: number, y: number): number {
return x - y;
}

subtract(1, 2);
""",
language="deno",
)
assert execution.results[0].text == "-1"


async def test_display(async_sandbox: AsyncSandbox):
code = """
{
[Symbol.for("Jupyter.display")]() {
return {
// Plain text content
"text/plain": "Hello world!",

// HTML output
"text/html": "<h1>Hello world!</h1>",
}
}
}
"""
execution = await async_sandbox.run_code(code, language="deno")
assert execution.results[0].text == "Hello world!"
assert execution.results[0].html == "<h1>Hello world!</h1>"
14 changes: 14 additions & 0 deletions python/tests/sync/test_default_kernels.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,20 @@
import pytest

from e2b_code_interpreter.code_interpreter_sync import Sandbox


def test_js_kernel(sandbox: Sandbox):
execution = sandbox.run_code("console.log('Hello, World!')", language="js")
assert execution.logs.stdout == ["Hello, World!\n"]


@pytest.mark.skip_debug()
def test_r_kernel(sandbox: Sandbox):
execution = sandbox.run_code('print("Hello, World!")', language="r")
assert execution.logs.stdout == ['[1] "Hello, World!"\n']


@pytest.mark.skip_debug()
def test_java_kernel(sandbox: Sandbox):
execution = sandbox.run_code('System.out.println("Hello, World!")', language="java")
assert execution.logs.stdout[0] == "Hello, World!"
6 changes: 6 additions & 0 deletions template/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ RUN npm install -g node-gyp
RUN npm install -g --unsafe-perm ijavascript
RUN ijsinstall --install=global

# Deno Kernel
COPY --from=denoland/deno:bin-2.0.4 /deno /usr/bin/deno
RUN chmod +x /usr/bin/deno
RUN deno jupyter --unstable --install
COPY ./deno.json /root/.local/share/jupyter/kernels/deno/kernel.json

# Bash Kernel
RUN pip install bash_kernel
RUN python -m bash_kernel.install
Expand Down
14 changes: 14 additions & 0 deletions template/deno.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"argv": [
"/usr/bin/deno",
"jupyter",
"--kernel",
"--conn",
"{connection_file}"
],
"display_name": "Deno",
"env": {
"NO_COLOR": "1"
},
"language": "typescript"
}
5 changes: 4 additions & 1 deletion template/server/api/models/result.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,10 @@ def __init__(self, is_main_result: bool, data: [str, str]):
self.is_main_result = is_main_result

self.text = data.pop("text/plain", None)
if self.text and self.text.startswith("'") and self.text.endswith("'"):
if self.text and (
(self.text.startswith("'") and self.text.endswith("'"))
or (self.text.startswith('"') and self.text.endswith('"'))
):
self.text = self.text[1:-1]

self.html = data.pop("text/html", None)
Expand Down
5 changes: 2 additions & 3 deletions template/server/contexts.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,8 @@ async def create_context(client, websockets: dict, language: str, cwd: str) -> C
response = await client.post(f"{JUPYTER_BASE_URL}/api/sessions", json=data)

if not response.is_success:
return PlainTextResponse(
raise Exception(
f"Failed to create context: {response.text}",
status_code=500,
)

session_data = response.json()
Expand All @@ -53,7 +52,7 @@ async def create_context(client, websockets: dict, language: str, cwd: str) -> C

logger.info(f"Setting working directory to {cwd}")
try:
await ws.change_current_directory(cwd)
await ws.change_current_directory(cwd, language)
except ExecutionError as e:
return PlainTextResponse(
"Failed to set working directory",
Expand Down
20 changes: 15 additions & 5 deletions template/server/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,13 @@ async def post_execute(request: ExecutionRequest):
context_id = default_websockets.get(language)

if not context_id:
context = await create_context(
client, websockets, language, "/home/user"
)
try:
context = await create_context(
client, websockets, language, "/home/user"
)
except Exception as e:
return PlainTextResponse(str(e), status_code=500)

context_id = context.id
default_websockets[language] = context_id

Expand All @@ -110,7 +114,10 @@ async def post_execute(request: ExecutionRequest):
)

return StreamingListJsonResponse(
ws.execute(request.code, env_vars=request.env_vars)
ws.execute(
request.code,
env_vars=request.env_vars,
)
)


Expand All @@ -121,7 +128,10 @@ async def post_contexts(request: CreateContext) -> Context:
language = normalize_language(request.language)
cwd = request.cwd or "/home/user"

return await create_context(client, websockets, language, cwd)
try:
return await create_context(client, websockets, language, cwd)
except Exception as e:
return PlainTextResponse(str(e), status_code=500)


@app.get("/contexts")
Expand Down
Loading