Skip to content

Commit face689

Browse files
Merge branch 'main' into wes/pmjs-regressions-276
2 parents 2c711b3 + 59a180f commit face689

File tree

10 files changed

+427
-64
lines changed

10 files changed

+427
-64
lines changed

.github/workflows/test-and-publish.yaml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -130,9 +130,7 @@ jobs:
130130
rm -rf doxygen-1.9.7 doxygen-1.9.7.linux.bin.tar.gz
131131
elif [[ "$OSTYPE" == "darwin"* ]]; then # macOS
132132
brew update || true # allow failure
133-
brew install cmake doxygen graphviz pkg-config wget coreutils # `coreutils` installs the `realpath` command
134-
brew uninstall --ignore-dependencies --force icu4c # https://gist.github.com/berkedel/d1fc6d13651c16002f64653096d1fded
135-
wget -c -q https://raw.githubusercontent.com/Homebrew/homebrew-core/7426122/Formula/i/icu4c.rb && brew install --formula icu4c.rb && rm icu4c.rb # pin icu4c version to 73.2
133+
brew install cmake doxygen pkg-config wget coreutils # `coreutils` installs the `realpath` command
136134
fi
137135
echo "Installing python deps"
138136
poetry self add "poetry-dynamic-versioning[plugin]"

README.md

Lines changed: 82 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44

