pyduktape2 0.5.0


pip install pyduktape2

  Latest version

Released: Apr 02, 2025

Project Links

Meta
Author: Stefano Dissegna
Requires Python: >=3.6

Classifiers

Development Status
  • 2 - Pre-Alpha

Programming Language
  • Cython
  • Python :: 3
  • JavaScript

Topic
  • Software Development :: Interpreters

Introduction

Pyduktape is a python wrapper around Duktape, an embeddable Javascript interpreter.

On top of the interpreter wrapper, pyduktape offers easy integration between the Python and the Javascript environments. You can pass Python objects to Javascript, call methods on them and access their attributes. Similarly, you can pass Javascript objects to Python.

Objects are never copied or serialized. Instead, they are passed between the two environments using proxy objects. Proxy objects delegate the execution to the original object environment.

Threading

It is possible to invoke Javascript code from multiple threads. Each thread will need to use its own embedded interpreter. Javascript objects returned to the Python environment will only be usable on the same thread that created them. The runtime always checks this condition automatically, and raises a DuktapeThreadError if it’s violated.

Getting Started

Installation

To install from pypi:

$ pip install pyduktape2

To install the latest version from github:

$ pip install git+https://github.com/phith0n/pyduktape2

Running Javascript code

To run Javascript code, you need to create an execution context and use the method eval_js:

import pyduktape2

context = pyduktape2.DuktapeContext()
context.eval_js("print(Duktape.version);")

Each execution context starts its own interpreter. Each context is independent, and tied to the Python thread that created it. Memory is automatically managed.

To evaluate external Javascript files, use eval_js_file:

// helloWorld.js
print('Hello, World!');

# in the Python interpreter
import pyduktape2

context = pyduktape2.DuktapeContext()
context.eval_js_file('helloWorld.js')

Pyduktape supports Javascript modules:

// js/helloWorld.js
exports.sayHello = function () {
    print('Hello, World!');
};

// js/main.js
var helloWorld = require('js/helloWorld');
helloWorld.sayHello();

# in the Python interpreter
import pyduktape2

context = pyduktape2.DuktapeContext()
context.eval_js_file('js/main')

The .js extension is automatically added if missing. Relative paths are relative to the current working directory, but you can change the base path using set_base_path:

# js/helloWorld.js
print('Hello, World!');

# in the Python interpreter
import pyduktape2

context = pyduktape2.DuktapeContext()
context.set_base_path('js')
context.eval_js_file('helloWorld')

Python and Javascript integration

You can use set_globals to set Javascript global variables:

import pyduktape2

def say_hello(to):
    print('Hello, {}!'.format(to))

context = pyduktape2.DuktapeContext()
context.set_globals(sayHello=say_hello, world='World')
context.eval_js("sayHello(world);")

You can use get_global to access Javascript global variables:

import pyduktape2

context = pyduktape2.DuktapeContext()
context.eval_js("var helloWorld = 'Hello, World!';")
print(context.get_global('helloWorld'))

eval_js returns the value of the last expression:

import pyduktape2

context = pyduktape2.DuktapeContext()
hello_world = context.eval_js("var helloWorld = 'Hello, World!'; helloWorld")
print(hello_world)

You can seamlessly use Python objects and functions within Javascript code. There are some limitations, though: any Python callable can only be used as a function, and other attributes cannot be accessed. Primitive types (int, float, string, None) are converted to equivalent Javascript primitives. The following code shows how to interact with a Python object from Javascript:

import pyduktape2

class Hello(object):
    def __init__(self, what):
        self.what = what

    def say(self):
        print('Hello, {}!'.format(self.what))

context = pyduktape2.DuktapeContext()
context.set_globals(Hello=Hello)
context.eval_js("var helloWorld = Hello('World'); helloWorld.say();")

In the same way, you can use Javascript objects in Python. You can use the special method new to instantiate an object:

import pyduktape2

