- added a new build type:
- **Sanitize**: same as **Debug**, except with [AddressSanitizer](https://github.com/google/sanitizers/wiki/AddressSanitizer) enabled
- added a new tool inspired by [wtfnode](https://www.npmjs.com/package/wtfnode) called WTFPythonMonkey to track down any hanging `setTimeout`/`setInterval` timers that are still ref'd when you hit ctrl-C.
- When using `pmjs`, to enable it you can simply pass the `--wtf` flag, like so:
bash
pmjs --wtf <filename>.js
- When using pythonmonkey from python, it can be enabled by using a [context manager (`with`-statement)](https://github.com/Distributive-Network/PythonMonkey/blob/c80f2ec4e7ca1c83c70a31556bbbc165529d41f3/python/pythonmonkey/lib/wtfpm.py#L16-L28) around the entry point of the event loop, like so:
py
import asyncio
import pythonmonkey as pm
from pythonmonkey.lib.wtfpm import WTF
async def pythonmonkey_main():
pm.eval("setInterval(() => console.log(new Date), 500)")
await pm.wait()
with WTF():
asyncio.run(pythonmonkey_main())
- implemented JS-like function calling for python functions in JS. Similar to JS functions, you can now call python functions with too few or too many arguments without throwing an error.
- When too many arguments are supplied, those beyond the function's parameter count are ignored, e.g.:
py
def f(a, b):
return [a, b]
assert [1, 2] == pm.eval("(f) => f(1, 2, 3)")(f)
- When too few arguments are supplied, those beyond the number of supplied arguments are passed as `None` to match JS's behaviour of passing `undefined`, e.g.:
py
def f(a, b):
return [a, b]
assert [1, None] == pm.eval("(f) => f(1)")(f)
- This also works for functions with default arguments, or varargs, e.g.:
py
def f(a, b, c=42, d=43, *args):
return [a, b, c, d, *args]
assert [1, 2, 3, 4, 5] == pm.eval("(f) => f(1, 2, 3, 4, 5)")(f)
assert [1, 2, 3, 4 ] == pm.eval("(f) => f(1, 2, 3, 4)" )(f)
assert [1, 2, 3, 43 ] == pm.eval("(f) => f(1, 2, 3)" )(f)
assert [1, 2, 42, 43 ] == pm.eval("(f) => f(1, 2)" )(f)
assert [1, None, 42, 43 ] == pm.eval("(f) => f(1)" )(f)
assert [None, None, 42, 43 ] == pm.eval("(f) => f()" )(f)
- implemented the [copy protocol](https://docs.python.org/3/library/copy.html) (both `copy.copy` and `copy.deepcopy`) for JSStringProxies
- using the aforementioned WTFPythonMonkey, we've fixed several bugs related to timers, including:
- the `Future object is not initialized` error and following segfault
- heap-use-after-free in `timerJobWrapper`
- hitting ctrl-C in `pmjs` printing out the entire Python `KeyboardInterrupt` traceback
- intervals from `setInterval` were not being unref'd correctly
- fixed a bug where uncaught JS Promise rejections would result in a `Future exception was never retrieved` Python error, rather than the actual JS error
- added support for `HTTP-Keep-Alive` in our implementation of `XMLHttpRequest`
- fixed a memory leak related to cross-language strings
- fixed a bug where attempting to install Pythonmonkey from source failed on Ubuntu 24.04
- PythonMonkey now uses the [bleeding edge version of SpiderMonkey](https://hg.mozilla.org/mozilla-central/) on this and all future releases
- we now build and distribute binaries for python 3.8 on amd64 Mac OS