Skip to content

Runtime

JavaScript runtime.

Each Runtime runs on a dedicated OS thread with its own V8 isolate and provides async-first JavaScript execution with promise support.

Runtime objects are not thread-safe; all methods must be invoked from the thread that created the runtime while holding the Python GIL.

__init__

__init__(config: RuntimeConfig | None = None) -> None

Create a runtime instance with optional configuration.

Parameters:

Name Type Description Default
config RuntimeConfig | None

Optional :class:RuntimeConfig to customize heap limits, bootstrap scripts, inspector, etc.

None

eval

eval(code: str) -> Any

Evaluate JavaScript code synchronously.

This is a convenience method that blocks on the async evaluation. For better performance with promises, use eval_async() instead.

Parameters:

Name Type Description Default
code str

JavaScript source code to evaluate

required

Returns:

Type Description
Any

The native Python representation of the result (int, str, dict, list, etc.)

Raises:

Type Description
RuntimeError

If evaluation fails or times out

JavaScriptError

If JavaScript code throws an exception

Example
>>> runtime = Runtime()
>>> result = runtime.eval("1 + 1")
>>> print(result)
2

eval_async async

eval_async(code: str, *, timeout: float | int | timedelta | None = None) -> Any

Evaluate JavaScript code asynchronously.

This method supports promises and will wait for them to resolve. It's the recommended way to execute JavaScript code.

Parameters:

Name Type Description Default
code str

JavaScript source code to evaluate

required
timeout float | int | timedelta | None

Optional timeout (seconds as float/int, or datetime.timedelta)

None

Returns:

Type Description
Any

The native Python representation of the result (int, str, dict, list, etc.)

Raises:

Type Description
RuntimeError

If evaluation fails

JavaScriptError

If JavaScript code throws an exception

Example
>>> runtime = Runtime()
>>> result = await runtime.eval_async("Promise.resolve(42)")
>>> print(result)
42

register_op

register_op(name: str, handler: Callable[..., Any], *, mode: str = 'sync') -> int

Register a host operation that can be called from JavaScript.

Parameters:

Name Type Description Default
name str

Operation name (must be unique)

required
handler Callable[..., Any]

Python callable that handles the operation

required
mode str

Operation mode ("sync" or "async")

'sync'

Returns:

Type Description
int

An unguessable capability token for the op, usable from

int

JavaScript as __host_op_sync__(token, ...) /

int

__host_op_async__(token, ...). The token is drawn from a

int

CSPRNG and knowing it is the authority to call the op: nothing

int

else reaches the handler, so do not hand it to guest code you do

int

not intend to grant the capability to. (Before v0.2.1 ids were

int

sequential from zero and any registered id was callable, which

int

made the registry ambient.) Revoke it with :meth:revoke_op.

Raises:

Type Description
RuntimeError

If registration fails

Note

Async handlers require an active asyncio context. Call :meth:Runtime.eval_async (or any other async entry point) at least once before invoking the op from JavaScript; otherwise the runtime will raise an error indicating that the event loop is not running.

Example
>>> def add_handler(a, b):
...     return a + b
>>> op_id = runtime.register_op("add", add_handler, mode="sync")
>>> # From JavaScript: __host_op_sync__(op_id, 10, 20)  # Returns 30

revoke_op

revoke_op(op_id: int) -> bool

Revoke an op capability.

Drops the handler and its dispatch entry, so the token stops working even for guest code that already captured the bound function. The global name installed by :meth:bind_function / :meth:bind_object remains, but calling it raises.

Parameters:

Name Type Description Default
op_id int

A token returned by :meth:register_op, :meth:bind_function or :meth:bind_object.

required

Returns:

Type Description
bool

True if a live capability was revoked, False if the token was

bool

already unknown (revoking twice is a no-op, not an error).

is_closed

is_closed() -> bool

Check if the runtime is closed.

Returns:

Type Description
bool

True if the runtime is closed, False otherwise

get_stats

get_stats() -> RuntimeStats

Capture a snapshot of runtime resource usage and execution counters.

Returns:

Name Type Description
RuntimeStats RuntimeStats

Structured metrics describing the runtime state.

inspector_endpoints

inspector_endpoints() -> InspectorEndpoints | None

Return the DevTools endpoints if the inspector is enabled.

Returns:

Name Type Description
InspectorEndpoints InspectorEndpoints | None

describing websocket and devtools:// URLs, or None when the runtime was created without inspector support.

close

close() -> None

Close the runtime and free all resources.

After calling close(), the runtime can no longer be used. This method is called automatically when using the runtime as a context manager.

terminate

terminate() -> None

Forcefully stop any running JavaScript and prevent future execution.

Must be invoked from the same thread that owns the runtime -- calling it (or any other Runtime method) from another thread raises pyo3_runtime.PanicException because Runtime is a PyO3 unsendable pyclass. To kill a runaway eval() from a watchdog thread, call :meth:termination_handle once from the owning thread beforehand and call .terminate() on the returned :class:TerminationHandle instead, which is safe from any thread. After termination, subsequent operations raise RuntimeTerminated.

termination_handle

termination_handle() -> TerminationHandle

Return a :class:TerminationHandle that can safely terminate this runtime's currently running (or next) JS execution from ANY thread, unlike :meth:terminate which panics if called off the owning thread. Intended for a watchdog thread enforcing a timeout on a synchronous eval() call blocking the runtime's owning thread.

Example
>>> runtime = Runtime()
>>> handle = runtime.termination_handle()
>>> import threading
>>> threading.Timer(2.0, handle.terminate).start()
>>> runtime.eval("while(true){}")  # raises within ~2s, no panic

