Update README with a suggestion to use PythonMonkey
This Pull Request suggests the usage of PythonMonkey, a Python Library for executing JavaScript in Python.
I'm happy to receive any feedback on this suggestion and modify it wherever appropriate.
PythonMonkey's API is similar to Js2Py's and its JavaScript engine is fully compatible with the newest updates to JavaScript since it leverages SpiderMonkey.
Below I'll list some examples using PythonMonkey to serve as a rationale for why it should be recommended in Js2Py's README.
Check out this Google Colab for examples on how to use PythonMonkey: https://colab.research.google.com/drive/1INshyn0gNMgULQVtXlQWK1QuDGwdgSGZ?usp=sharing
Installation
Install with:
$ pip3 install pythonmonkey
(works with Python 3.8+ and requires npm to be installed on the system during install).
Simple Examples
toUpperCase Example:
>>> import pythonmonkey as pm
>>> hello = pm.eval(" 'Hello World'.toUpperCase(); ")
>>> print(hello)
'HELLO WORLD'
Passing a Function Example:
PythonMonkey supports arbitrarily deeply nested JS->Py->JS->Py->... function calling between Python and JavaScript functions.
>>> import pythonmonkey as pm
>>> hello = pm.eval("(func) => { func('Hello World!')}")
>>> hello(print)
Hello World!
Loading a JavaScript Module in Python Example:
my-javascript-module.js
exports.sayHello = () => { console.log('hello, world') };
main.py
import pythonmonkey as pm
test = pm.require('./my-javascript-module');
test.sayHello() # this prints hello, world
Python Loading a JavaScript Module Loading a Python Module Using CommonJS Example:
my-python-module.py
def getStringLength(s):
return len(s)
exports['getStringLength'] = getStringLength
my-javascript-module.js
const { getStringLength } = require('./my-python-module');
function printStringLength(s) {
console.log(`String: "${s}" has a length of ${getStringLength(s)}`);
}
module.exports = { printStringLength, };
main.py
import pythonmonkey as pm
test = pm.require('./my-javascript-module');
test.printStringLength("Hello, world!") # String: "Hello, world!" has a length of 13
WebAssembly & Promise Example
Another interesting side effect of it using SpiderMonkey under the hood is that it also supports WebAssembly for free.
Here is an example:
import asyncio # we'll use asyncio to deal with an event loop
import pythonmonkey
# we'll put our code in an async python function
async def async_fn():
# read the factorial.wasm binary file
file = open('factorial.wasm', 'rb')
wasm_bytes = bytearray(file.read())
# instantiate the WebAssembly code
wasm_fact = await pythonmonkey.WebAssembly.instantiate(wasm_bytes, {})
# return the "fac" factorial function from the wasm module
return wasm_fact.instance.exports.fac;
# await the promise which returns the factorial WebAssembly function
factorial = asyncio.run(async_fn())
# execute WebAssembly code in Python!
print(factorial(4)) # this outputs "24.0" since factorial(4) == 24
print(factorial(5)) # this outputs "120.0"
print(factorial(6)) # this outputs "720.0"
Oh Here's more information on PythonMonkey for reference:
- GitHub: https://github.com/Distributive-Network/PythonMonkey
- Release article I wrote: https://medium.com/@willkantorpringle/pythonmonkey-javascript-wasm-interop-in-python-using-spidermonkey-bindings-4a8efce2e598
SpiderMonkey is only a js interpreter (FFI from python to node), but no js2py translator
Sadly in PythonMonkey no any kind of context support. One global context for all.
In js2py with some hacks possible create multiply contexts.