PythonMonkey
A Mozilla SpiderMonkey JavaScript engine embedded into the Python VM, using the Python engine to provide the JS host environment.
Install / Use
/learn @Distributive-Network/PythonMonkeyREADME
PythonMonkey
About
PythonMonkey is a Mozilla SpiderMonkey JavaScript engine embedded into the Python Runtime, using the Python engine to provide the Javascript host environment.
We feature JavaScript Array and Object methods implemented on Python List and Dictionaries using the cPython C API, and the inverse using the Mozilla Firefox Spidermonkey JavaScript C++ API.
This project has reached MVP as of September 2024. It is under maintenance by Distributive.
External contributions and feedback are welcome and encouraged.
tl;dr
$ pip install pythonmonkey
from pythonmonkey import eval as js_eval
js_eval("console.log")('hello, world')
Goals
- Fast and memory-efficient
- Make writing code in either JS or Python a developer preference
- Use JavaScript libraries from Python
- Use Python libraries from JavaScript
- The same process runs both JavaScript and Python VirtualMachines - no serialization, pipes, etc
- Python Lists and Dicts behave as Javacript Arrays and Objects, and vice-versa, fully adapting to the given context.
Data Interchange
- Strings share immutable backing stores whenever possible (when allocating engine choses UCS-2 or Latin-1 internal string representation) to keep memory consumption under control, and to make it possible to move very large strings between JavaScript and Python library code without memory-copy overhead.
- TypedArrays share mutable backing stores.
- JS objects are represented by Python dicts through a Dict subclass for optimal compatibility. Similarly for JS arrays and Python lists.
- JS Date objects are represented by Python datetime.datetime objects
- Intrinsics (boolean, number, null, undefined) are passed by value
- JS Functions are automatically wrapped so that they behave like Python functions, and vice-versa
- Python Lists are represented by JS true arrays and support all Array methods through a JS API Proxy. Similarly for Python Dicts and JS objects.
Roadmap
- [done] JS instrinsics coerce to Python intrinsics
- [done] JS strings coerce to Python strings
- [done] JS objects coerce to Python dicts [own-properties only]
- [done] JS functions coerce to Python function wrappers
- [done] JS exceptions propagate to Python
- [done] Implement
eval()function in Python which accepts JS code and returns JS->Python coerced values - [done] NodeJS+NPM-compatible CommonJS module system
- [done] Python strings coerce to JS strings
- [done] Python intrinsics coerce to JS intrinsics
- [done] Python dicts coerce to JS objects
- [done] Python
requirefunction, returns a coerced dict of module exports - [done] Python functions coerce to JS function wrappers
- [done] CommonJS module system .py loader, loads Python modules for use by JS
- [done] Python host environment supplies event loop, including EventEmitter, setTimeout, etc.
- [done] Python host environment supplies XMLHttpRequest
- [done] Python TypedArrays coerce to JS TypeArrays
- [done] JS TypedArrays coerce to Python TypeArrays
- [done] Python lists coerce to JS Arrays
- [done] JS arrays coerce to Python lists
- [done] PythonMonkey can run the dcp-client npm package from Distributive.
Build Instructions
Read this if you want to build a local version.
-
You will need the following installed (which can be done automatically by running
./setup.sh):- bash
- cmake
- Doxygen 1.9 series (if you want to build the docs)
- graphviz (if you want to build the docs)
- llvm
- rust
- python3.8 or later with header files (python3-dev)
- spidermonkey latest from mozilla-central
- npm (nodejs)
- Poetry
- poetry-dynamic-versioning
-
Run
poetry install. This command automatically compiles the project and installs the project as well as dependencies into the poetry virtualenv. If you would like to build the docs, set theBUILD_DOCSenvironment variable, like so:BUILD_DOCS=1 poetry install. PythonMonkey supports multiple build types, which you can build by setting theBUILD_TYPEenvironment variable, like so:BUILD_TYPE=Debug poetry install. The build types are (case-insensitive):
Release: stripped symbols, maximum optimizations (default)DRelease: same asRelease, except symbols are not strippedDebug: minimal optimizationsSanitize: same asDebug, except with AddressSanitizer enabledProfile: same asDebug, except profiling is enabledNone: don't compile (useful if you only want to build the docs)
If you are using VSCode, you can just press <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>B</kbd> to run build task - We have the tasks.json file configured for you.
Running tests
- Compile the project
- Install development dependencies:
poetry install --no-root --only=dev - From the root directory, run
poetry run pytest ./tests/python - From the root directory, run
poetry run bash ./peter-jr ./tests/js/
For VSCode users, similar to the Build Task, we have a Test Task ready to use.
Using the library
npm (Node.js) is required during installation only to populate the JS dependencies.
Install from PyPI
$ pip install pythonmonkey
Install the nightly build
$ pip install --extra-index-url https://nightly.pythonmonkey.io/ --pre pythonmonkey
Use local version
pythonmonkey is available in the poetry virtualenv once you compiled the project using poetry.
$ poetry run python
Python 3.10.6 (main, Nov 14 2022, 16:10:14) [GCC 11.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import pythonmonkey as pm
>>> hello = pm.eval("() => {return 'Hello from Spidermonkey!'}")
>>> hello()
'Hello from Spidermonkey!'
Alternatively, you can build installable packages by running
$ cd python/pminit && poetry build --format=sdist && cd - && mv -v python/pminit/dist/* ./dist/
$ poetry build --format=wheel
and install them by pip install ./dist/*.
Uninstallation
Installing pythonmonkey will also install the pminit package as a dependency. However, pip uninstalling a package won't automatically remove its dependencies.
If you want to cleanly remove pythonmonkey from your system, do the following:
$ pip uninstall pythonmonkey pminit
Debugging Steps
- build the project locally
- To use gdb, run
poetry run gdb python. See Python Wiki: DebuggingWithGdb
If you are using VSCode, it's more convenient to debug in VSCode's built-in debugger. Simply press <kbd>F5</kbd> on an open Python file in the editor to start debugging - We have the launch.json file configured for you.
Examples
- examples/
- https://github.com/Distributive-Network/PythonMonkey-examples
- https://github.com/Distributive-Network/PythonMonkey-Crypto-JS-Fullstack-Example
Official API
These methods are exported from the pythonmonkey module. See definitions in python/pythonmonkey/pythonmonkey.pyi.
eval(code, options)
Evaluate JavaScript code. The semantics of this eval are very similar to the eval used in JavaScript;
the last expression evaluated in the code string is used as the return value of this function. To
evaluate code in strict mode, the first expression should be the string "use strict".
options
The eval function supports an options object that can affect how JS code is evaluated in powerful ways.
They are largely based on SpiderMonkey's CompileOptions. The supported option keys are:
filename: set the filename of this code for the purposes of generating stack traces etc.lineno: set the line number offset of this code for the purposes of generating stack traces etc.column: set the column number offset of this code for the purposes of generating stack traces etc.mutedErrors: if set toTrue, eval errors or unhandled rejections are ignored ("muted"). DefaultFalse.noScriptRval: ifFalse, return the last expression value of the script as the result value to the caller. DefaultFalse.selfHosting: experimentalstrict: forcibly evaluate in strict mode ("use strict"). DefaultFalse.module: indicate the file is an ECMAScript module (always strict mode code and disallow HTML comments). DefaultFalse.fromPythonFrame: generate the equivalent of filename, lineno, and column based on the location of the Python call to eval. This makes it possible to evaluate Python multiline string literals and generate stack traces in JS pointing to the error in the Python source file.
tricks
- function literals evaluate as
undefinedin JavaScript; if you want to return a function, you must evaluate an expression:
orpythonmonkey.eval("myFunction() { return 123 }; myFunction")pythonmonkey.eval("(myFunction() { return 123 })") - function expressions are a great way to build JS IIFEs that accept Python arguments
pyth
Related Skills
node-connect
329.7kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
openai-image-gen
329.7kBatch-generate images via OpenAI Images API. Random prompt sampler + `index.html` gallery.
claude-opus-4-5-migration
81.2kMigrate prompts and code from Claude Sonnet 4.0, Sonnet 4.5, or Opus 4.1 to Opus 4.5
frontend-design
81.2kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