55
## About
66
[PythonMonkey](https://pythonmonkey.io) is a Mozilla [SpiderMonkey](https://firefox-source-docs.mozilla.org/js/index.html) JavaScript engine embedded into the Python Runtime,
7-
using the Python engine to provide the Javascript host environment.
7+
using the Python engine to provide the Javascript host environment.
88

9-
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.
9+
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.
1010

11-
This product is in an intermediate stage, approximately 90% to MVP as of January 2024. It is under active development by [Distributive](https://distributive.network/).
11+
This product is in an intermediate stage, approximately 95% to MVP as of March 2024. It is under active development by [Distributive](https://distributive.network/).
1212
External contributions and feedback are welcome and encouraged.
1313

1414
### tl;dr
@@ -54,11 +54,11 @@ js_eval("console.log")('hello, world')
5454
- [done] CommonJS module system .py loader, loads Python modules for use by JS
5555
- [done] Python host environment supplies event loop, including EventEmitter, setTimeout, etc.
5656
- [done] Python host environment supplies XMLHttpRequest
57-
- Python host environment supplies basic subsets of NodeJS's fs, path, process, etc, modules; as-needed by dcp-client
5857
- [done] Python TypedArrays coerce to JS TypeArrays
5958
- [done] JS TypedArrays coerce to Python TypeArrays
6059
- [done] Python lists coerce to JS Arrays
6160
- [done] JS arrays coerce to Python lists
61+
- [90%] PythonMonkey can run the dcp-client npm package from Distributive.
6262

6363
## Build Instructions
6464

@@ -82,7 +82,7 @@ Read this if you want to build a local version.
8282
If you are using VSCode, you can just press <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>B</kbd> to [run build task](https://code.visualstudio.com/docs/editor/tasks#_custom-tasks) - We have [the `tasks.json` file configured for you](.vscode/tasks.json).
8383

8484
## Running tests
85-
1. Compile the project
85+
1. Compile the project
8686
2. Install development dependencies: `poetry install --no-root --only=dev`
8787
3. From the root directory, run `poetry run pytest ./tests/python`
8888
4. From the root directory, run `poetry run bash ./peter-jr ./tests/js/`
@@ -131,7 +131,7 @@ and install them by `pip install ./dist/*`.
131131
## Debugging Steps
132132

133133
1. [build the project locally](#build-instructions)
134-
2. To use gdb, run `poetry run gdb python`.
134+
2. To use gdb, run `poetry run gdb python`.
135135
See [Python Wiki: DebuggingWithGdb](https://wiki.python.org/moin/DebuggingWithGdb)
136136

137137
If you are using VSCode, it's more convenient to debug in [VSCode's built-in debugger](https://code.visualstudio.com/docs/editor/debugging). 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](https://github.com/Distributive-Network/PythonMonkey/blob/main/.vscode/launch.json).
@@ -142,18 +142,43 @@ If you are using VSCode, it's more convenient to debug in [VSCode's built-in deb
142142
* https://github.com/Distributive-Network/PythonMonkey-examples
143143
* https://github.com/Distributive-Network/PythonMonkey-Crypto-JS-Fullstack-Example
144144

145-
## API
146-
These methods are exported from the pythonmonkey module.
147-
148-
* eval(code, evalOpts)
149-
* isCompilableUnit(code)
150-
* collect()
151-
* bigint(int)
152-
* `SpiderMonkeyError`
153-
* `JSObjectProxy`
154-
* `null`
155-
156-
See definitions in [python/pythonmonkey/pythonmonkey.pyi](https://github.com/Distributive-Network/PythonMonkey/blob/main/python/pythonmonkey/pythonmonkey.pyi).
145+
## Official API
146+
These methods are exported from the pythonmonkey module. See definitions in [python/pythonmonkey/pythonmonkey.pyi](https://github.com/Distributive-Network/PythonMonkey/blob/main/python/pythonmonkey/pythonmonkey.pyi).
147+
148+
### eval(code, options)
149+
Evaluate JavaScript code. The semantics of this eval are very similar to the eval used in JavaScript;
150+
the last expression evaluated in the `code` string is used as the return value of this function. To
151+
evaluate `code` in strict mode, the first expression should be the string `"use strict"`.
152+
153+
#### options
154+
The eval function supports an options object that can affect how JS code is evaluated in powerful ways.
155+
They are largely based on SpiderMonkey's `CompileOptions`. The supported option keys are:
156+
- `filename`: set the filename of this code for the purposes of generating stack traces etc.
157+
- `lineno`: set the line number offset of this code for the purposes of generating stack traces etc.
158+
- `column`: set the column number offset of this code for the purposes of generating stack traces etc.
159+
- `mutedErrors`: experimental
160+
- `noScriptRval`: experimental
161+
- `selfHosting`: experimental
162+
- `strict`: experimental
163+
- `module`: experimental
164+
- `fromPythonFrame`: generate the equivalent of filename, lineno, and column based on the location of
165+
the Python call to eval. This makes it possible to evaluate Python multiline string literals and
166+
generate stack traces in JS pointing to the error in the Python source file.
167+
168+
#### tricks
169+
- function literals evaluate as `undefined` in JavaScript; if you want to return a function, you must
170+
evaluate an expression:
171+
```python
172+
pythonmonkey.eval("myFunction() { return 123 }; myFunction")
173+
```
174+
or
175+
```python
176+
pythonmonkey.eval("(myFunction() { return 123 })")
177+
```
178+
- function expressions are a great way to build JS IIFEs that accept Python arguments
179+
```python
180+
pythonmonkey.eval("(thing) => console.log('you said', thing)")("this string came from Python")
181+
```
157182

158183
### require(moduleIdentifier)
159184
Return the exports of a CommonJS module identified by `moduleIdentifier`, using standard CommonJS
@@ -188,6 +213,40 @@ necessary unless the main entry point of your program is written in JavaScript.
188213

189214
Care should be taken to ensure that only one program module is run per JS context.
190215

216+
### isCompilableUnit(code)
217+
Examines the string `code` and returns False if the string might become a valid JS statement with
218+
the addition of more lines. This is used internally by pmjs and can be very helpful for building
219+
JavaScript REPLs; the idea is to accumulate lines in a buffer until isCompilableUnit is true, then
220+
evaluate the entire buffer.
221+
222+
### new(function)
223+
Returns a Python function which invokes `function` with the JS new operator.
224+
```python
225+
import pythonmonkey as pm
226+
227+
>>> pm.eval("class MyClass { constructor() { console.log('ran ctor') }}")
228+
>>> MyClass = pm.eval("MyClass")
229+
>>> MyClass()
230+
Traceback (most recent call last):
231+
File "<stdin>", line 1, in <module>
232+
pythonmonkey.SpiderMonkeyError: TypeError: class constructors must be invoked with 'new'
233+
234+
>>> MyClassCtor = pm.new(MyClass)
235+
>>> MyClassCtor()
236+
ran ctor
237+
{}
238+
>>>
239+
```
240+
241+
### typeof(value)
242+
This is the JS `typeof` operator, wrapped in a function so that it can be used easily from Python.
243+
244+
### Standard Classes and Globals
245+
All of the JS Standard Classes (Array, Function, Object, Date...) and objects (globalThis,
246+
FinalizationRegistry...) are available as exports of the pythonmonkey module. These exports are
247+
generated by enumerating the global variable in the current SpiderMonkey context. The current list is:
248+
<blockquote>undefined, Boolean, JSON, Date, Math, Number, String, RegExp, Error, InternalError, AggregateError, EvalError, RangeError, ReferenceError, SyntaxError, TypeError, URIError, ArrayBuffer, Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array, Uint8ClampedArray, BigInt64Array, BigUint64Array, BigInt, Proxy, WeakMap, Map, Set, DataView, Symbol, Intl, Reflect, WeakSet, Promise, WebAssembly, WeakRef, Iterator, AsyncIterator, NaN, Infinity, isNaN, isFinite, parseFloat, parseInt, escape, unescape, decodeURI, encodeURI, decodeURIComponent, encodeURIComponent, Function, Object, debuggerGlobal, FinalizationRegistry, Array, globalThis</blockquote>
249+
191250
## Built-In Functions
192251

193252
See definitions in [python/pythonmonkey/global.d.ts](https://github.com/Distributive-Network/PythonMonkey/blob/main/python/pythonmonkey/global.d.ts).
@@ -213,8 +272,8 @@ pythonmonkey module.
213272
- `python.stderr` - an object with `read` and `write` methods, which read and write to stderr
214273
- `python.exec` - the Python exec function
215274
- `python.eval` - the Python eval function
216-
- `python.exit` - the Python exit function (wrapped to return BigInt in place of number)
217-
- `python.paths` - the Python sys.paths list (currently a copy; will become an Array-like reflection)
275+
- `python.exit` - exit via sys.exit(); the exit code is the function argument or `python.exit.code`.
276+
- `python.paths` - the Python sys.paths list, visible in JS as an Array
218277

219278
## Type Transfer (Coercion / Wrapping)
220279
When sending variables from Python into JavaScript, PythonMonkey will intelligently coerce or wrap your
@@ -231,7 +290,7 @@ Where shared backing store is not possible, PythonMonkey will automatically emit
231290
the "real" data structure as its value authority. Only immutable intrinsics are copied. This means
232291
that if you update an object in JavaScript, the corresponding Dict in Python will be updated, etc.
233292

234-
JavaScript Array and Object methods are implemented on Python List and Dictionaries, and vice-versa.
293+
JavaScript Array and Object methods are implemented on Python List and Dictionaries, and vice-versa.
235294

236295
| Python Type | JavaScript Type |
237296
|:------------|:----------------|
@@ -301,7 +360,7 @@ import asyncio
301360

302361
async def async_fn():
303362
await pm.eval("""
304-
new Promise((resolve) => setTimeout((...args) => {
363+
new Promise((resolve) => setTimeout((...args) => {
305364
console.log(args);
306365
resolve();
307366
}, 1000, 42, "abc")
@@ -406,5 +465,5 @@ $1 = { '0': '/home/wes/git/pythonmonkey2',
406465
'5': '/home/wes/git/pythonmonkey2/python' }
407466
> $1[3]
408467
'/usr/lib/python3.10/lib-dynload'
409-
>
468+
>
410469
```

include/ExceptionType.hh

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
/**
22
* @file ExceptionType.hh
3-
* @author Tom Tang ([email protected])
3+
* @author Tom Tang ([email protected]) and Philippe Laporte ([email protected])
44
* @brief Struct for representing Python Exception objects from a corresponding JS Error object
55
* @version 0.1
66
* @date 2023-04-11
77
*
8-
* @copyright Copyright (c) 2023
8+
* @copyright Copyright (c) 2023-2024 Distributive Corp.
99
*
1010
*/
1111

@@ -24,8 +24,6 @@
2424
*/
2525
struct ExceptionType : public PyType {
2626
public:
27-
ExceptionType(PyObject *object);
28-
2927
/**
3028
* @brief Construct a new SpiderMonkeyError from the JS Error object.
3129
*
@@ -37,11 +35,13 @@ public:
3735
const TYPE returnType = TYPE::EXCEPTION;
3836

3937
/**
40-
* @brief Convert a python [*Exception object](https://docs.python.org/3/c-api/exceptions.html#standard-exceptions) to JS Error object
38+
* @brief Convert a python Exception object to a JS Error object
4139
*
4240
* @param cx - javascript context pointer
41+
* @param exceptionValue - Exception object pointer, cannot be NULL
42+
* @param traceBack - Exception traceback pointer, can be NULL
4343
*/
44-
JSObject *toJsError(JSContext *cx);
44+
static JSObject *toJsError(JSContext *cx, PyObject *exceptionValue, PyObject *traceBack);
4545
};
4646

4747
#endif

setup.sh

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,7 @@ if [[ "$OSTYPE" == "linux-gnu"* ]]; then # Linux
1919
rm -rf doxygen-1.9.7 doxygen-1.9.7.linux.bin.tar.gz
2020
elif [[ "$OSTYPE" == "darwin"* ]]; then # macOS
2121
brew update || true # allow failure
22-
brew install cmake doxygen graphviz pkg-config wget coreutils # `coreutils` installs the `realpath` command
23-
brew uninstall --ignore-dependencies --force icu4c # https://gist.github.com/berkedel/d1fc6d13651c16002f64653096d1fded
24-
wget -c -q https://raw.githubusercontent.com/Homebrew/homebrew-core/7426122/Formula/i/icu4c.rb && brew install --formula icu4c.rb && rm icu4c.rb # pin icu4c version to 73.2
22+
brew install cmake doxygen pkg-config wget coreutils # `coreutils` installs the `realpath` command
2523
elif [[ "$OSTYPE" == "msys"* ]]; then # Windows
2624
echo "Dependencies are not going to be installed automatically on Windows."
2725
else

0 commit comments

Comments
 (0)