PythonMonkey (GitHub Link) is a Python library designed to integrate the Python and JavaScript ecosystems. It uses Mozilla’s SpiderMonkey engine to execute JavaScript and WebAssembly within Python. This approach allows Python developers to interact with JavaScript libraries, modules, and WebAssembly more efficiently.
Read the Release article: Run JavaScript/WASM in Python: high-level SpiderMonkey bindings to Python with PythonMonkey
Here's a quick demo that uses JavaScript's console.log
function for printing to the console from Python.
import pythonmonkey
pythonmonkey.eval("console.log('Hello from JavaScript!');")
PythonMonkey requires npm
to be installed as well as pip
, then install with:
pip install pythonmonkey
In this example, we'll define a function in a JavaScript file that will add two numbers and then we'll import this JavaScript file into Python and execute it!
// lib.js
function add(a, b) {
return a + b;
}
exports.add = add;
# main.py
import pythonmonkey
js_lib = pythonmonkey.require('./lib')
print( js_lib.add(1,2) ) # 3.0
print( js_lib.add(99,1) ) # 100.0
This example shows a JavaScript object getting defined in JavaScript using pythonmonkey.eval
.
This function evaluated JavaScript code in a JavaScript context and returns it to Python if its a statement.
# This example demonstrates passing an object defined in JavaScript to Python
# and using pythonmonkey.eval to evaluate JavaScript code.
import pythonmonkey as pm
js_obj = pm.eval("({ a: 1, b: () => 2 })")
print(js_obj) # {'a': 1.0, 'b': <built-in method JSFunctionCallable of tuple object at 0x7b5d50926f80>}
print(js_obj.a) # 1.0
print(js_obj['a']) # 1.0
print(js_obj.b()) # 2.0
We'll use Python's asyncio
to provide an event loop for JavaScript to execute Promises.
This allows Python developers to use a familiar library for executing asynchronous JavaScript code!
# This example will demonstrate using asyncio to await a promise which resolves
# after 2 seconds.
import pythonmonkey
import asyncio
async def someAsyncStuff():
two_sec_promise = pythonmonkey.eval("""
new Promise((resolve, reject) => {
setTimeout(resolve, 2000);
});
""")
print("before calling the 2 second timer")
await two_sec_promise
print("two seconds have now passed")
asyncio.run(someAsyncStuff())
Using PythonMonkey, we can execute WebAssembly code in Python and call functions from WebAssembly exports directly from Python. Refer to the following example as reference:
# Executing WebAssembly from Python
#
# PythonMonkey uses SpiderMonkey, which is a JavaScript and WebAssembly engine.
# Using the JavaScript WebAssembly API and calling it from Python using PythonMonkey,
# we can execute WebAssembly easily in Python.
#
# Refer to the MDN documentation for more information on WebAssembly.instantiate
# https://developer.mozilla.org/en-US/docs/WebAssembly/JavaScript_interface/instantiate
import pythonmonkey
import asyncio
WebAssembly = pythonmonkey.WebAssembly
# This is some WebAssembly code which calculates the factorial in a function called
# fac. Typically you would read a file in python and not hard code the bytes into
# the file like this.
wasm_bytes = bytearray(b'\x00asm\x01\x00\x00\x00\x01\x06\x01`\x01|\x01|\x03\x02\x01\x00\x07\x07\x01\x03fac\x00\x00\n.\x01,\x00 \x00D\x00\x00\x00\x00\x00\x00\xf0?c\x04|D\x00\x00\x00\x00\x00\x00\xf0?\x05 \x00 \x00D\x00\x00\x00\x00\x00\x00\xf0?\xa1\x10\x00\xa2\x0b\x0b\x00\x12\x04name\x01\x06\x01\x00\x03fac\x02\x03\x01\x00\x00')
async def getWasmExports(wasm_bytes):
# WebAssembly.instantiate returns a promise which we'll await in python
return (await WebAssembly.instantiate(wasm_bytes, {})).instance.exports
my_wasm_module = asyncio.run(getWasmExports(wasm_bytes))
# execute WebAssembly code in Python!
print(my_wasm_module.fac(4)) # this outputs "24.0" since factorial(4) == 24
print(my_wasm_module.fac(5)) # this outputs "120.0"
print(my_wasm_module.fac(6)) # this outputs "720.0"
Check out the following articles for more WebAssembly in Python using PythonMonkey examples:
PythonMonkey is a groundbreaking library that bridges the Python and JavaScript ecosystems, allowing seamless execution of JavaScript and WebAssembly within Python. Leveraging Mozilla’s SpiderMonkey engine, PythonMonkey ensures high performance, making it possible to harness JavaScript libraries, modules, and even WebAssembly in Python without a significant performance hit. Whether you're importing npm packages, executing WebAssembly, or running JavaScript functions directly in Python, PythonMonkey delivers a smooth experience.
If you like PythonMonkey, consider giving it a star on Github! https://github.com/Distributive-Network/PythonMonkey
Enjoy using PythonMonkey to execute JavaScript code or WASM in Python!
Video version of this article: https://youtu.be/UmlSryXsh30