bind_function

bind_function(name: str, handler: Callable[..., Any]) -> int

Expose a Python handler as a global JavaScript function.

Parameters:

Name Type Description Default
name str

Global function name (assigned on globalThis)

required
handler Callable[..., Any]

Python callable invoked when JS calls the function

required

Returns:

Type Description
int

The op's capability token, for :meth:revoke_op.

Note

If handler is async, the runtime must first establish asyncio context via :meth:Runtime.eval_async (or another async entry point). Calling an async-bound function from a purely synchronous evaluation without that context will result in an error about the event loop not running.

Example
>>> runtime = Runtime()
>>> def add(a, b): return a + b
>>> runtime.bind_function("add", add)
>>> runtime.eval("add(1, 2)")
3

stream_from_async_iterable

stream_from_async_iterable(iterable: AsyncIterable[Any]) -> PyStreamSource

Wrap a Python async iterable and expose it to JavaScript as a ReadableStream.

Parameters:

Name Type Description Default
iterable AsyncIterable[Any]

Object implementing __aiter__ that yields JSON-serializable chunks.

required

Returns:

Type Description
PyStreamSource

Handle that can be passed into JavaScript and consumed via stream readers.

bind_object

bind_object(name: str, obj: Mapping[str, Any]) -> dict[str, int]

Expose a Python mapping as a global JavaScript object.

Each key/value pair becomes a property on globalThis[name]. Values that are Python callables are bound as callable JavaScript functions, following the same async detection rules as :meth:bind_function.

Parameters:

Name Type Description Default
name str

Object name assigned on globalThis

required
obj Mapping[str, Any]

Mapping with string keys and JSON-serializable values or callables

required

Returns:

Type Description
dict[str, int]

The capability token of each callable key, for :meth:revoke_op.

dict[str, int]

Non-callable keys are absent.

Example
>>> runtime = Runtime()
>>> def add(a, b):
...     return a + b
>>> runtime.bind_object("api", {"add": add, "value": 42})
>>> runtime.eval("api.value")
42

set_module_resolver

set_module_resolver(resolver: Callable[[str, str], str | None]) -> None

Set a custom module resolver for JavaScript imports.

The resolver function is called whenever JavaScript code attempts to import a module. It receives the module specifier and referrer, and should return a fully-qualified URL or None to fall back to simple static resolution.

Parameters:

Name Type Description Default
resolver Callable[[str, str], str | None]

A callable that takes (specifier, referrer) and returns a fully-qualified URL string or None

required
Note

By default, no modules are loadable. You must either call this method, set_module_loader(), or add_static_module() to enable module loading.

Example
>>> def my_resolver(specifier, referrer):
...     if specifier == "my-lib":
...         return "static:my-lib"
...     return None
>>> runtime.set_module_resolver(my_resolver)

set_module_loader

set_module_loader(loader: Callable[[str], Any]) -> None

Set a custom module loader for JavaScript imports.

The loader function is called to fetch the source code for a module specifier. It should return the module source code as a string, or a coroutine that resolves to the source code for async loading.

Parameters:

Name Type Description Default
loader Callable[[str], Any]

A callable that takes a module specifier and returns the module source code as a string, or an awaitable that resolves to the source code

required
Note

By default, no modules are loadable. You must either call this method, set_module_resolver(), or add_static_module() to enable module loading.

Example
>>> def my_loader(specifier):
...     if specifier == "my-lib":
...         return 'export const value = 42;'
...     raise ValueError(f"Unknown module: {specifier}")
>>> runtime.set_module_loader(my_loader)

add_static_module

add_static_module(name: str, source: str) -> None

Add a static module that can be imported by JavaScript code.

This is syntactic sugar for pre-registering modules without custom resolvers. The module can be imported by its bare name (e.g., lib).

Parameters:

Name Type Description Default
name str

Module name (will be prefixed with static:)

required
source str

JavaScript source code for the module

required
Example
>>> runtime.add_static_module("lib", "export const value = 42;")
>>> result = runtime.eval_module("lib")
>>> print(result["value"])
42

eval_module

eval_module(specifier: str) -> Any

Evaluate a JavaScript module synchronously.

This is a convenience method that blocks on the async module evaluation. For better performance with async modules, use eval_module_async() instead.

Parameters:

Name Type Description Default
specifier str

Module specifier to evaluate

required

Returns:

Type Description
Any

The native Python representation of the module namespace (dict-like object)

Raises:

Type Description
RuntimeError

If module evaluation fails or times out

JavaScriptError

If JavaScript code throws an exception

Example
>>> runtime.add_static_module("lib", "export const value = 42;")
>>> result = runtime.eval_module("lib")
>>> print(result["value"])
42

eval_module_async async

eval_module_async(specifier: str, *, timeout: float | int | timedelta | None = None) -> Any

Evaluate a JavaScript module asynchronously.

This method supports async modules and will wait for them to resolve. It's the recommended way to evaluate modules.

Parameters:

Name Type Description Default
specifier str

Module specifier to evaluate

required
timeout float | int | timedelta | None

Optional timeout (seconds as float/int, or datetime.timedelta)

None

Returns:

Type Description
Any

The native Python representation of the module namespace (dict-like object)

Raises:

Type Description
RuntimeError

If module evaluation fails

JavaScriptError

If JavaScript code throws an exception

Example
>>> runtime.add_static_module("lib", "export const value = 42;")
>>> result = await runtime.eval_module_async("static:lib")
>>> print(result["value"])
42

__enter__

__enter__() -> Self

Context manager entry - returns self.

__exit__

__exit__(exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: TracebackType | None) -> bool

Context manager exit - closes the runtime.