Skip to content

Conversation

@wiwichips
Copy link

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"

This commit suggests the usage of PythonMonkey, a Python Library for executing JavaScript in Python. PythonMonkey's API is similar to JS2PYs and its JavaScript engine is fully compatible with the newest updates to JavaScript since it leverages SpiderMonkey. Another interesting side effect of it using SpiderMonkey under the hood is that it also supports WebAssembly for free.
@wiwichips
Copy link
Author

@milahu
Copy link

milahu commented Feb 20, 2024

SpiderMonkey is only a js interpreter (FFI from python to node), but no js2py translator

@4144
Copy link
Contributor

4144 commented Feb 20, 2024

Sadly in PythonMonkey no any kind of context support. One global context for all.

In js2py with some hacks possible create multiply contexts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants