├── .gitignore ├── README.md ├── function-call-eval.py ├── function-passing-eval.py ├── hello-world-eval.py ├── load-wasm-from-py ├── README.md ├── factorial.wasm └── main.py ├── promises ├── README.md ├── async-await-example.js └── main.py ├── require-js-file-from-py ├── README.md ├── main.py └── my-javascript-module.js ├── require-npm-package-from-py ├── README.md ├── main.py ├── package-lock.json └── package.json ├── require-npm-packages ├── README.md ├── main.py ├── package-lock.json ├── package.json └── sha256.js └── require-py-file-from-js ├── README.md ├── main.py ├── my-javascript-module.js └── my-python-module.py /.gitignore: -------------------------------------------------------------------------------- 1 | *node_modules* 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PythonMonkey Examples 2 | 3 | ## What is PythonMonkey 4 | [PythonMonkey](https://pythonmonkey.io/) is a Python library for executing JavaScript in Python 5 | and executing Python in JavaScript. It uses [Mozilla's SpiderMonkey](https://firefox-source-docs.mozilla.org/js/index.html) 6 | JavaScript Engine and shares memory with Python for fast execution. 7 | 8 | Check out [PythonMonkey on GitHub](https://github.com/Distributive-Network/PythonMonkey#pythonmonkey)! 9 | 10 | ## Installation 11 | - requires Python 3.8 or higher 12 | ```bash 13 | pip install pythonmonkey 14 | ``` 15 | 16 | ## Running Examples 17 | - Run the examples via `python3`. Refer to the README.md files in each of the directories for more information. 18 | 19 | ## Examples: 20 | - `hello-world-eval.py` 21 | - A "Hello, World" which evaluates a string in JavaScript 22 | - Run with `python3 hello-world-eval.py` 23 | - `function-call-eval.py` 24 | - Calling a JavaScript function in Python 25 | - Run with `python3 function-call-eval.py` 26 | - `function-passing-eval.py` 27 | - Calling a Python function in a JavaScript function from Python 28 | - Run with `python3 function-passing-eval.py` 29 | - `require-js-file-from-py/` 30 | - Loading a JavaScript module from Python 31 | - `require-py-file-from-js/` 32 | - Loading a Python module from JavaScript 33 | - `require-npm-package-from-py/` 34 | - Using an NPM package directly from Python 35 | - `require-npm-packages/` 36 | - Calling JavaScript code that uses NPM modules 37 | - `load-wasm-from-py/` 38 | - Loading a WebAssembly module in Python and calling WASM function 39 | - `promises/` 40 | - Using JavaScript promises in Python 41 | 42 | ## Fullstack Example using CryptoJS 43 | For a more in depth example using the CryptoJS NPM package, refer to [https://github.com/Distributive-Network/PythonMonkey-Crypto-JS-Fullstack-Example](https://github.com/Distributive-Network/PythonMonkey-Crypto-JS-Fullstack-Example/). 44 | -------------------------------------------------------------------------------- /function-call-eval.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | This example demonstrates calling a JavaScript function from Python. 4 | A simple function is defined in JavaScript which just returns the 5 | number 3. 6 | """ 7 | 8 | import pythonmonkey as pm 9 | my_JS_function = pm.eval(" () => { return 3; }") 10 | print(my_JS_function()) 11 | 12 | -------------------------------------------------------------------------------- /function-passing-eval.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | This example demonstrates passing functions as arguments. Here, a 4 | function is defined in JavaScript which expects a function as an 5 | argument. Then that JavaScript function is executed from Python and 6 | the Python `print` function is passed as an argument. 7 | """ 8 | 9 | import pythonmonkey as pm 10 | hello = pm.eval("(func) => { func('Hello, World!'); }") 11 | hello(print) # this outputs "Hello, World!" 12 | 13 | -------------------------------------------------------------------------------- /hello-world-eval.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | This example returns a "HELLO, WORLD!" string created in JavaScript 4 | using `pm.eval` for execting the JavaScript code. 5 | The string is set to uppercase using JavaScript's `toUpperCase` 6 | function. 7 | """ 8 | 9 | import pythonmonkey as pm 10 | hello = pm.eval(" 'Hello, World!'.toUpperCase(); ") 11 | print(hello) # this outputs "HELLO, WORLD!" 12 | 13 | -------------------------------------------------------------------------------- /load-wasm-from-py/README.md: -------------------------------------------------------------------------------- 1 | # Load WebAssembly from Python 2 | 3 | This example demonstrates running [WebAssembly](https://developer.mozilla.org/en-US/docs/WebAssembly) code from Python using 4 | PythonMonkey. 5 | 6 | There are two files used in this example: `factorial.wasm` and 7 | `main.py`. 8 | 9 | `factorial.wasm` is a WebAssembly binary program for calculating the 10 | nth factorial. It exposes a function `fac(n)`. 11 | 12 | `main.py` is the entry point of this example. This program reads 13 | `factorial.wasm` and uses JavaScript to compile and instantiate it. 14 | Then it calls the `fac(n)` function directly from Python. 15 | 16 | ## Factorial Problem 17 | For more information on Factorials, refer to [https://en.wikipedia.org/wiki/Factorial](https://en.wikipedia.org/wiki/Factorial) 18 | 19 | ## Factorial Source Code 20 | Here is the source code for `factorial.wasm` written in WebAssembly 21 | Text. 22 | 23 | ```wat 24 | (module 25 | (func $fac (export "fac") (param f64) (result f64) 26 | local.get 0 27 | f64.const 1 28 | f64.lt 29 | if (result f64) 30 | f64.const 1 31 | else 32 | local.get 0 33 | local.get 0 34 | f64.const 1 35 | f64.sub 36 | call $fac 37 | f64.mul 38 | end)) 39 | ``` 40 | 41 | -------------------------------------------------------------------------------- /load-wasm-from-py/factorial.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Distributive-Network/pythonmonkey-examples/c9dd5034e14a6bd93ee84f70f3d0678f553ca927/load-wasm-from-py/factorial.wasm -------------------------------------------------------------------------------- /load-wasm-from-py/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | This example uses the JavaScript WebAssembly API to compile and 4 | instantiate the `factorial.wasm` file and return the "fac" function. 5 | """ 6 | 7 | import asyncio 8 | import pythonmonkey as pm 9 | 10 | # get the global WebAssembly object 11 | WebAssembly = pm.eval('WebAssembly') 12 | 13 | async def async_fn(): 14 | # read the factorial.wasm binary file 15 | file = open('factorial.wasm', 'rb') 16 | wasm_bytes = bytearray(file.read()) 17 | 18 | # instantiate the WebAssembly code 19 | wasm_fact = await WebAssembly.instantiate(wasm_bytes, {}) 20 | 21 | # return the "fac" factorial function from the wasm module 22 | return wasm_fact.instance.exports.fac; 23 | 24 | # await the promise which returns the factorial WebAssembly function 25 | factorial = asyncio.run(async_fn()) 26 | 27 | # execute WebAssembly code in Python! 28 | print(factorial(4)) # this outputs "24.0" since factorial(4) == 24 29 | print(factorial(5)) # this outputs "120.0" 30 | print(factorial(6)) # this outputs "720.0" 31 | 32 | -------------------------------------------------------------------------------- /promises/README.md: -------------------------------------------------------------------------------- 1 | # Use JavaScript Promises in Python 2 | 3 | This example demonstrates using JavaScript promsies in Python with 4 | Python's [asyncio library](https://docs.python.org/3/library/asyncio.html). 5 | 6 | There are two files used in this example: `async-await-example.js` and 7 | `main.py`. 8 | 9 | `async-await-example.js` is a JavaScript module that contains a single 10 | async function which returns a promise that resolves after 3 seconds 11 | and returns the current unix time. 12 | 13 | `main.py` is the entry point of this example. This program 14 | demonstrates awaiting JavaScript promises defined from both `pm.eval()` 15 | and from a JavaScript async function. 16 | 17 | ## Related Examples 18 | Refer to the WebAssembly example for another example involving 19 | awaiting JavaScript promises in Python. 20 | 21 | -------------------------------------------------------------------------------- /promises/async-await-example.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This function returns a JavaScript promise which resolves after 3 | * 3 seconds with the current unix timestamp in seconds. 4 | */ 5 | async function exampleAsyncFunc() { 6 | // create a promise that resolves in 3000 with the current date 7 | const somePromise = new Promise((resolve, reject) => { 8 | setTimeout(() => { 9 | resolve(new Date()) 10 | }, 3000) 11 | }); 12 | 13 | // await the promise defined above 14 | const time = await somePromise; 15 | 16 | // return the unix time in seconds 17 | return Math.trunc(time.getTime() / 1000); 18 | } 19 | 20 | module.exports = exampleAsyncFunc; 21 | 22 | -------------------------------------------------------------------------------- /promises/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | This example demonstrates JavaScript promises interacting with Python 4 | using Python's asyncio library. 5 | 6 | For an additional example using a real world example of promises, 7 | refer to the WebAssembly example. 8 | """ 9 | import pythonmonkey as pm 10 | import asyncio 11 | import time 12 | 13 | async_await_example = pm.require("./async-await-example") 14 | 15 | async def main(): 16 | # create a JavaScript promise which resolves after 1 second (1000 milliseconds) 17 | my_awesome_promise = pm.eval("new Promise((resolve, reject) => { setTimeout(resolve, 1000); })") 18 | await my_awesome_promise # await the promise 19 | print("1 second later") # this will output one second after the line above was invoked 20 | 21 | # This example awaits another promise that returns the current time after 3 seconds 22 | print(int(time.time())) # will output the current unix time in seconds 23 | current_unix_time = await async_await_example() # awaits for 3 seconds 24 | print(current_unix_time) # will output the current unix time in seconds 25 | 26 | asyncio.run(main()) 27 | 28 | -------------------------------------------------------------------------------- /require-js-file-from-py/README.md: -------------------------------------------------------------------------------- 1 | # Require JavaScript File From Python 2 | 3 | This examples demonstrates requiring a JavaScript file from Python. 4 | 5 | `main.py` is the entry point of this example. 6 | `my-javascript-module.js` contains JavaScript code that prints: 7 | "hello world" using `console.log`. 8 | 9 | -------------------------------------------------------------------------------- /require-js-file-from-py/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import pythonmonkey as pm 3 | 4 | test = pm.require('./my-javascript-module'); 5 | test.sayHello() # this outputs "hello, world" 6 | 7 | -------------------------------------------------------------------------------- /require-js-file-from-py/my-javascript-module.js: -------------------------------------------------------------------------------- 1 | exports.sayHello = function sayHello () { 2 | console.log('hello, world') 3 | }; 4 | -------------------------------------------------------------------------------- /require-npm-package-from-py/README.md: -------------------------------------------------------------------------------- 1 | # Require NPM Packages from Python 2 | 3 | This example demonstrates requiring NPM packages from Python. 4 | 5 | In order to run this example, first install the NPM packages 6 | specified in the `package.json` file by running th following command: 7 | `$ npm install` 8 | 9 | For information on how to install NPM, refre to [https://nodejs.org/en/download](https://nodejs.org/en/download) 10 | 11 | `main.py` is the entry point of this example. This program usese 12 | `require` to load the JavaScript module [is-odd](https://www.npmjs.com/package/is-odd) 13 | 14 | -------------------------------------------------------------------------------- /require-npm-package-from-py/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | This example demonstrates requiring an NPM package from Python. The 4 | "is-odd" (https://www.npmjs.com/package/is-odd) is used. Please refer 5 | to the README file in this directory for instructions on how to 6 | install it. 7 | """ 8 | 9 | import pythonmonkey as pm 10 | 11 | isOdd = pm.require("is-odd") 12 | 13 | print(isOdd(7)) # This will output False 14 | print(isOdd(2048)) # This will output True 15 | 16 | -------------------------------------------------------------------------------- /require-npm-package-from-py/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "require-npm-package-from-py", 3 | "lockfileVersion": 3, 4 | "requires": true, 5 | "packages": { 6 | "": { 7 | "dependencies": { 8 | "is-odd": "^3.0.1" 9 | } 10 | }, 11 | "node_modules/is-number": { 12 | "version": "6.0.0", 13 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-6.0.0.tgz", 14 | "integrity": "sha512-Wu1VHeILBK8KAWJUAiSZQX94GmOE45Rg6/538fKwiloUu21KncEkYGPqob2oSZ5mUT73vLGrHQjKw3KMPwfDzg==", 15 | "engines": { 16 | "node": ">=0.10.0" 17 | } 18 | }, 19 | "node_modules/is-odd": { 20 | "version": "3.0.1", 21 | "resolved": "https://registry.npmjs.org/is-odd/-/is-odd-3.0.1.tgz", 22 | "integrity": "sha512-CQpnWPrDwmP1+SMHXZhtLtJv90yiyVfluGsX5iNCVkrhQtU3TQHsUWPG9wkdk9Lgd5yNpAg9jQEo90CBaXgWMA==", 23 | "dependencies": { 24 | "is-number": "^6.0.0" 25 | }, 26 | "engines": { 27 | "node": ">=4" 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /require-npm-package-from-py/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "is-odd": "^3.0.1" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /require-npm-packages/README.md: -------------------------------------------------------------------------------- 1 | # Require NPM Packages 2 | 3 | This example demonstrates requiring NPM packages. The [CryptoJS](https://www.npmjs.com/package/crypto-js) module 4 | is loaded from `sha256.js` using `require` and a function `sha256()` 5 | is exported which converts strings to [sha256 hashes](https://en.wikipedia.org/wiki/SHA-256). 6 | 7 | In order to run this example, first install the NPM packages 8 | specified in the `package.json` file by running th following command: 9 | `$ npm install` 10 | 11 | For information on how to install NPM, refre to [https://nodejs.org/en/download](https://nodejs.org/en/download) 12 | 13 | `main.py` is the entry point of this example. 14 | 15 | -------------------------------------------------------------------------------- /require-npm-packages/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | This example requires a JavaScript file that itself requires an NPM 4 | module called CryptoJS. That file exports a function called `sha256` 5 | which will return the sha256 hash of a string entered. 6 | """ 7 | import pythonmonkey as pm 8 | 9 | sha256 = pm.require("./sha256") 10 | 11 | print(sha256("Hello, World!")) # this outputs dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986f 12 | 13 | -------------------------------------------------------------------------------- /require-npm-packages/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "require-npm-packages", 3 | "lockfileVersion": 3, 4 | "requires": true, 5 | "packages": { 6 | "": { 7 | "dependencies": { 8 | "crypto-js": "^4.2.0" 9 | } 10 | }, 11 | "node_modules/crypto-js": { 12 | "version": "4.2.0", 13 | "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", 14 | "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==" 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /require-npm-packages/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "crypto-js": "^4.2.0" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /require-npm-packages/sha256.js: -------------------------------------------------------------------------------- 1 | const CryptoJS = require("crypto-js"); 2 | 3 | module.exports = function sha256(thing) { 4 | return CryptoJS.SHA256(thing).toString() 5 | } 6 | 7 | -------------------------------------------------------------------------------- /require-py-file-from-js/README.md: -------------------------------------------------------------------------------- 1 | # Require Python File From JavaScript 2 | 3 | This example demonstrates loading Python modules from JavaScript 4 | using `require`. 5 | 6 | This example uses three files: 7 | `main.py` 8 | `my-javascript-module.js` 9 | `my-python-module.py` 10 | 11 | `main.py` requires `my-javascript-module.js` which requires `my-python-module.py`. 12 | 13 | -------------------------------------------------------------------------------- /require-py-file-from-js/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # @file main.py 3 | # Sample code which demonstrates how to use require 4 | # @author Wes Garland, wes@distributive.network 5 | # @date Jun 2023 6 | 7 | import sys, os 8 | import pythonmonkey as pm 9 | 10 | pm.require('./my-javascript-module'); 11 | 12 | -------------------------------------------------------------------------------- /require-py-file-from-js/my-javascript-module.js: -------------------------------------------------------------------------------- 1 | const { helloWorld } = require('./my-python-module'); 2 | helloWorld() 3 | 4 | -------------------------------------------------------------------------------- /require-py-file-from-js/my-python-module.py: -------------------------------------------------------------------------------- 1 | def helloWorld(): 2 | print('hello, world!') 3 | 4 | exports['helloWorld'] = helloWorld 5 | 6 | --------------------------------------------------------------------------------