Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
f6c35f1
Add package.json for npm/JS dependencies
May 26, 2023
9b313fc
Add node-compatible require() for CommonJS modules
May 27, 2023
156feb8
use-require example: update include() so that cwd doesn't matter
May 27, 2023
8f480ed
pythonmonkey_require - improve code clarity; now compatible with late…
May 27, 2023
72f4f46
pythonmonkey_require - add python JS global, improve debug function, …
May 27, 2023
c89036b
pythonmonkey_require - add sys.paths+/node_modules to module.paths
May 27, 2023
264a9d4
pythonmonkey_require - add support for .py modules
May 27, 2023
704baca
pythonmonkey_require - fix support for directory/index modules
May 27, 2023
aed2672
Update README to reflect module system progress
May 29, 2023
7c4cbfb
feat: Updated pythonmonkey_require to use pythonic module loading use…
May 29, 2023
ca2d68f
chore: Add some pythonic comments and type hinting for devs
May 29, 2023
55bff26
fix: Fixed import for importlib machinery to keep it in scope and bet…
May 29, 2023
9bc5d09
rename exports to module_exports to make sure semantics aren't confused
May 29, 2023
cca1218
fix: pythonmonkey_require - Make sure memoized modules are also expor…
May 29, 2023
8f43482
feat: Updated variable names in examples, more accurate python module…
May 30, 2023
77d5473
fix: Delete mistakenly copied additional file
Jun 16, 2023
fad3dba
Merge branch 'BF-38' into wes/module-system
Jun 21, 2023
27c8ee0
Merge branch 'hamada/module-system' into wes/module-system
Jun 22, 2023
0839bae
Merge: main into module system to update build system
Jun 22, 2023
1544520
WIP: Updated pythonmonkey_require to be in pythonmonkey directory and…
Jun 22, 2023
ddbdb92
chore: `npm i` should be run in `python/pythonmonkey` directory
Xmader Jun 22, 2023
bcd6f67
test(promise): fix regex doesn't match when having `ctx-module`
Xmader Jun 22, 2023
3423f19
chore: must explicitly include `node_modules` into the wheel package
Xmader Jun 22, 2023
acc13d0
Merge pull request #47 from Distributive-Network/Xmader/fix/module-sy…
Hamada-Distributed Jun 22, 2023
336b0cc
Add reentrance_smoke test
Jun 23, 2023
32b09f4
eval - implement support for compilation options
Jun 23, 2023
0ea3b54
Add simple console.log placeholder
Jun 23, 2023
7456148
Add simple js testing
Jun 23, 2023
fc3314b
peter-jr - improve output
Jun 23, 2023
7eaa6c7
Add trivial REPL; pmjs
Jun 23, 2023
4fdb52d
Add hard-coded __version__ to pythonmonkey module
Jun 23, 2023
ab1a0a3
Add emacs tmp files to .gitignore
Jun 23, 2023
baa2c66
Add (dormant) implementation of runInContext for require
Jun 23, 2023
01d34e2
Generate __version__ directly from pyproject.toml at build time
wesgarland Jun 24, 2023
a246b51
Add console smoke test
wesgarland Jun 24, 2023
7619a00
require - add ./builtin_modules/ to list of search paths
wesgarland Jun 24, 2023
2c594e5
temp console - plumb-in globalThis.console as a side-effect of loadin…
wesgarland Jun 24, 2023
5118c58
Update key file locations and paths so that createRequire can be expo…
wesgarland Jun 24, 2023
be29725
Update examples to load createRequire from pythonmonkey module
wesgarland Jun 24, 2023
8c74c23
peter-jr - improve output
wesgarland Jun 24, 2023
ed09e2a
Add python-language CommonJS module test
wesgarland Jun 24, 2023
89a78ca
Add isCompilableUnit to support writing JS REPLs
wesgarland Jun 24, 2023
e3f8e8f
pmjs - exit REPL when ^D
wesgarland Jun 24, 2023
7a7477c
Add test coverage for isCompilableUnit
wesgarland Jun 24, 2023
e3e7ff4
pmjs - add support for multi-line statements, result colourization, i…
wesgarland Jun 25, 2023
70c37e8
pmjs - improve Error output
wesgarland Jun 25, 2023
1c2966c
pmjs - implement half-baked sigint handler; might need to escape read…
wesgarland Jun 25, 2023
a9a9e9b
pmjs - improve code readability and command argument parsing
wesgarland Jun 25, 2023
7206801
Add basic smoke-test for CommonJS module loading
wesgarland Jun 25, 2023
e1fd220
require.py - remove globalSet and propSet hacks, depends on ctx-modul…
wesgarland Jun 25, 2023
311b46e
chore: make pythonmonkey python files more pythonic and update tests
Jun 26, 2023
da3a900
build_script.sh - stop growing version.py
wesgarland Jun 26, 2023
7270d4c
peter-jr - fix argv parsing, add test-failure exit code
wesgarland Jun 26, 2023
334fb0d
pmjs - police whitespace
wesgarland Jun 26, 2023
7f38d25
Merge branch 'BF-38' into wes/module-system-main-merge
wesgarland Jun 28, 2023
7bc5a5f
add pmjs-require.js
wesgarland Jun 28, 2023
4c11666
pmjs, require examples, etc - let poetry manage sys.path to find pyth…
wesgarland Jun 28, 2023
bfee9f2
Add builtin_modules to wheel
wesgarland Jun 28, 2023
4087f37
Change cmake LINUX variables to UNIX so that the build builds
wesgarland Jun 28, 2023
2b1dbf4
re-fix rpath for appple in CMakeLists.txt
wesgarland Jun 30, 2023
3e39ead
Remove cmake inputs from .gitignore
wesgarland Jun 30, 2023
3062532
Merge remote-tracking branch 'origin/hamada/update-module-system' int…
wesgarland Jun 30, 2023
fb7cb57
Merge branch 'main' into wes/module-system
wesgarland Jul 4, 2023
3afea05
Merge branch 'main' into wes/module-system
Xmader Jul 4, 2023
1066eeb
docs: update README.md
Xmader Jul 4, 2023
90f981d
chore: fix src/CMakeLists.txt typo
Xmader Jul 4, 2023
04d3303
Update README.md to reflect roadmap advances
wesgarland Jul 5, 2023
8445eee
README - add examples section
wesgarland Jul 5, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
build/
.vscode/
pyvenv.cfg
python/pythonmonkey/version.py
python/pythonmonkey/node_modules
bin/
lib/*
.pytest_cache
.DS_Store
firefox-*.tar.xz
firefox-*/
tests/__pycache__/*
tests/python/__pycache__/*
__pycache__
Testing/Temporary
_spidermonkey_install
__pycache__
__pycache__/*
dist
*.so
_spidermonkey_install/*
*~
*.dylib
*.dll
*.pyd
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
set(PYTHON_INCLUDE_DIR ${Python_INCLUDE_DIRS})
set(PYTHON_LIBRARIES ${Python_LIBRARIES})
message("Apple - Using Python:${Python_VERSION_MAJOR} - Libraries:${PYTHON_LIBRARIES} - IncludeDirs: ${PYTHON_INCLUDE_DIR}")
elseif(LINUX)
elseif(UNIX)
find_package(Python 3.8 COMPONENTS Interpreter Development REQUIRED)
set(Python_FIND_VIRTUALENV FIRST) # (require cmake >= v3.15 and this is the default) use the Python version configured by pyenv if available
set(PYTHON_LIBRARIES ${Python_LIBRARIES})
Expand Down
33 changes: 27 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
PythonMonkey is a Mozilla [SpiderMonkey](https://firefox-source-docs.mozilla.org/js/index.html) JavaScript engine embedded into the Python VM,
using the Python engine to provide the JS host environment.

This product is in an early stage, approximately 65% to MVP as of March 2023. It is under active development by Distributive Corp.,
This product is in an early stage, approximately 80% to MVP as of May 2023. It is under active development by Distributive Corp.,
https://distributive.network/. External contributions and feedback are welcome and encouraged.

The goal is to make writing code in either JS or Python a developer preference, with libraries commonly used in either language
Expand All @@ -30,15 +30,15 @@ this package to execute our complex `dcp-client` library, which is written in JS
- [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
- [underway] NodeJS+NPM-compatible CommonJS module system
- [done] NodeJS+NPM-compatible CommonJS module system
- [done] Python strings coerce to JS strings
- [done] Python intrinsics coerce to JS intrinsics
- Python dicts coerce to JS objects
- Python `require` function, returns a coerced dict of module exports
- [done] Python dicts coerce to JS objects
- [done] Python `require` function, returns a coerced dict of module exports
- [done] Python functions coerce to JS function wrappers
- CommonJS module system .py loader, loads Python modules for use by JS
- [done] CommonJS module system .py loader, loads Python modules for use by JS
- JS object->Python dict coercion supports inherited-property lookup (via __getattribute__?)
- Python host environment supplies event loop, including EventEmitter, setTimeout, etc.
- [done] Python host environment supplies event loop, including EventEmitter, setTimeout, etc.
- Python host environment supplies XMLHttpRequest (other project?)
- Python host environment supplies basic subsets of NodeJS's fs, path, process, etc, modules; as-needed by dcp-client (other project?)
- Python TypedArrays coerce to JS TypeArrays
Expand All @@ -53,6 +53,7 @@ this package to execute our complex `dcp-client` library, which is written in JS
- rust
- python3.8 or later with header files (python3-dev)
- spidermonkey 102.2.0 or later
- npm (nodejs)
- [Poetry](https://python-poetry.org/docs/#installation)
- [poetry-dynamic-versioning](https://github.com/mtkennerly/poetry-dynamic-versioning)

Expand Down Expand Up @@ -95,3 +96,23 @@ Type "help", "copyright", "credits" or "license" for more information.
```

Alternatively, you can build a `wheel` package by running `poetry build --format=wheel`, and install it by `pip install dist/*.whl`.

## Examples

* [examples/](examples/)
* https://github.com/Distributive-Network/PythonMonkey-examples
* https://github.com/Distributive-Network/PythonMonkey-Crypto-JS-Fullstack-Example

# Troubleshooting Tips

## REPL - pmjs
A basic JavaScript shell, `pmjs`, ships with PythonMonkey.

## CommonJS (require)
If you are having trouble with the CommonJS require function, set environment variable DEBUG='ctx-module*' and you can see the filenames it tries to laod.

### Extra Symbols
Loading the CommonJS subsystem declares some extra symbols which may be helpful in debugging -
- `python.print` - the Python print function
- `python.getenv` - the Python getenv function

14 changes: 14 additions & 0 deletions build_script.sh
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
#! /bin/bash
#
# @file build.sh
# @author Giovanni Tedesco <giovanni@distributive.network>
# @date Aug 2022

cd `dirname "$0"`
topDir=`pwd`

# Get number of CPU cores
CPUS=$(getconf _NPROCESSORS_ONLN 2>/dev/null || getconf NPROCESSORS_ONLN 2>/dev/null || echo 1)

Expand All @@ -14,3 +23,8 @@ else
cmake ..
fi
cmake --build . -j$CPUS --config Release

cd ../python/pythonmonkey
# npm is used to load JS components, see package.json
cd "${topDir}/python/pythonmonkey/"
npm i
9 changes: 9 additions & 0 deletions examples/use-python-module.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# @file use-require.py
# Sample code which demonstrates how to use require
# @author Wes Garland, wes@distributive.network
# @date Jun 2023

import pythonmonkey as pm

require = pm.createRequire(__file__)
require('./use-python-module');
3 changes: 3 additions & 0 deletions examples/use-python-module/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const { helloWorld } = require('./my-python-module');
helloWorld()

5 changes: 5 additions & 0 deletions examples/use-python-module/my-python-module.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
def helloWorld():
print('hello, world!')

exports['helloWorld'] = helloWorld

11 changes: 11 additions & 0 deletions examples/use-require.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# @file use-require.py
# Sample code which demonstrates how to use require
# @author Wes Garland, wes@distributive.network
# @date Jun 2023

import pythonmonkey as pm

require = pm.createRequire(__file__)
require('./use-require/test1');
print("Done")

5 changes: 5 additions & 0 deletions examples/use-require/test1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
'use strict'

const makeOutput = require('./test2').makeOutput;

makeOutput('hello world');
9 changes: 9 additions & 0 deletions examples/use-require/test2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
'use strict'

exports.makeOutput = function makeOutput()
{
const argv = Array.from(arguments);
argv.unshift('TEST OUTPUT: ');
python.print.apply(null, argv);
}

16 changes: 16 additions & 0 deletions js-test-runner
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#! /usr/bin/env python3
# @file js-test-runner
# A simple test driver for peter-jr that runs JS code via PythonMonkey.require
# @author Wes Garland, wes@distributive.network
# @date Jun 2023

import sys, os
import pythonmonkey as pm

# Main
require = pm.createRequire(__file__)
require('console');

testName = os.path.realpath(sys.argv[1]);
testDir = os.path.dirname(testName);
pm.createRequire(testName)(testName);
130 changes: 130 additions & 0 deletions peter-jr
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
#! /bin/bash
#
# @file peter-js
# A simple test framework in the spirit of Peter (npmjs.com/packages/peter) for testing
# basic PythonMonkey functionality.
#
# Exit Codes:
# 0 - all tests passed
# 1 - one or more tests failed
# 2 - no tests ran
# 3 - internal error
#
# @author Wes Garland, wes@distributive.network
# @date Jun 2023
#
runDir=`pwd`
cd `dirname "$0"`
topDir=`pwd`
cd "$runDir"

set -u
set -o pipefail
peter_exit_code=2

if [ "${1:-}" = "-v" ]; then
VERBOSE=1
shift
else
VERBOSE="${VERBOSE:-}"
fi

[ "${1:-}" ] || set "${topDir}/tests/js"
testLocations=("$@")

function panic()
{
echo "PANIC: $*" >&2
exit 3
}

TMP=`mktemp -d`
([ "${TMP}" ] && [ -d "${TMP}" ]) || exit 3

trap "rm -r \"${TMP}\"" EXIT

if [ "$VERBOSE" ]; then
stdout="/dev/stdout"
stderr="/dev/stderr"
else
stdout="$TMP/stdout"
stderr="$TMP/stderr"
fi

red()
{
printf "\e[0;31m%s\e[0m" "$*"
}

green()
{
printf "\e[0;32m%s\e[0m" "$*"
}

yellow()
{
printf "\e[0;33m%s\e[0m" "$*"
}

grey()
{
printf "\e[0;90m%s\e[0m" "$*"
}

(
for loc in "${testLocations[@]}"
do
find $(realpath "$loc") -type f -name \*.simple
find $(realpath "$loc") -type f -name \*.bash
done
) \
| while read file
do
sfile=$(realpath --relative-to="${runDir}" "${file}")
printf 'Testing %-40s ... ' "${sfile}"
ext="${file##*.}"
(
case "$ext" in
"simple")
"${topDir}/js-test-runner" "$file"
exitCode="$?"
;;
"bash")
bash "$file"
exitCode="$?"
;;
*)
echo
panic "${file}: invalid extension '$ext'"
;;
esac

exit "$exitCode"
)> $stdout 2>$stderr
exitCode="$?"

if [ "$exitCode" = "0" ]; then
echo "$(green PASS)"
[ "${peter_exit_code}" = "2" ] && peter_exit_code=0
printf "\e[0;31m"
[ "$VERBOSE" ] || cat "$stderr"
printf "\e[0m"
else
echo "$(red FAIL)"
peter_exit_code=1
if [ ! "$VERBOSE" ]; then
echo
echo "$(grey --) $(yellow ${file}) $(grey vvvvvvvvvvvvvv)"
cat "$stdout" | sed 's/^/ /'
printf "\e[0;31m"
cat "$stderr" | sed -e 's/^/ /'
printf "\e[0m"
echo "$(grey --) $(yellow ${file}) $(grey ^^^^^^^^^^^^^^)"
echo
fi
fi
(exit ${peter_exit_code})
done
peter_exit_code="$?"

exit ${peter_exit_code}
Loading