context = pyduktape2.DuktapeContext()
Hello = context.eval_js("""
function Hello(what) {
    this.what = what;
}

Hello.prototype.say = function () {
    print('Hello, ' + this.what + '!');
};

Hello
""")

hello_world = Hello.new('World')
hello_world.say()

You can use Python lists and dicts from Javascript, and viceversa:

import pyduktape2

context = pyduktape2.DuktapeContext()
res = context.eval_js('[1, 2, 3]')

for item in res:
    print(item)

context.set_globals(lst=[4, 5, 6])
context.eval_js('for (var i = 0; i < lst.length; i++) { print(lst[i]); }')

res = context.eval_js('var x = {a: 1, b: 2}; x')
for key, val in res.items():
    print(key, '=', val)
res.c = 3
context.eval_js('print(x.c);')

context.set_globals(x=dict(a=1, b=2))
context.eval_js("""
var items = x.items();
for (var i = 0; i < items.length; i++) {
    print(items[i][0] + ' = ' + items[i][1]);
}
""")
context.set_globals(x=dict(a=1, b=2))
context.eval_js('for (var k in x) { print(k + " = " + x[k]); }')

Wheel compatibility matrix

Platform CPython 3.6 CPython 3.7 CPython 3.8 CPython 3.9 CPython 3.10 CPython 3.11 CPython 3.12 CPython 3.13 PyPy 3.7 (pp73) PyPy 3.8 (pp73) PyPy 3.9 (pp73) PyPy 3.10 (pp73) PyPy 3.11 (pp73)
macosx_10_13_universal2
macosx_10_13_x86_64
macosx_10_15_x86_64
macosx_10_9_universal2
macosx_10_9_x86_64
macosx_11_0_arm64
manylinux1_i686
manylinux2014_aarch64
manylinux2014_i686
manylinux2014_x86_64
manylinux_2_17_aarch64
manylinux_2_17_i686
manylinux_2_17_x86_64
manylinux_2_5_i686
musllinux_1_2_aarch64
musllinux_1_2_i686
musllinux_1_2_x86_64
win32
win_amd64

Files in release

