PiotrDabkowski / Js2Py

JavaScript to Python Translator & JavaScript interpreter written in 100% pure Python🚀 Try it online:
http://piter.io/projects/js2py
MIT License
2.45k stars 259 forks source link

Update README with a suggestion to use PythonMonkey #315

Open wiwichips opened 1 year ago

wiwichips commented 1 year ago

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"
wiwichips commented 1 year ago

Oh Here's more information on PythonMonkey for reference:

milahu commented 6 months ago

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

4144 commented 6 months ago

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

In js2py with some hacks possible create multiply contexts.