Skip to content

Quick Start

Installation

Create or activate a virtual environment inside your project and install the package:

python -m venv .venv
source .venv/bin/activate

pip install pydeno  # or `uv install pydeno`

Platform Support

Supports macOS (Apple Silicon) and Linux (x86_64, ARM64) with glibc (manylinux). Windows and musl-based distributions (e.g., Alpine) are not supported currently.

Start here: Pydeno

For code you did not write (an agent's, a user's), use Pydeno: a pool of pre-started workers, each in its own OS sandbox and used for one session only. It has the same shape as Monty's Monty.

from pydeno import Pydeno

with Pydeno() as pool:
    with pool.checkout() as session:
        session.feed_run("const x = 20")
        session.feed_run("x + 1")                                   # 21
        session.feed_run("await lookup(7)", external_lookup={"lookup": lambda i: i * 6})  # 42
from pydeno import AsyncPydeno

async with AsyncPydeno() as pool:
    async with pool.checkout() as session:
        await session.feed_run("1 + 1")                             # 2

The front-door guide covers the defaults, limits, errors, snapshots and the Monty-to-pydeno mapping. The rest of this page is the in-process Runtime, for code you trust.

Run JavaScript from Python

Use pydeno.eval to evaluate JavaScript code directly:

>>> import pydeno
>>>
>>> print(pydeno.eval("2 + 2"))
4
>>> print(pydeno.eval("Math.sqrt(25)"))
5

pydeno.eval() runs synchronously and returns the result immediately.

Run JavaScript from the command line

The pydeno command evaluates an expression in the sandboxed worker and prints the result as JSON:

$ pydeno '[1, 2, 3].map(x => x * 2)'
[2, 4, 6]
$ echo 'Promise.resolve("done")' | pydeno --raw
done

It exits non-zero on a JavaScript error, with the error on stderr. See Command line for --timeout, --max-memory, --raw and the exit codes.

Share functions and data

Bind Python callables or objects so they are visible from JavaScript:

import pydeno

pydeno.bind_function("notify", lambda msg: print("JS:", msg))
pydeno.eval("notify('hello from JS')")

pydeno.bind_object("config", {"debug": True})
pydeno.eval("config.debug")

Once bound, they will remain available to all subsequent evaluations.

Run code asynchronously

Use eval_async to run JavaScript without blocking Python’s event loop. This is useful when JavaScript performs long-running work or returns a Promise.

import asyncio

async def main():
    # JavaScript expression
    result = await pydeno.eval_async("42")

    # Code that returns a Promise is also supported
    result = await pydeno.eval_async("Promise.resolve('done')")
    print(result)

asyncio.run(main())

Keep types familiar

pydeno automatically converts common data types between Python and JavaScript, so you can work with familiar types on both sides. Numbers, strings, booleans, lists, dictionaries, and more are converted seamlessly.

# Python → JavaScript → Python
result = pydeno.eval("[1, 2, 3].map(x => x * 2)")
print(result)  # [2, 4, 6]

For complete details on type conversion, including special types like undefined, BigInt, Date, and binary data, see Type Conversion.

Working with Runtime directly

pydeno vs. Runtime

The pydeno module provides a convenient interface that automatically manages a context-local Runtime for you. Each asyncio task or thread gets its own isolated runtime instance, created lazily and cleaned up automatically. This makes it perfect for everyday use where you just want to run JavaScript without managing runtime lifecycle.

For more control, you can work with the Runtime class directly:

from pydeno import Runtime

runtime = Runtime()  # Create a runtime instance

runtime.eval("let counter = 0")
runtime.eval("counter++")
print(runtime.eval("counter"))  # 1

runtime.close()  # Clean up when done

Or use it as a context manager for automatic cleanup:

with Runtime() as runtime:
    print(runtime.eval("42"))

Each Runtime runs on a dedicated thread with its own V8 isolate, where state persists across evaluations.

Next steps