pyduktape2-0.5.0-cp310-cp310-macosx_10_9_universal2.whl (708.2KiB)
pyduktape2-0.5.0-cp310-cp310-macosx_10_9_x86_64.whl (375.1KiB)
pyduktape2-0.5.0-cp310-cp310-macosx_11_0_arm64.whl (341.0KiB)
pyduktape2-0.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (1.8MiB)
pyduktape2-0.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.9MiB)
pyduktape2-0.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (1.8MiB)
pyduktape2-0.5.0-cp310-cp310-musllinux_1_2_aarch64.whl (1.8MiB)
pyduktape2-0.5.0-cp310-cp310-musllinux_1_2_i686.whl (1.9MiB)
pyduktape2-0.5.0-cp310-cp310-musllinux_1_2_x86_64.whl (1.9MiB)
pyduktape2-0.5.0-cp310-cp310-win32.whl (239.7KiB)
pyduktape2-0.5.0-cp310-cp310-win_amd64.whl (286.3KiB)
pyduktape2-0.5.0-cp311-cp311-macosx_10_9_universal2.whl (708.2KiB)
pyduktape2-0.5.0-cp311-cp311-macosx_10_9_x86_64.whl (375.4KiB)
pyduktape2-0.5.0-cp311-cp311-macosx_11_0_arm64.whl (340.8KiB)
pyduktape2-0.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (1.9MiB)
pyduktape2-0.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.9MiB)
pyduktape2-0.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (1.8MiB)
pyduktape2-0.5.0-cp311-cp311-musllinux_1_2_aarch64.whl (1.8MiB)
pyduktape2-0.5.0-cp311-cp311-musllinux_1_2_i686.whl (1.9MiB)
pyduktape2-0.5.0-cp311-cp311-musllinux_1_2_x86_64.whl (1.9MiB)
pyduktape2-0.5.0-cp311-cp311-win32.whl (239.6KiB)
pyduktape2-0.5.0-cp311-cp311-win_amd64.whl (287.2KiB)
pyduktape2-0.5.0-cp312-cp312-macosx_10_13_universal2.whl (705.7KiB)
pyduktape2-0.5.0-cp312-cp312-macosx_10_13_x86_64.whl (374.3KiB)
pyduktape2-0.5.0-cp312-cp312-macosx_11_0_arm64.whl (340.6KiB)
pyduktape2-0.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (1.8MiB)
pyduktape2-0.5.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.9MiB)
pyduktape2-0.5.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (1.8MiB)
pyduktape2-0.5.0-cp312-cp312-musllinux_1_2_aarch64.whl (1.8MiB)
pyduktape2-0.5.0-cp312-cp312-musllinux_1_2_i686.whl (1.9MiB)
pyduktape2-0.5.0-cp312-cp312-musllinux_1_2_x86_64.whl (1.9MiB)
pyduktape2-0.5.0-cp312-cp312-win32.whl (239.1KiB)
pyduktape2-0.5.0-cp312-cp312-win_amd64.whl (286.3KiB)
pyduktape2-0.5.0-cp313-cp313-macosx_10_13_universal2.whl (703.1KiB)
pyduktape2-0.5.0-cp313-cp313-macosx_10_13_x86_64.whl (373.0KiB)
pyduktape2-0.5.0-cp313-cp313-macosx_11_0_arm64.whl (339.4KiB)
pyduktape2-0.5.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (1.8MiB)
pyduktape2-0.5.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.9MiB)
pyduktape2-0.5.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (1.8MiB)
pyduktape2-0.5.0-cp313-cp313-musllinux_1_2_aarch64.whl (1.8MiB)
pyduktape2-0.5.0-cp313-cp313-musllinux_1_2_i686.whl (1.9MiB)
pyduktape2-0.5.0-cp313-cp313-musllinux_1_2_x86_64.whl (1.9MiB)
pyduktape2-0.5.0-cp313-cp313-win32.whl (238.9KiB)
pyduktape2-0.5.0-cp313-cp313-win_amd64.whl (286.0KiB)
pyduktape2-0.5.0-cp36-cp36m-macosx_10_9_x86_64.whl (369.3KiB)
pyduktape2-0.5.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (1.7MiB)
pyduktape2-0.5.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.8MiB)
pyduktape2-0.5.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (1.7MiB)
pyduktape2-0.5.0-cp36-cp36m-musllinux_1_2_aarch64.whl (1.8MiB)
pyduktape2-0.5.0-cp36-cp36m-musllinux_1_2_i686.whl (1.8MiB)
pyduktape2-0.5.0-cp36-cp36m-musllinux_1_2_x86_64.whl (1.9MiB)
pyduktape2-0.5.0-cp36-cp36m-win32.whl (265.7KiB)
pyduktape2-0.5.0-cp36-cp36m-win_amd64.whl (318.2KiB)
pyduktape2-0.5.0-cp37-cp37m-macosx_10_9_x86_64.whl (372.8KiB)
pyduktape2-0.5.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (1.8MiB)
pyduktape2-0.5.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.8MiB)
pyduktape2-0.5.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (1.8MiB)
pyduktape2-0.5.0-cp37-cp37m-musllinux_1_2_aarch64.whl (1.8MiB)
pyduktape2-0.5.0-cp37-cp37m-musllinux_1_2_i686.whl (1.8MiB)
pyduktape2-0.5.0-cp37-cp37m-musllinux_1_2_x86_64.whl (1.9MiB)
pyduktape2-0.5.0-cp37-cp37m-win32.whl (237.9KiB)
pyduktape2-0.5.0-cp37-cp37m-win_amd64.whl (284.7KiB)
pyduktape2-0.5.0-cp38-cp38-macosx_10_9_universal2.whl (707.3KiB)
pyduktape2-0.5.0-cp38-cp38-macosx_10_9_x86_64.whl (374.6KiB)
pyduktape2-0.5.0-cp38-cp38-macosx_11_0_arm64.whl (340.6KiB)
pyduktape2-0.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (1.8MiB)
pyduktape2-0.5.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.9MiB)
pyduktape2-0.5.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (1.8MiB)
pyduktape2-0.5.0-cp38-cp38-musllinux_1_2_aarch64.whl (1.8MiB)
pyduktape2-0.5.0-cp38-cp38-musllinux_1_2_i686.whl (1.9MiB)
pyduktape2-0.5.0-cp38-cp38-musllinux_1_2_x86_64.whl (1.9MiB)
pyduktape2-0.5.0-cp38-cp38-win32.whl (240.0KiB)
pyduktape2-0.5.0-cp38-cp38-win_amd64.whl (286.7KiB)
pyduktape2-0.5.0-cp39-cp39-macosx_10_9_universal2.whl (709.0KiB)
pyduktape2-0.5.0-cp39-cp39-macosx_10_9_x86_64.whl (375.4KiB)
pyduktape2-0.5.0-cp39-cp39-macosx_11_0_arm64.whl (341.4KiB)
pyduktape2-0.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (1.8MiB)
pyduktape2-0.5.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.9MiB)
pyduktape2-0.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (1.8MiB)
pyduktape2-0.5.0-cp39-cp39-musllinux_1_2_aarch64.whl (1.8MiB)
pyduktape2-0.5.0-cp39-cp39-musllinux_1_2_i686.whl (1.9MiB)
pyduktape2-0.5.0-cp39-cp39-musllinux_1_2_x86_64.whl (1.9MiB)
pyduktape2-0.5.0-cp39-cp39-win32.whl (239.8KiB)
pyduktape2-0.5.0-cp39-cp39-win_amd64.whl (286.5KiB)
pyduktape2-0.5.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl (310.5KiB)
pyduktape2-0.5.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl (283.8KiB)
pyduktape2-0.5.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (284.9KiB)
pyduktape2-0.5.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (301.5KiB)
pyduktape2-0.5.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (323.7KiB)
pyduktape2-0.5.0-pp310-pypy310_pp73-win_amd64.whl (273.6KiB)
pyduktape2-0.5.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl (310.9KiB)
pyduktape2-0.5.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl (283.9KiB)
pyduktape2-0.5.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (284.8KiB)
pyduktape2-0.5.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (301.4KiB)
pyduktape2-0.5.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (323.7KiB)
pyduktape2-0.5.0-pp311-pypy311_pp73-win_amd64.whl (273.5KiB)
pyduktape2-0.5.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl (310.3KiB)
pyduktape2-0.5.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (287.5KiB)
pyduktape2-0.5.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (303.9KiB)
pyduktape2-0.5.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (326.4KiB)
pyduktape2-0.5.0-pp37-pypy37_pp73-win_amd64.whl (273.0KiB)
pyduktape2-0.5.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl (310.3KiB)
pyduktape2-0.5.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl (283.8KiB)
pyduktape2-0.5.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (286.0KiB)
pyduktape2-0.5.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (301.9KiB)
pyduktape2-0.5.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (324.3KiB)
pyduktape2-0.5.0-pp38-pypy38_pp73-win_amd64.whl (273.0KiB)
pyduktape2-0.5.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl (310.2KiB)
pyduktape2-0.5.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl (283.6KiB)
pyduktape2-0.5.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (284.8KiB)
pyduktape2-0.5.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (301.3KiB)
pyduktape2-0.5.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (323.4KiB)
pyduktape2-0.5.0-pp39-pypy39_pp73-win_amd64.whl (273.5KiB)
pyduktape2-0.5.0.tar.gz (1.0MiB)
No dependencies