From ccb202821ec9bcf5d99aaad45bcd026d9d38bb55 Mon Sep 17 00:00:00 2001 From: Wes Garland Date: Mon, 10 Jul 2023 23:42:58 -0400 Subject: [PATCH 001/428] Begin modifying pmjs for event loop integration --- pmjs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pmjs b/pmjs index 52c6730e..6f94e6ab 100755 --- a/pmjs +++ b/pmjs @@ -3,7 +3,7 @@ # @author Wes Garland, wes@distributive.network # @date June 2023 -import sys, os, readline, signal, getopt +import sys, os, readline, signal, getopt, asyncio import pythonmonkey as pm globalThis = pm.eval("globalThis") evalOptions = { 'strict': False } @@ -290,7 +290,7 @@ def initGlobalThis(): argvBuilder(arg); # list=>Array not working yet return globalInitModule -def main(): +async def main(): """ Main program entry point """ @@ -339,4 +339,4 @@ def main(): repl() if __name__ == "__main__": - main() + asyncio.run(main()) From 67ca9e043585e7c2f479fb319d11a937bb15d6a2 Mon Sep 17 00:00:00 2001 From: Wes Garland Date: Sat, 15 Jul 2023 17:26:57 -0400 Subject: [PATCH 002/428] pmjs - implement event-loop, works with timers.js setTimeout --- pmjs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/pmjs b/pmjs index 2ebda028..c4d5a396 100755 --- a/pmjs +++ b/pmjs @@ -296,7 +296,7 @@ def initGlobalThis(): argvBuilder(arg); # list=>Array not working yet return globalInitModule -async def main(): +def main(): """ Main program entry point """ @@ -338,11 +338,16 @@ async def main(): assert False, "unhandled option" if (len(args) > 0): - globalInitModule.patchGlobalRequire() - pm.runProgramModule(args[0], args, requirePath) + loop = asyncio.new_event_loop() + async def runJS(): + globalInitModule.patchGlobalRequire() + pm.runProgramModule(args[0], args, requirePath) + loop.create_task(runJS()) + loop.run_forever() + loop.close() elif (enterRepl or forceRepl): globalInitModule.initReplLibs() repl() if __name__ == "__main__": - asyncio.run(main()) + main(); From 887a33799b69da79adbd4cabd2aa8166ab0c39a7 Mon Sep 17 00:00:00 2001 From: Wes Garland Date: Sat, 15 Jul 2023 20:29:07 -0400 Subject: [PATCH 003/428] pmjs - implement event loop via pmjs-lib/event-loop* modules --- pmjs | 8 ++- pmjs-lib/event-loop-asyncio.py | 83 +++++++++++++++++++++++++ pmjs-lib/event-loop.js | 109 +++++++++++++++++++++++++++++++++ 3 files changed, 198 insertions(+), 2 deletions(-) create mode 100644 pmjs-lib/event-loop-asyncio.py create mode 100644 pmjs-lib/event-loop.js diff --git a/pmjs b/pmjs index c4d5a396..ae5d2bf4 100755 --- a/pmjs +++ b/pmjs @@ -338,13 +338,17 @@ def main(): assert False, "unhandled option" if (len(args) > 0): - loop = asyncio.new_event_loop() + ela = pm.require('./pmjs-lib/event-loop-asyncio') + loop = ela['makeLoop']() + globalThis.setTimeout = pm.require('./pmjs-lib/event-loop')['setTimeout']; + async def runJS(): globalInitModule.patchGlobalRequire() pm.runProgramModule(args[0], args, requirePath) + loop.create_task(runJS()) loop.run_forever() - loop.close() + elif (enterRepl or forceRepl): globalInitModule.initReplLibs() repl() diff --git a/pmjs-lib/event-loop-asyncio.py b/pmjs-lib/event-loop-asyncio.py new file mode 100644 index 00000000..7dca4044 --- /dev/null +++ b/pmjs-lib/event-loop-asyncio.py @@ -0,0 +1,83 @@ +# @file event-loop-asyncio.py +# Interface to the asyncio module for the event-loop library. We can't use JavaScript for +# some of this code, because PythonMonkey can't transport things like asyncio.TimerHandler +# and event loops as of version 0.2.0. +# @author Wes Garland, wes@distributive.network +# @date July 2023 +# +import asyncio + +loop = False + +def enqueueWithDelay(callback, delay): + """ + Schedule a callback to run after a certain amount of time. Delay is in seconds. + """ + return { 'timer': loop.call_later(delay, callback) } + +def enqueue(callback): + """ + Schedule a callback to run as soon as possible. + """ + global loop + acb = loop.run_in_executor(None, callback) + loop.call_soon(acb) + return acb + +def cancelTimer(pyHnd): + """ + Cancel a timer that was previously enqueued. The pyHnd argument is the return value from one of the + enqueue functions. + """ + loop.pyHnd['timer'].cancel() + +def getLoop(): + """ + Get the current Python event loop used by this code. If no loop has been specified and this is the + first time this function is run, we start using the event loop that invoked this call. + """ + global loop + if (loop == False): + loop = asyncio.get_running_loop() + return loop + +def setLoop(newLoop): + """ + Set the event loop this code will use. Replacing a running loop is not allowed. + """ + global loop + if (loop != False and loop != newLoop): + raise Except("can't set loop - event loop already exists") + loop = newLoop + +def makeLoop(): + """ + Make a new event loop. + """ + global loop + if (loop != False): + raise Except("can't make loop - event loop already exists") + loop = asyncio.new_event_loop() + return loop + +def endLoop(): + """ + End the event loop. This will throw if there are pending events. + """ + global loop + if (loop != False): + loop.stop() + loop = False + +def uptime(): + """ + Return the number of seconds this event loop has been running. + """ + return loop.time() + +exports['enqueueWithDelay'] = enqueueWithDelay +exports['enqueue'] = enqueue +exports['getLoop'] = getLoop +exports['setLoop'] = setLoop +exports['makeLoop'] = makeLoop +exports['endLoop'] = endLoop diff --git a/pmjs-lib/event-loop.js b/pmjs-lib/event-loop.js new file mode 100644 index 00000000..f0dc6475 --- /dev/null +++ b/pmjs-lib/event-loop.js @@ -0,0 +1,109 @@ +/** + * @file event-loops.js + * Code for creating and manipulating a NodeJS-style reference-centric event loop for use + * within pmjs. The code currently in builtin_modules/timers.js implements WHATWG-spec- + * compliant timers, but this code needs different functionality and access to the Python + * awaitables implementing the timers because of that. + * + * @author Wes Garland, wes@distributive.network + * @date July 2023 + */ +'use strict'; + +const { enqueue, enqueueWithDelay, cancelTimer, endLoop } = require('./event-loop-asyncio'); + +const references = new Set(); +var seq = 0; + +/** + * Timeout constructor. This is the handle returned from setTimeout, setInterval, and setImmediate in an + * environment with a node-style event-loop. We implement the following methods, modelled on Node.js: + * - ref() + * - unref() + * - toString() + * + * Also like Node.js, there is a repeat property on this handle which controls if it is re-scheduled + * every time it fires. This is the main difference between intervals and timeouts. + * + * @param {Dict} pyHnd a dict with a timer attribute which can be used for cancelling the timeout + */ +function Timeout(pyHnd) +{ + this.id = ++seq; + this.pyHnd = pyHnd; + this.repeat = false; + this.ref(); +} + +Timeout.prototype.toString = function eventLoop$$Timeout$toString() +{ + return `${this.id}` +} + +Timeout.prototype.unref = function eventLoop$$Timeout$unref() +{ + references.delete(this); + this._refed = false; +} + +Timeout.prototype.ref = function eventLoop$$Timeout$unref() +{ + console.log('add reference') + references.add(this); + this._refed = true; +} + +/** + * setTimeout method. setImmediate and setInterval are implemented in terms of setTimeout. + */ +function eventLoop$$setTimeout(callback, delayMs, ...args) +{ + var pyHnd, timer; + + if (delayMs) + pyHnd = enqueueWithDelay(timerCallbackWrapper, Math.max(4, delayMs) / 1000); + else + pyHnd = enqueue(timerCallbackWrapper); + + timer = new Timeout(pyHnd); + + function timerCallbackWrapper() + { + if (timer._destroyed === true) + return; + callback.apply(this, ...args); + if (timer._repeat && typeof timer._repeat === 'number') + enqueueWithDelay(callbackWrapper, Math.max(4, delayMs) / 1000, timer._repeat); + else + timer.unref(); + + if (references.size === 0) + endLoop(); + } +} + +function eventLoop$$setInterval(callback, delayMs, ...args) +{ + const timer = eventLoop$$setTimeout(callback, delayMs, ...args) + timer._repeat = delayMs; + return timer; +} + +function eventLoop$$setImmediate(callback, ...args) +{ + return setTimeout(callback, false, ...args) +} + +function eventLoop$$clearTimeout(timer) +{ + timer.unref(); + timer._repeat = false; + timer._destroyed = true; +} + +exports.setInterval = eventLoop$$setImmediate; +exports.setTimeout = eventLoop$$setTimeout; +exports.setInterval = eventLoop$$setInterval; +exports.clearTimeout = eventLoop$$clearTimeout; +exports.clearInterval = eventLoop$$clearTimeout; +exports.clearImmediate = eventLoop$$clearTimeout; From 116e7774e2c13bbc0a18c0c305bda3255a8430a5 Mon Sep 17 00:00:00 2001 From: Wes Garland Date: Sat, 15 Jul 2023 20:58:02 -0400 Subject: [PATCH 004/428] pmjs - plumb in all event loop methods, make programs without events exit properly --- pmjs | 3 ++- pmjs-lib/event-loop-asyncio.py | 5 +---- pmjs-lib/event-loop.js | 5 ++--- pmjs-lib/global-init.js | 4 ++++ 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/pmjs b/pmjs index ae5d2bf4..58daa4f8 100755 --- a/pmjs +++ b/pmjs @@ -339,12 +339,13 @@ def main(): if (len(args) > 0): ela = pm.require('./pmjs-lib/event-loop-asyncio') + eljs = pm.require('./pmjs-lib/event-loop') loop = ela['makeLoop']() - globalThis.setTimeout = pm.require('./pmjs-lib/event-loop')['setTimeout']; async def runJS(): globalInitModule.patchGlobalRequire() pm.runProgramModule(args[0], args, requirePath) + pm.eval("setImmediate(()=>1)") # seed the loop.stop() code loop.create_task(runJS()) loop.run_forever() diff --git a/pmjs-lib/event-loop-asyncio.py b/pmjs-lib/event-loop-asyncio.py index 7dca4044..abd15767 100644 --- a/pmjs-lib/event-loop-asyncio.py +++ b/pmjs-lib/event-loop-asyncio.py @@ -19,10 +19,7 @@ def enqueue(callback): """ Schedule a callback to run as soon as possible. """ - global loop - acb = loop.run_in_executor(None, callback) - loop.call_soon(acb) - return acb + return { 'timer': loop.call_soon(callback) } def cancelTimer(pyHnd): """ diff --git a/pmjs-lib/event-loop.js b/pmjs-lib/event-loop.js index f0dc6475..21166ae6 100644 --- a/pmjs-lib/event-loop.js +++ b/pmjs-lib/event-loop.js @@ -48,7 +48,6 @@ Timeout.prototype.unref = function eventLoop$$Timeout$unref() Timeout.prototype.ref = function eventLoop$$Timeout$unref() { - console.log('add reference') references.add(this); this._refed = true; } @@ -60,7 +59,7 @@ function eventLoop$$setTimeout(callback, delayMs, ...args) { var pyHnd, timer; - if (delayMs) + if (delayMs >= 0) pyHnd = enqueueWithDelay(timerCallbackWrapper, Math.max(4, delayMs) / 1000); else pyHnd = enqueue(timerCallbackWrapper); @@ -101,7 +100,7 @@ function eventLoop$$clearTimeout(timer) timer._destroyed = true; } -exports.setInterval = eventLoop$$setImmediate; +exports.setImmediate = eventLoop$$setImmediate; exports.setTimeout = eventLoop$$setTimeout; exports.setInterval = eventLoop$$setInterval; exports.clearTimeout = eventLoop$$clearTimeout; diff --git a/pmjs-lib/global-init.js b/pmjs-lib/global-init.js index db78892c..10c08544 100644 --- a/pmjs-lib/global-init.js +++ b/pmjs-lib/global-init.js @@ -49,3 +49,7 @@ exports.initReplLibs = function pmjs$$initReplLibs() { globalThis.util = require('util'); } + +const eventLoopMethods = require('./event-loop'); +for (let name in eventLoopMethods) + globalThis[name] = eventLoopMethods[name]; From 6ec009bfb393d223d67e8bdf683cbcbd1e20b85e Mon Sep 17 00:00:00 2001 From: Wes Garland Date: Sun, 16 Jul 2023 14:42:01 -0400 Subject: [PATCH 005/428] pmjs - unreference events during exit, improve uncaught handling --- pmjs | 24 ++++++++--- pmjs-lib/event-loop-asyncio.py | 3 +- pmjs-lib/event-loop.js | 76 +++++++++++++++++++++++++++++++--- pmjs-lib/global-init.js | 16 +++++-- 4 files changed, 104 insertions(+), 15 deletions(-) diff --git a/pmjs b/pmjs index 58daa4f8..996cf4e7 100755 --- a/pmjs +++ b/pmjs @@ -343,11 +343,25 @@ def main(): loop = ela['makeLoop']() async def runJS(): - globalInitModule.patchGlobalRequire() - pm.runProgramModule(args[0], args, requirePath) - pm.eval("setImmediate(()=>1)") # seed the loop.stop() code - - loop.create_task(runJS()) + try: + pm.eval("setImmediate(()=>1)") # seed the loop.stop() code + globalInitModule.patchGlobalRequire() + pm.runProgramModule(args[0], args, requirePath) + except pm.SpiderMonkeyError as error: + globalInitModule.uncaughtExceptionHandler(error) + except Exception as error: + print(error) + + def cleanupExit(code): + eljs['unrefEverything']() + dummyReference = programTask + realExit(code); + + realExit = globalThis.python.exit; + globalThis.python.exit = cleanupExit; + + programTask = loop.create_task(runJS()) + programTask.set_name('pmjs-program') loop.run_forever() elif (enterRepl or forceRepl): diff --git a/pmjs-lib/event-loop-asyncio.py b/pmjs-lib/event-loop-asyncio.py index abd15767..857b522a 100644 --- a/pmjs-lib/event-loop-asyncio.py +++ b/pmjs-lib/event-loop-asyncio.py @@ -26,7 +26,7 @@ def cancelTimer(pyHnd): Cancel a timer that was previously enqueued. The pyHnd argument is the return value from one of the enqueue functions. """ - loop.pyHnd['timer'].cancel() + pyHnd['timer'].cancel() def getLoop(): """ @@ -74,6 +74,7 @@ def uptime(): exports['enqueueWithDelay'] = enqueueWithDelay exports['enqueue'] = enqueue +exports['cancelTimer'] = cancelTimer exports['getLoop'] = getLoop exports['setLoop'] = setLoop exports['makeLoop'] = makeLoop diff --git a/pmjs-lib/event-loop.js b/pmjs-lib/event-loop.js index 21166ae6..2222b34e 100644 --- a/pmjs-lib/event-loop.js +++ b/pmjs-lib/event-loop.js @@ -12,7 +12,7 @@ const { enqueue, enqueueWithDelay, cancelTimer, endLoop } = require('./event-loop-asyncio'); -const references = new Set(); +const pendingTimers = new Set(); var seq = 0; /** @@ -33,6 +33,8 @@ function Timeout(pyHnd) this.pyHnd = pyHnd; this.repeat = false; this.ref(); + + pendingTimers.add(this); } Timeout.prototype.toString = function eventLoop$$Timeout$toString() @@ -40,20 +42,29 @@ Timeout.prototype.toString = function eventLoop$$Timeout$toString() return `${this.id}` } +/** + * Remove a reference from a timer. Program will not naturally exit until all references are removed. + */ Timeout.prototype.unref = function eventLoop$$Timeout$unref() { - references.delete(this); this._refed = false; } +/** + * Add a reference to a timer. Program will not naturally exit until all references are removed. Timers + * are referenced by default. References are binary, on/off, not counted. + */ Timeout.prototype.ref = function eventLoop$$Timeout$unref() { - references.add(this); this._refed = true; } /** * setTimeout method. setImmediate and setInterval are implemented in terms of setTimeout. + * @param {function} callback Function to run after delay + * @param {number} delayMs minimum number of ms to delay; false to run immediately + * @param {...} ...args arguments passed to callback + * @returns instance of Timer */ function eventLoop$$setTimeout(callback, delayMs, ...args) { @@ -68,17 +79,31 @@ function eventLoop$$setTimeout(callback, delayMs, ...args) function timerCallbackWrapper() { + const globalInit = require('./global-init'); + if (timer._destroyed === true) return; - callback.apply(this, ...args); + + try + { + const p = callback.apply(this, ...args); + if (p instanceof Promise) + p.catch(globalInit.unhandledRejection) + } + catch (error) + { + globalInit.unhandledException(error); + } + if (timer._repeat && typeof timer._repeat === 'number') enqueueWithDelay(callbackWrapper, Math.max(4, delayMs) / 1000, timer._repeat); else timer.unref(); - if (references.size === 0) - endLoop(); + maybeEndLoop(); } + + return timer; } function eventLoop$$setInterval(callback, delayMs, ...args) @@ -93,16 +118,55 @@ function eventLoop$$setImmediate(callback, ...args) return setTimeout(callback, false, ...args) } +/** + * Remove a timeout/interval/immediate by cleaning up JS object and removing Timer from Python's event loop. + */ function eventLoop$$clearTimeout(timer) { + if (timer._destroyed) + return; timer.unref(); timer._repeat = false; timer._destroyed = true; + cancelTimer(timer.pyHnd); +} + +/* Scan the pendingTimers for any event loop references. If there are none, clear all the pending timers + * and end the event loop. + */ +function maybeEndLoop() +{ + for (let pendingTimer of pendingTimers) + if (pendingTimer._refed === true) + return; + + for (let pendingTimer of pendingTimers) + eventLoop$$clearTimeout(pendingTimer); + + endLoop(); } +/** + * Remove all references - part of a clean shutdown. + */ +function eventLoop$$unrefEverything() +{ + for (let pendingTimer of pendingTimers) + pendingTimer.unref(); +} + +/* Enumerable exports are intended to replace global methods of the same name when running this style + * of event loop. + */ exports.setImmediate = eventLoop$$setImmediate; exports.setTimeout = eventLoop$$setTimeout; exports.setInterval = eventLoop$$setInterval; exports.clearTimeout = eventLoop$$clearTimeout; exports.clearInterval = eventLoop$$clearTimeout; exports.clearImmediate = eventLoop$$clearTimeout; + +/* Not enumerable -> not part of official/public API */ +Object.defineProperty(exports, 'unrefEverything', { + value: eventLoop$$unrefEverything, + enumerable: false +}); diff --git a/pmjs-lib/global-init.js b/pmjs-lib/global-init.js index 10c08544..c3a75162 100644 --- a/pmjs-lib/global-init.js +++ b/pmjs-lib/global-init.js @@ -15,6 +15,11 @@ for (let mid in require.cache) delete require.cache[mid]; +/* Patch the global object so that our event loop methods are the kind that understand references */ +const eventLoopMethods = require('./event-loop'); +for (let name in eventLoopMethods) + globalThis[name] = eventLoopMethods[name]; + /** * Set the global arguments array, which is just the program's argv. We use an argvBuilder function to * get around PythonMonkey's missing list->Array coercion. /wg june 2023 @@ -50,6 +55,11 @@ exports.initReplLibs = function pmjs$$initReplLibs() globalThis.util = require('util'); } -const eventLoopMethods = require('./event-loop'); -for (let name in eventLoopMethods) - globalThis[name] = eventLoopMethods[name]; +/** + * Temporary API until we get EventEmitters working. Replace this export for a custom handler. + */ +exports.uncaughtExceptionHandler = function globalInit$$uncaughtExceptionHandler(error) +{ + console.error(error); +} + From faf6f505855d07ece1b1153131b75b41fd1ae032 Mon Sep 17 00:00:00 2001 From: Wes Garland Date: Sun, 16 Jul 2023 16:00:43 -0400 Subject: [PATCH 006/428] pmjs - exit with code 1 when uncaught exception --- pmjs | 2 ++ tests/js/program-throw.bash | 29 +++++++++++++++++++++++++++++ tests/js/program-throw.js | 9 +++++++++ 3 files changed, 40 insertions(+) create mode 100755 tests/js/program-throw.bash create mode 100644 tests/js/program-throw.js diff --git a/pmjs b/pmjs index 996cf4e7..3cccf616 100755 --- a/pmjs +++ b/pmjs @@ -349,8 +349,10 @@ def main(): pm.runProgramModule(args[0], args, requirePath) except pm.SpiderMonkeyError as error: globalInitModule.uncaughtExceptionHandler(error) + cleanupExit(1) except Exception as error: print(error) + cleanupExit(1) def cleanupExit(code): eljs['unrefEverything']() diff --git a/tests/js/program-throw.bash b/tests/js/program-throw.bash new file mode 100755 index 00000000..ef94b774 --- /dev/null +++ b/tests/js/program-throw.bash @@ -0,0 +1,29 @@ +#! /bin/bash +# +# @file program-throw.bash +# A peter-jr test which shows that uncaught exceptions in the program throw, get shown +# on stderr, cause a non-zero exit code, and aren't delayed because of pending events. +# +# @author Wes Garland, wes@distributive.network +# @date July 2023 +# +# timeout: 5 + +set -u + +panic() +{ + echo "FAIL: $*" >&2 + exit 2 +} + +cd `dirname "$0"` || panic "could not change to test directory" + +"${PMJS:-../../pmjs}" ./program-throw.js 2>&1 1>/dev/null \ +| egrep 'hello|goodbye' \ +| while read line + do + [[ "$line" =~ goodbye ]] && panic "found goodbye - timer fired when it shouldn't have!" + [[ "$line" =~ hello ]] && echo "found expected '$line'" && exit 0 + echo wtf $line + done diff --git a/tests/js/program-throw.js b/tests/js/program-throw.js new file mode 100644 index 00000000..dd842f3e --- /dev/null +++ b/tests/js/program-throw.js @@ -0,0 +1,9 @@ +/** + * @file program-throw.js + * Support code program-throw.bash + * @author Wes Garland, wes@distributive.network + * @date July 2023 + */ + +setTimeout(() => console.error('goodbye'), 6000) +throw new Error('hello') From eda4c93b62325106ef0e41cc77a758bf0966d5b9 Mon Sep 17 00:00:00 2001 From: Wes Garland Date: Sun, 16 Jul 2023 16:11:43 -0400 Subject: [PATCH 007/428] fix unhandled exceptions from timers --- tests/js/timer-throw.bash | 38 ++++++++++++++++++++++++++++++++++++++ tests/js/timer-throw.js | 9 +++++++++ 2 files changed, 47 insertions(+) create mode 100755 tests/js/timer-throw.bash create mode 100644 tests/js/timer-throw.js diff --git a/tests/js/timer-throw.bash b/tests/js/timer-throw.bash new file mode 100755 index 00000000..a3d87804 --- /dev/null +++ b/tests/js/timer-throw.bash @@ -0,0 +1,38 @@ +#! /bin/bash +# +# @file program-throw.bash +# A peter-jr test which shows that uncaught exceptions in the program throw, get shown +# on stderr, cause a non-zero exit code, and aren't delayed because of pending events. +# +# @author Wes Garland, wes@distributive.network +# @date July 2023 +# +# timeout: 5 + +set -u + +panic() +{ + echo "FAIL: $*" >&2 + exit 2 +} + +cd `dirname "$0"` || panic "could not change to test directory" + +"${PMJS:-../../pmjs}" ./timer-throw.js 2>&1 1>/dev/null \ +| egrep 'hello|goodbye' \ +| ( + read line + if [[ "$line" =~ hello ]]; then + echo "found expected '$line'" + else + panic "expected hello, found '${line}'" + fi + + read line + if [[ "$line" =~ Error:.goodbye ]]; then + echo "found expected '$line'" + else + panic "expected Error: goodbye, found '${line}'" + fi + ) diff --git a/tests/js/timer-throw.js b/tests/js/timer-throw.js new file mode 100644 index 00000000..c9901890 --- /dev/null +++ b/tests/js/timer-throw.js @@ -0,0 +1,9 @@ +/** + * @file timer-throw.js + * Support code timer-throw.bash + * @author Wes Garland, wes@distributive.network + * @date July 2023 + */ + +setTimeout(() => { throw new Error('goodbye') }, 600); +console.error('hello'); From 688a1a12d2bd2ded859a7ee7ce47c9a2e992f2bd Mon Sep 17 00:00:00 2001 From: Wes Garland Date: Sun, 16 Jul 2023 17:05:27 -0400 Subject: [PATCH 008/428] peter-jr - improve timeout display, fix dynamic timeouts --- peter-jr | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/peter-jr b/peter-jr index d931a507..3d487c8e 100755 --- a/peter-jr +++ b/peter-jr @@ -21,6 +21,7 @@ cd "$runDir" set -u set -o pipefail peter_exit_code=2 +defaultTimeout="${defaultTimeout:-15}" if [ "${1:-}" = "-h" ] || [ "${1:-}" = "--help" ]; then cat < Date: Sun, 16 Jul 2023 17:08:24 -0400 Subject: [PATCH 009/428] pmjs - support unhandled rejections in event handlers --- pmjs-lib/event-loop.js | 4 ++-- pmjs-lib/global-init.js | 10 ++++++++ tests/js/timer-reject.bash | 47 ++++++++++++++++++++++++++++++++++++++ tests/js/timer-reject.js | 10 ++++++++ 4 files changed, 69 insertions(+), 2 deletions(-) create mode 100755 tests/js/timer-reject.bash create mode 100644 tests/js/timer-reject.js diff --git a/pmjs-lib/event-loop.js b/pmjs-lib/event-loop.js index 2222b34e..f45d4909 100644 --- a/pmjs-lib/event-loop.js +++ b/pmjs-lib/event-loop.js @@ -88,11 +88,11 @@ function eventLoop$$setTimeout(callback, delayMs, ...args) { const p = callback.apply(this, ...args); if (p instanceof Promise) - p.catch(globalInit.unhandledRejection) + p.catch(globalInit.unhandledRejectionHandler) } catch (error) { - globalInit.unhandledException(error); + globalInit.uncaughtExceptionHandler(error); } if (timer._repeat && typeof timer._repeat === 'number') diff --git a/pmjs-lib/global-init.js b/pmjs-lib/global-init.js index c3a75162..13f274cb 100644 --- a/pmjs-lib/global-init.js +++ b/pmjs-lib/global-init.js @@ -61,5 +61,15 @@ exports.initReplLibs = function pmjs$$initReplLibs() exports.uncaughtExceptionHandler = function globalInit$$uncaughtExceptionHandler(error) { console.error(error); + python.exit(1); +} + +/** + * Temporary API until we get EventEmitters working. Replace this export for a custom handler. + */ +exports.unhandledRejectionHandler = function globalInit$$unhandledRejectionHandler(error) +{ + console.error(error); + python.exit(1); } diff --git a/tests/js/timer-reject.bash b/tests/js/timer-reject.bash new file mode 100755 index 00000000..6cc3c89e --- /dev/null +++ b/tests/js/timer-reject.bash @@ -0,0 +1,47 @@ +#! /bin/bash +# +# @file timer-reject.bash +# A peter-jr test which shows that unhandled rejections in timers get shown on stderr, +# exit with status 1, and aren't delayed because of pending events. +# +# @author Wes Garland, wes@distributive.network +# @date July 2023 +# +# timeout: 10 + +set -u +set -o pipefail + +panic() +{ + echo "FAIL: $*" >&2 + exit 2 +} + +cd `dirname "$0"` || panic "could not change to test directory" + +"${PMJS:-../../pmjs}" ./timer-reject.js 2>&1 1>/dev/null \ +| egrep 'hello|goodbye|fire' \ +| ( + read line + if [[ "$line" =~ hello ]]; then + echo "found expected '$line'" + else + panic "expected hello, found '${line}'" + fi + + read line + if [[ "$line" =~ Error:.goodbye ]]; then + echo "found expected '$line'" + else + panic "expected Error: goodbye, found '${line}'" + fi + ) +exitCode="$?" + +if [ "${exitCode}" = "1" ]; then + echo pass + exit 0 +fi + +[ "$exitCode" = 2 ] || panic "Exit code was $exitCode" diff --git a/tests/js/timer-reject.js b/tests/js/timer-reject.js new file mode 100644 index 00000000..b756cd34 --- /dev/null +++ b/tests/js/timer-reject.js @@ -0,0 +1,10 @@ +/** + * @file timer-reject.js + * Support code timer-reject.bash + * @author Wes Garland, wes@distributive.network + * @date July 2023 + */ + +setTimeout(async () => { throw new Error('goodbye') }, 600); +setTimeout(async () => { console.warn('this should not fire') }, 2000); +console.error('hello'); From 343192c228cbb3bd3dd4293b9fe8078f194c8aa0 Mon Sep 17 00:00:00 2001 From: Wes Garland Date: Sun, 16 Jul 2023 17:18:31 -0400 Subject: [PATCH 010/428] pmjs - improve test coverage for timers, exit --- tests/js/program-exit.bash | 35 +++++++++++++++++++++++++++++++ tests/js/program-exit.js | 8 +++++++ tests/js/program-throw.bash | 1 - tests/js/timers-force-exit.simple | 13 ++++++++++++ tests/js/timers-natural-exit.bash | 27 ++++++++++++++++++++++++ tests/js/timers-natural-exit.js | 9 ++++++++ 6 files changed, 92 insertions(+), 1 deletion(-) create mode 100755 tests/js/program-exit.bash create mode 100644 tests/js/program-exit.js create mode 100644 tests/js/timers-force-exit.simple create mode 100755 tests/js/timers-natural-exit.bash create mode 100644 tests/js/timers-natural-exit.js diff --git a/tests/js/program-exit.bash b/tests/js/program-exit.bash new file mode 100755 index 00000000..70eb4987 --- /dev/null +++ b/tests/js/program-exit.bash @@ -0,0 +1,35 @@ +#! /bin/bash +# +# @file program-exit.bash +# A peter-jr test which shows that python.exit can cause a program to exit without +# reporting errors, even if there are pending timers. +# +# @author Wes Garland, wes@distributive.network +# @date July 2023 +# +# timeout: 5 + +set -u + +panic() +{ + echo "FAIL: $*" >&2 + exit 2 +} + +cd `dirname "$0"` || panic "could not change to test directory" + +"${PMJS:-../../pmjs}" ./program-exit.js 2>&1 \ +| while read line + do + panic "Unexpected output '$line'" + done +exitCode="$?" +[ "$exitCode" = 0 ] || exit "$exitCode" + +"${PMJS:-../../pmjs}" ./program-exit.js +exitCode="$?" + +[ "$exitCode" = "99" ] || panic "exit code should have been 99 but was $exitCode" + +exit 0 diff --git a/tests/js/program-exit.js b/tests/js/program-exit.js new file mode 100644 index 00000000..b88b0ed2 --- /dev/null +++ b/tests/js/program-exit.js @@ -0,0 +1,8 @@ +/** + * @file program-exit.js + * Support code program-exit.bash + * @author Wes Garland, wes@distributive.network + * @date July 2023 + */ +setTimeout(()=>console.log('hey'), 10400) +python.exit(99) diff --git a/tests/js/program-throw.bash b/tests/js/program-throw.bash index ef94b774..2f4d848c 100755 --- a/tests/js/program-throw.bash +++ b/tests/js/program-throw.bash @@ -25,5 +25,4 @@ cd `dirname "$0"` || panic "could not change to test directory" do [[ "$line" =~ goodbye ]] && panic "found goodbye - timer fired when it shouldn't have!" [[ "$line" =~ hello ]] && echo "found expected '$line'" && exit 0 - echo wtf $line done diff --git a/tests/js/timers-force-exit.simple b/tests/js/timers-force-exit.simple new file mode 100644 index 00000000..93e2eb79 --- /dev/null +++ b/tests/js/timers-force-exit.simple @@ -0,0 +1,13 @@ +/** + * @file timers-force-exit.simple + * ensure we can use python.exit() even though there are timers pending + * @author Wes Garland, wes@distributive.network + * @date July 2023 + * + * timeout: 2 + */ + +setTimeout(()=>console.log('fired timer'), 500000); +setTimeout(()=>console.error('should not have fired timer!'), 0); +console.log('about to exit even though timers are pending') +python.exit(0) diff --git a/tests/js/timers-natural-exit.bash b/tests/js/timers-natural-exit.bash new file mode 100755 index 00000000..00c5532b --- /dev/null +++ b/tests/js/timers-natural-exit.bash @@ -0,0 +1,27 @@ +#! /bin/bash +# +# @file timers-natural-exit.bash +# A peter-jr test which show that programs exit when the event loop becomes empty. +# +# @author Wes Garland, wes@distributive.network +# @date July 2023 + +set -u +set -o pipefail + +panic() +{ + echo "FAIL: $*" >&2 + exit 2 +} + +cd `dirname "$0"` || panic "could not change to test directory" + +"${PMJS:-../../pmjs}" ./timers-natural-exit.js \ +| egrep 'end of program|fired timer' \ +| ( + read line + [ "$line" = "end of program" ] || panic "first line read was '$line', not 'end of program'" + read line + [ "$line" = "fired timer" ] || panic "second line read was '$line', not 'fired timer'" + ) diff --git a/tests/js/timers-natural-exit.js b/tests/js/timers-natural-exit.js new file mode 100644 index 00000000..178e3cae --- /dev/null +++ b/tests/js/timers-natural-exit.js @@ -0,0 +1,9 @@ +/** + * @file timers-natural-exit.js + * Support code timers-natural-exit.bash + * @author Wes Garland, wes@distributive.network + * @date July 2023 + */ + +setTimeout(()=>console.log('fired timer'), 500); +console.log('end of program') From 6297147f76c06b2a1d903d25e9f76297abeeacb4 Mon Sep 17 00:00:00 2001 From: Wes Garland Date: Sun, 16 Jul 2023 17:35:02 -0400 Subject: [PATCH 011/428] pmjs - fix setInterval --- pmjs-lib/event-loop.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pmjs-lib/event-loop.js b/pmjs-lib/event-loop.js index f45d4909..9c9fa71f 100644 --- a/pmjs-lib/event-loop.js +++ b/pmjs-lib/event-loop.js @@ -96,7 +96,7 @@ function eventLoop$$setTimeout(callback, delayMs, ...args) } if (timer._repeat && typeof timer._repeat === 'number') - enqueueWithDelay(callbackWrapper, Math.max(4, delayMs) / 1000, timer._repeat); + enqueueWithDelay(timerCallbackWrapper, Math.max(4, timer._repeat) / 1000); else timer.unref(); From 68dca850cb135636a6b9430022879b20ad24692d Mon Sep 17 00:00:00 2001 From: Wes Garland Date: Sun, 16 Jul 2023 17:36:08 -0400 Subject: [PATCH 012/428] Add timers-segfaults.simple.failing for issue 112 --- tests/js/timers-segfault.simple.failing | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 tests/js/timers-segfault.simple.failing diff --git a/tests/js/timers-segfault.simple.failing b/tests/js/timers-segfault.simple.failing new file mode 100644 index 00000000..a902ecf2 --- /dev/null +++ b/tests/js/timers-segfault.simple.failing @@ -0,0 +1,12 @@ +/** + * @file timers-segfault.simlpe + * MRTC for a segfault when using the pmjs-lib/event-timers.js module. + * @author Wes Garland, wes@distributive.network + * @date July 2023 + * + * timeout: 10 + */ + +setTimeout(() => { /* a.push(1) */ 1 }); +const interval = setInterval(() => { 1 }, 500); +setTimeout(() => { 2 }, 1000); From ac645cfb2cba146af4fc012477cdb5f0e212ced2 Mon Sep 17 00:00:00 2001 From: Wes Garland Date: Mon, 17 Jul 2023 14:23:26 -0400 Subject: [PATCH 013/428] util.js - improve display of jsapi stacks w/ .code props --- python/pythonmonkey/builtin_modules/util.js | 23 +++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/python/pythonmonkey/builtin_modules/util.js b/python/pythonmonkey/builtin_modules/util.js index 4131cf98..dbe2fccb 100644 --- a/python/pythonmonkey/builtin_modules/util.js +++ b/python/pythonmonkey/builtin_modules/util.js @@ -1,5 +1,8 @@ /** * @file util.js + * Node.js-style util.inspect implementation, largely based on + * https://github.com/nodejs/node/blob/v8.17.0/lib/util.js. + * * @author Tom Tang * @date June 2023 */ @@ -532,7 +535,8 @@ function formatValue(ctx, value, recurseTimes, ln) { // Make error with message first say the error if (keyLength === 0) return formatError(ctx, value); - base = ` ${formatError(ctx, value)}`; + base = ` ${formatError(ctx, value)}\n`; + braces.length=0; } else if (isAnyArrayBuffer(value)) { // Fast path for ArrayBuffer and SharedArrayBuffer. // Can't do the same for DataView because it has a non-primitive @@ -647,10 +651,11 @@ function formatError(ctx, error) .split('\n') .filter(a => a.length > 0) .map(a => ` ${a}`); - return (`${error.name}: ${error.message}\n` - + stackEls[0] + '\n' - + style(stackEls.slice(1).join('\n')) - ); + const retstr = + `${error.name}: ${error.message}\n` + + stackEls[0] + '\n' + + style(stackEls.slice(1).join('\n')); + return retstr; } function formatObject(ctx, value, recurseTimes, keys) { @@ -871,7 +876,12 @@ function reduceToSingleString(ctx, output, base, braces, addLn) { } } if (length <= breakLength) - return `${braces[0]}${base} ${join(output, ', ')} ${braces[1]}`; + { + if (braces.length) + return `${braces[0]}${base} ${join(output, ', ')} ${braces[1]}`; + else + return `${base} ${join(output, ', ')}`; + } } // If the opening "brace" is too large, like in the case of "Set {", // we need to force the first item to be on the next line or the @@ -881,6 +891,7 @@ function reduceToSingleString(ctx, output, base, braces, addLn) { const ln = base === '' && braces[0].length === 1 ? ' ' : `${base}\n${indentation} `; const str = join(output, `,\n${indentation} `); + return `${extraLn}${braces[0]}${ln}${str} ${braces[1]}`; } From 95cb7fe2555f92c5b0a2b4fa8e6379d86d8fe81e Mon Sep 17 00:00:00 2001 From: Wes Garland Date: Mon, 17 Jul 2023 14:24:07 -0400 Subject: [PATCH 014/428] pmjs ropt, popt tests - fix error in failure-handling --- tests/js/pmjs-popt.bash | 2 +- tests/js/pmjs-ropt.bash | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/js/pmjs-popt.bash b/tests/js/pmjs-popt.bash index d5b19a89..9252bab7 100755 --- a/tests/js/pmjs-popt.bash +++ b/tests/js/pmjs-popt.bash @@ -27,7 +27,7 @@ do exit 111 ;; *) - echo "Ignored: ${keyword} ${rest} (${loaded})" + echo "Ignored: ${keyword} ${rest}" ;; esac done diff --git a/tests/js/pmjs-ropt.bash b/tests/js/pmjs-ropt.bash index 7c4e96f5..969b4bf2 100755 --- a/tests/js/pmjs-ropt.bash +++ b/tests/js/pmjs-ropt.bash @@ -27,7 +27,7 @@ do exit 111 ;; *) - echo "Ignored: ${keyword} ${rest} (${loaded})" + echo "Ignored: ${keyword} ${rest}" ;; esac done From 8b2d7179dce50ca03ae5cb09567e8ecb9a9204b6 Mon Sep 17 00:00:00 2001 From: Wes Garland Date: Mon, 17 Jul 2023 14:28:02 -0400 Subject: [PATCH 015/428] pmjs-lib/event-loop - throw if callback is not a function --- pmjs-lib/event-loop.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pmjs-lib/event-loop.js b/pmjs-lib/event-loop.js index 9c9fa71f..edd3a29f 100644 --- a/pmjs-lib/event-loop.js +++ b/pmjs-lib/event-loop.js @@ -10,6 +10,7 @@ */ 'use strict'; +const util = require('util'); const { enqueue, enqueueWithDelay, cancelTimer, endLoop } = require('./event-loop-asyncio'); const pendingTimers = new Set(); @@ -70,6 +71,13 @@ function eventLoop$$setTimeout(callback, delayMs, ...args) { var pyHnd, timer; + if (typeof callback !== 'function') + { + const error = new Error('Callback must be a function. Received ' + util.inspect(callback, { depth: 1, colors: false })); + error.code = 'ERR_INVALID_CALLBACK'; + throw error; + } + if (delayMs >= 0) pyHnd = enqueueWithDelay(timerCallbackWrapper, Math.max(4, delayMs) / 1000); else From 31f6b000bcc78f170c4c5fec970a62fc028d89e7 Mon Sep 17 00:00:00 2001 From: Wes Garland Date: Mon, 17 Jul 2023 14:51:13 -0400 Subject: [PATCH 016/428] createRequire - return existing require from module cache when exact filename match; add pminit node_modules to require.path --- python/pythonmonkey/require.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/python/pythonmonkey/require.py b/python/pythonmonkey/require.py index 4774cc0e..69942bb8 100644 --- a/python/pythonmonkey/require.py +++ b/python/pythonmonkey/require.py @@ -48,7 +48,8 @@ globalThis.python.pythonMonkey.dir = os.path.dirname(__file__) #globalThis.python.pythonMonkey.version = pm.__version__ #globalThis.python.pythonMonkey.module = pm -globalThis.python.pythonMonkey.isCompilableUnit = pm.isCompilableUnit; +globalThis.python.pythonMonkey.isCompilableUnit = pm.isCompilableUnit +globalThis.python.pythonMonkey.nodeModules = node_modules globalThis.python.print = print globalThis.python.stdout.write = sys.stdout.write globalThis.python.stderr.write = sys.stderr.write @@ -272,10 +273,15 @@ def _createRequireInner(*args): module.exports = python.load(filename); } + if (moduleCache[filename]) + return moduleCache[filename].require; + const module = new CtxModule(globalThis, filename, moduleCache); + moduleCache[filename] = module; for (let path of python.paths) module.paths.push(path + '/node_modules'); module.require.path.push(python.pythonMonkey.dir + '/builtin_modules'); + module.require.path.push(python.pythonMonkey.nodeModules); module.require.extensions['.py'] = loadPythonModule; if (isMain) From e790de3ec5fd0b91ddc5bb8d06b9313893e41250 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 27 Jun 2023 05:38:04 +0000 Subject: [PATCH 017/428] chore: update package-lock.json to use lockfileVersion 2 --- python/pminit/pythonmonkey/package-lock.json | 500 ++++++++++++++++++- 1 file changed, 499 insertions(+), 1 deletion(-) diff --git a/python/pminit/pythonmonkey/package-lock.json b/python/pminit/pythonmonkey/package-lock.json index 58f8278c..36fc56fe 100644 --- a/python/pminit/pythonmonkey/package-lock.json +++ b/python/pminit/pythonmonkey/package-lock.json @@ -1,8 +1,506 @@ { "name": "pythonmonkey", "version": "0.0.1", - "lockfileVersion": 1, + "lockfileVersion": 2, "requires": true, + "packages": { + "": { + "name": "pythonmonkey", + "version": "0.0.1", + "license": "MIT", + "dependencies": { + "ctx-module": "^1.0.12" + } + }, + "node_modules/asn1.js": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", + "dependencies": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/asn1.js/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==" + }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" + }, + "node_modules/browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dependencies": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "dependencies": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "node_modules/browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "dependencies": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/browserify-rsa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", + "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", + "dependencies": { + "bn.js": "^5.0.0", + "randombytes": "^2.0.1" + } + }, + "node_modules/browserify-sign": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz", + "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==", + "dependencies": { + "bn.js": "^5.1.1", + "browserify-rsa": "^4.0.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.3", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.5", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==" + }, + "node_modules/cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/create-ecdh": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", + "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", + "dependencies": { + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" + } + }, + "node_modules/create-ecdh/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "node_modules/create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "node_modules/crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "dependencies": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ctx-module": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/ctx-module/-/ctx-module-1.0.12.tgz", + "integrity": "sha512-iaple0ZSdEOq5Wdx7/eh6VvVZ5Rm4IICzvEulDiXXER+eGMgUlaPBBPZsV3aPhyy5LJNVwA4pKSqc0hIBvP0sA==", + "dependencies": { + "buffer": "^6.0.3", + "crypto-browserify": "^3.12.0" + } + }, + "node_modules/des.js": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz", + "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==", + "dependencies": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "dependencies": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + } + }, + "node_modules/diffie-hellman/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dependencies": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dependencies": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "bin": { + "miller-rabin": "bin/miller-rabin" + } + }, + "node_modules/miller-rabin/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==" + }, + "node_modules/parse-asn1": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", + "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", + "dependencies": { + "asn1.js": "^5.2.0", + "browserify-aes": "^1.0.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", + "dependencies": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "dependencies": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/public-encrypt/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "dependencies": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + } + }, "dependencies": { "asn1.js": { "version": "5.4.1", From d5cab0bd9c3a9935931bc9ea66cfac234819c802 Mon Sep 17 00:00:00 2001 From: Wes Garland Date: Tue, 18 Jul 2023 08:34:40 -0400 Subject: [PATCH 018/428] pmjs - don't plumb in setTimeout for repl, pass around {loop} to avoid NYI pm type errors --- pmjs | 5 ++--- pmjs-lib/event-loop-asyncio.py | 5 +++-- pmjs-lib/global-init.js | 15 ++++++++++----- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/pmjs b/pmjs index 3cccf616..b0244b88 100755 --- a/pmjs +++ b/pmjs @@ -223,7 +223,7 @@ def repl(): if (statement == ""): statement = input('> ')[readline_skip_chars:] readline_skip_chars = 0 - + if (len(statement) == 0): continue if (statement[0] == '.'): @@ -338,9 +338,8 @@ def main(): assert False, "unhandled option" if (len(args) > 0): - ela = pm.require('./pmjs-lib/event-loop-asyncio') + loop = globalInitModule.prepareEventLoop()['loop'] eljs = pm.require('./pmjs-lib/event-loop') - loop = ela['makeLoop']() async def runJS(): try: diff --git a/pmjs-lib/event-loop-asyncio.py b/pmjs-lib/event-loop-asyncio.py index 857b522a..910a2caf 100644 --- a/pmjs-lib/event-loop-asyncio.py +++ b/pmjs-lib/event-loop-asyncio.py @@ -36,7 +36,7 @@ def getLoop(): global loop if (loop == False): loop = asyncio.get_running_loop() - return loop + return { loop } def setLoop(newLoop): """ @@ -55,7 +55,8 @@ def makeLoop(): if (loop != False): raise Except("can't make loop - event loop already exists") loop = asyncio.new_event_loop() - return loop + + return { 'loop': loop } def endLoop(): """ diff --git a/pmjs-lib/global-init.js b/pmjs-lib/global-init.js index 13f274cb..d5992597 100644 --- a/pmjs-lib/global-init.js +++ b/pmjs-lib/global-init.js @@ -15,16 +15,21 @@ for (let mid in require.cache) delete require.cache[mid]; -/* Patch the global object so that our event loop methods are the kind that understand references */ -const eventLoopMethods = require('./event-loop'); -for (let name in eventLoopMethods) - globalThis[name] = eventLoopMethods[name]; +exports.prepareEventLoop = function globalInit$$prepareEventLoops() +{ + /* Patch the global object so that our event loop methods are the kind that understand references */ + const loopHnd = require('./event-loop-asyncio').makeLoop(); + const eventLoopMethods = require('./event-loop'); + for (let name in eventLoopMethods) + globalThis[name] = eventLoopMethods[name]; + return loopHnd; +} /** * Set the global arguments array, which is just the program's argv. We use an argvBuilder function to * get around PythonMonkey's missing list->Array coercion. /wg june 2023 */ -exports.makeArgvBuilder = function pmjsRequire$$makeArgvBuilder() +exports.makeArgvBuilder = function globalInit$$makeArgvBuilder() { const argv = []; globalThis.arguments = argv; From b9b8507c7c9027b3cd06ad75c0389db88a3b0233 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 19 Jul 2023 00:02:01 +0000 Subject: [PATCH 019/428] feat(pmpm): write our own minimum copy of npm in Python to remove the requirement for Node.js npm --- README.md | 1 - python/pminit/pmpm.py | 72 ++++++++++++++++++++++++++++++ python/pminit/post-install-hook.py | 17 +------ 3 files changed, 74 insertions(+), 16 deletions(-) create mode 100644 python/pminit/pmpm.py diff --git a/README.md b/README.md index 450a38da..784ae4ba 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,6 @@ Read this if you want to build a local version. - 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) diff --git a/python/pminit/pmpm.py b/python/pminit/pmpm.py new file mode 100644 index 00000000..d9986b7f --- /dev/null +++ b/python/pminit/pmpm.py @@ -0,0 +1,72 @@ +# @file pmpm.py +# A minimum copy of npm written in pure Python. +# Currently, this can only install dependencies specified by package-lock.json into node_modules. +# @author Tom Tang +# @date July 2023 + +import json +import io +import os, shutil +import tempfile +import tarfile +from dataclasses import dataclass +import urllib.request +from typing import List, Union + +WORK_DIR = os.path.join( + os.path.realpath(os.path.dirname(__file__)), + "pythonmonkey" +) + +@dataclass +class PackageItem: + installation_path: str + tarball_url: str + has_install_script: bool + +def parse_package_lock_json(json_data: Union[str, bytes]) -> List[PackageItem]: + # See https://docs.npmjs.com/cli/v9/configuring-npm/package-lock-json#packages + packages: dict = json.loads(json_data)["packages"] + items: List[PackageItem] = [] + for key, entry in packages.items(): + if key == "": + # Skip the root project (listed with a key of "") + continue + items.append( + PackageItem( + installation_path=key, # relative path from the root project folder + # The path is flattened for nested node_modules, e.g., "node_modules/create-ecdh/node_modules/bn.js" + tarball_url=entry["resolved"], # TODO: handle git dependencies + has_install_script=entry.get("hasInstallScript", False) # the package has a preinstall, install, or postinstall script + ) + ) + return items + +def download_package(tarball_url: str) -> bytes: + with urllib.request.urlopen(tarball_url) as response: + tarball_data: bytes = response.read() + return tarball_data + +def unpack_package(installation_path: str, tarball_data: bytes): + installation_path = os.path.join(WORK_DIR, installation_path) + shutil.rmtree(installation_path, ignore_errors=True) + + with tempfile.TemporaryDirectory(prefix="pmpm_cache-") as tmpdir: + with io.BytesIO(tarball_data) as tar_file: + with tarfile.open(fileobj=tar_file) as tar: + tar.extractall(tmpdir) + shutil.move( + os.path.join(tmpdir, "package"), # Strip the root folder + installation_path + ) + +def main(): + with open(os.path.join(WORK_DIR, "package-lock.json"), encoding="utf-8") as f: + items = parse_package_lock_json(f.read()) + for i in items: + print("Installing " + i.installation_path) + tarball_data = download_package(i.tarball_url) + unpack_package(i.installation_path, tarball_data) + +if __name__ == "__main__": + main() diff --git a/python/pminit/post-install-hook.py b/python/pminit/post-install-hook.py index 52f1e423..390f81c4 100644 --- a/python/pminit/post-install-hook.py +++ b/python/pminit/post-install-hook.py @@ -1,20 +1,7 @@ -import subprocess -import sys - -def execute(cmd: str): - popen = subprocess.Popen(cmd, stdout = subprocess.PIPE, stderr = subprocess.STDOUT, - shell = True, text = True ) - for stdout_line in iter(popen.stdout.readline, ""): - sys.stdout.write(stdout_line) - sys.stdout.flush() - - popen.stdout.close() - return_code = popen.wait() - if return_code: - raise subprocess.CalledProcessError(return_code, cmd) +import pmpm def main(): - execute("cd pythonmonkey && npm i --no-package-lock") # do not update package-lock.json + pmpm.main() # cd pythonmonkey && npm i if __name__ == "__main__": main() From 0e0d15d40a1f8163dcaf20ca105bdfd7afac974e Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 19 Jul 2023 00:08:06 +0000 Subject: [PATCH 020/428] fix(pmpm): import path for post-install-hook --- python/pminit/post-install-hook.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/pminit/post-install-hook.py b/python/pminit/post-install-hook.py index 390f81c4..58deb01e 100644 --- a/python/pminit/post-install-hook.py +++ b/python/pminit/post-install-hook.py @@ -1,4 +1,4 @@ -import pmpm +from . import pmpm def main(): pmpm.main() # cd pythonmonkey && npm i From 5757ac2ead1af778fcd89300562a057be4415b60 Mon Sep 17 00:00:00 2001 From: Wes Garland Date: Wed, 19 Jul 2023 07:57:57 -0400 Subject: [PATCH 021/428] Move pmjs libs to python/pythonmonkey/lib/pmjs --- {pmjs-lib => python/pythonmonkey/lib/pmjs}/event-loop-asyncio.py | 0 {pmjs-lib => python/pythonmonkey/lib/pmjs}/event-loop.js | 0 {pmjs-lib => python/pythonmonkey/lib/pmjs}/global-init.js | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename {pmjs-lib => python/pythonmonkey/lib/pmjs}/event-loop-asyncio.py (100%) rename {pmjs-lib => python/pythonmonkey/lib/pmjs}/event-loop.js (100%) rename {pmjs-lib => python/pythonmonkey/lib/pmjs}/global-init.js (100%) diff --git a/pmjs-lib/event-loop-asyncio.py b/python/pythonmonkey/lib/pmjs/event-loop-asyncio.py similarity index 100% rename from pmjs-lib/event-loop-asyncio.py rename to python/pythonmonkey/lib/pmjs/event-loop-asyncio.py diff --git a/pmjs-lib/event-loop.js b/python/pythonmonkey/lib/pmjs/event-loop.js similarity index 100% rename from pmjs-lib/event-loop.js rename to python/pythonmonkey/lib/pmjs/event-loop.js diff --git a/pmjs-lib/global-init.js b/python/pythonmonkey/lib/pmjs/global-init.js similarity index 100% rename from pmjs-lib/global-init.js rename to python/pythonmonkey/lib/pmjs/global-init.js From 69193ac912e9b895b3ee10d3cd2a6f287b6fcbac Mon Sep 17 00:00:00 2001 From: Wes Garland Date: Wed, 19 Jul 2023 08:01:00 -0400 Subject: [PATCH 022/428] Update pmjs to load event-loop libs from lib/pmjs --- python/pythonmonkey/cli/pmjs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/pythonmonkey/cli/pmjs.py b/python/pythonmonkey/cli/pmjs.py index 6ec4ecf4..775dde46 100755 --- a/python/pythonmonkey/cli/pmjs.py +++ b/python/pythonmonkey/cli/pmjs.py @@ -339,7 +339,7 @@ def main(): if (len(args) > 0): loop = globalInitModule.prepareEventLoop()['loop'] - eljs = pm.require('./pmjs-lib/event-loop') + eljs = pm.require('../lib/pmjs/event-loop') async def runJS(): try: From 6c774fbea9cc25ab99da5b3dfaaf4fbf4c5a88f1 Mon Sep 17 00:00:00 2001 From: Wes Garland Date: Wed, 19 Jul 2023 11:36:47 -0400 Subject: [PATCH 023/428] Implement python.on('uncaughtException') and python.on('unhandledRejection') --- python/pminit/pythonmonkey/package-lock.json | 5 +++ python/pminit/pythonmonkey/package.json | 3 +- python/pythonmonkey/lib/pmjs/global-init.js | 35 +++++++++++++++++--- 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/python/pminit/pythonmonkey/package-lock.json b/python/pminit/pythonmonkey/package-lock.json index 58f8278c..73425c54 100644 --- a/python/pminit/pythonmonkey/package-lock.json +++ b/python/pminit/pythonmonkey/package-lock.json @@ -234,6 +234,11 @@ } } }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" + }, "evp_bytestokey": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", diff --git a/python/pminit/pythonmonkey/package.json b/python/pminit/pythonmonkey/package.json index 9a5cce4b..af06ddb8 100644 --- a/python/pminit/pythonmonkey/package.json +++ b/python/pminit/pythonmonkey/package.json @@ -21,6 +21,7 @@ }, "homepage": "https://github.com/Distributive-Network/PythonMonkey#readme", "dependencies": { - "ctx-module": "^1.0.13" + "ctx-module": "^1.0.13", + "events": "^3.3.0" } } diff --git a/python/pythonmonkey/lib/pmjs/global-init.js b/python/pythonmonkey/lib/pmjs/global-init.js index d5992597..99c2bd5b 100644 --- a/python/pythonmonkey/lib/pmjs/global-init.js +++ b/python/pythonmonkey/lib/pmjs/global-init.js @@ -15,6 +15,20 @@ for (let mid in require.cache) delete require.cache[mid]; +/* Recreate the python object as an EventEmitter */ +const { EventEmitter } = require('events'); +const originalPython = globalThis.python; +const python = globalThis.python = new EventEmitter('python'); +Object.assign(python, originalPython); + +/* Emulate node's process.on('error') behaviour with python.on('error'). */ +python.on('error', function unhandledError() { + if (python.listenerCount('error') > 1) + return; + if (python.listenerCount('error') === 0 || python.listeners('error')[0] === unhandledErrror) + python.emit('unhandledException', error); +}); + exports.prepareEventLoop = function globalInit$$prepareEventLoops() { /* Patch the global object so that our event loop methods are the kind that understand references */ @@ -58,6 +72,7 @@ exports.patchGlobalRequire = function pmjs$$patchGlobalRequire() exports.initReplLibs = function pmjs$$initReplLibs() { globalThis.util = require('util'); + globalThis.events = require('events'); } /** @@ -65,8 +80,14 @@ exports.initReplLibs = function pmjs$$initReplLibs() */ exports.uncaughtExceptionHandler = function globalInit$$uncaughtExceptionHandler(error) { - console.error(error); - python.exit(1); + error.name = 'Uncaught ' + error.name; + if (python._events && python._events['uncaughtException']) + python.emit('uncaughtException', error); + else + { + console.error(error); + python.exit(1); + } } /** @@ -74,7 +95,11 @@ exports.uncaughtExceptionHandler = function globalInit$$uncaughtExceptionHandler */ exports.unhandledRejectionHandler = function globalInit$$unhandledRejectionHandler(error) { - console.error(error); - python.exit(1); + if (python._events && python._events['uncaughtRejection']) + python.emit('unhandledRejection', error); + else + { + console.error(error); + python.exit(1); + } } - From 3646564bfbb60ad6c4f412247287887fa639eda5 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 2 Aug 2023 06:47:13 +0000 Subject: [PATCH 024/428] cleanup --- python/pythonmonkey/cli/pmjs.py | 4 +- .../lib/pmjs/event-loop-asyncio.py | 82 -------- python/pythonmonkey/lib/pmjs/event-loop.js | 180 ------------------ python/pythonmonkey/lib/pmjs/global-init.js | 14 +- 4 files changed, 3 insertions(+), 277 deletions(-) delete mode 100644 python/pythonmonkey/lib/pmjs/event-loop-asyncio.py delete mode 100644 python/pythonmonkey/lib/pmjs/event-loop.js diff --git a/python/pythonmonkey/cli/pmjs.py b/python/pythonmonkey/cli/pmjs.py index fca4a973..7b70d43a 100755 --- a/python/pythonmonkey/cli/pmjs.py +++ b/python/pythonmonkey/cli/pmjs.py @@ -368,12 +368,10 @@ async def runJS(): except Exception as error: print(error, file=sys.stderr) sys.exit(1) - asyncio.run(runJS()) - elif (enterRepl or forceRepl): globalInitModule.initReplLibs() repl() if __name__ == "__main__": - main(); + main() diff --git a/python/pythonmonkey/lib/pmjs/event-loop-asyncio.py b/python/pythonmonkey/lib/pmjs/event-loop-asyncio.py deleted file mode 100644 index 910a2caf..00000000 --- a/python/pythonmonkey/lib/pmjs/event-loop-asyncio.py +++ /dev/null @@ -1,82 +0,0 @@ -# @file event-loop-asyncio.py -# Interface to the asyncio module for the event-loop library. We can't use JavaScript for -# some of this code, because PythonMonkey can't transport things like asyncio.TimerHandler -# and event loops as of version 0.2.0. -# @author Wes Garland, wes@distributive.network -# @date July 2023 -# -import asyncio - -loop = False - -def enqueueWithDelay(callback, delay): - """ - Schedule a callback to run after a certain amount of time. Delay is in seconds. - """ - return { 'timer': loop.call_later(delay, callback) } - -def enqueue(callback): - """ - Schedule a callback to run as soon as possible. - """ - return { 'timer': loop.call_soon(callback) } - -def cancelTimer(pyHnd): - """ - Cancel a timer that was previously enqueued. The pyHnd argument is the return value from one of the - enqueue functions. - """ - pyHnd['timer'].cancel() - -def getLoop(): - """ - Get the current Python event loop used by this code. If no loop has been specified and this is the - first time this function is run, we start using the event loop that invoked this call. - """ - global loop - if (loop == False): - loop = asyncio.get_running_loop() - return { loop } - -def setLoop(newLoop): - """ - Set the event loop this code will use. Replacing a running loop is not allowed. - """ - global loop - if (loop != False and loop != newLoop): - raise Except("can't set loop - event loop already exists") - loop = newLoop - -def makeLoop(): - """ - Make a new event loop. - """ - global loop - if (loop != False): - raise Except("can't make loop - event loop already exists") - loop = asyncio.new_event_loop() - - return { 'loop': loop } - -def endLoop(): - """ - End the event loop. This will throw if there are pending events. - """ - global loop - if (loop != False): - loop.stop() - loop = False - -def uptime(): - """ - Return the number of seconds this event loop has been running. - """ - return loop.time() - -exports['enqueueWithDelay'] = enqueueWithDelay -exports['enqueue'] = enqueue -exports['cancelTimer'] = cancelTimer -exports['getLoop'] = getLoop -exports['setLoop'] = setLoop -exports['makeLoop'] = makeLoop -exports['endLoop'] = endLoop diff --git a/python/pythonmonkey/lib/pmjs/event-loop.js b/python/pythonmonkey/lib/pmjs/event-loop.js deleted file mode 100644 index edd3a29f..00000000 --- a/python/pythonmonkey/lib/pmjs/event-loop.js +++ /dev/null @@ -1,180 +0,0 @@ -/** - * @file event-loops.js - * Code for creating and manipulating a NodeJS-style reference-centric event loop for use - * within pmjs. The code currently in builtin_modules/timers.js implements WHATWG-spec- - * compliant timers, but this code needs different functionality and access to the Python - * awaitables implementing the timers because of that. - * - * @author Wes Garland, wes@distributive.network - * @date July 2023 - */ -'use strict'; - -const util = require('util'); -const { enqueue, enqueueWithDelay, cancelTimer, endLoop } = require('./event-loop-asyncio'); - -const pendingTimers = new Set(); -var seq = 0; - -/** - * Timeout constructor. This is the handle returned from setTimeout, setInterval, and setImmediate in an - * environment with a node-style event-loop. We implement the following methods, modelled on Node.js: - * - ref() - * - unref() - * - toString() - * - * Also like Node.js, there is a repeat property on this handle which controls if it is re-scheduled - * every time it fires. This is the main difference between intervals and timeouts. - * - * @param {Dict} pyHnd a dict with a timer attribute which can be used for cancelling the timeout - */ -function Timeout(pyHnd) -{ - this.id = ++seq; - this.pyHnd = pyHnd; - this.repeat = false; - this.ref(); - - pendingTimers.add(this); -} - -Timeout.prototype.toString = function eventLoop$$Timeout$toString() -{ - return `${this.id}` -} - -/** - * Remove a reference from a timer. Program will not naturally exit until all references are removed. - */ -Timeout.prototype.unref = function eventLoop$$Timeout$unref() -{ - this._refed = false; -} - -/** - * Add a reference to a timer. Program will not naturally exit until all references are removed. Timers - * are referenced by default. References are binary, on/off, not counted. - */ -Timeout.prototype.ref = function eventLoop$$Timeout$unref() -{ - this._refed = true; -} - -/** - * setTimeout method. setImmediate and setInterval are implemented in terms of setTimeout. - * @param {function} callback Function to run after delay - * @param {number} delayMs minimum number of ms to delay; false to run immediately - * @param {...} ...args arguments passed to callback - * @returns instance of Timer - */ -function eventLoop$$setTimeout(callback, delayMs, ...args) -{ - var pyHnd, timer; - - if (typeof callback !== 'function') - { - const error = new Error('Callback must be a function. Received ' + util.inspect(callback, { depth: 1, colors: false })); - error.code = 'ERR_INVALID_CALLBACK'; - throw error; - } - - if (delayMs >= 0) - pyHnd = enqueueWithDelay(timerCallbackWrapper, Math.max(4, delayMs) / 1000); - else - pyHnd = enqueue(timerCallbackWrapper); - - timer = new Timeout(pyHnd); - - function timerCallbackWrapper() - { - const globalInit = require('./global-init'); - - if (timer._destroyed === true) - return; - - try - { - const p = callback.apply(this, ...args); - if (p instanceof Promise) - p.catch(globalInit.unhandledRejectionHandler) - } - catch (error) - { - globalInit.uncaughtExceptionHandler(error); - } - - if (timer._repeat && typeof timer._repeat === 'number') - enqueueWithDelay(timerCallbackWrapper, Math.max(4, timer._repeat) / 1000); - else - timer.unref(); - - maybeEndLoop(); - } - - return timer; -} - -function eventLoop$$setInterval(callback, delayMs, ...args) -{ - const timer = eventLoop$$setTimeout(callback, delayMs, ...args) - timer._repeat = delayMs; - return timer; -} - -function eventLoop$$setImmediate(callback, ...args) -{ - return setTimeout(callback, false, ...args) -} - -/** - * Remove a timeout/interval/immediate by cleaning up JS object and removing Timer from Python's event loop. - */ -function eventLoop$$clearTimeout(timer) -{ - if (timer._destroyed) - return; - timer.unref(); - timer._repeat = false; - timer._destroyed = true; - cancelTimer(timer.pyHnd); -} - -/* Scan the pendingTimers for any event loop references. If there are none, clear all the pending timers - * and end the event loop. - */ -function maybeEndLoop() -{ - for (let pendingTimer of pendingTimers) - if (pendingTimer._refed === true) - return; - - for (let pendingTimer of pendingTimers) - eventLoop$$clearTimeout(pendingTimer); - - endLoop(); -} - -/** - * Remove all references - part of a clean shutdown. - */ -function eventLoop$$unrefEverything() -{ - for (let pendingTimer of pendingTimers) - pendingTimer.unref(); -} - -/* Enumerable exports are intended to replace global methods of the same name when running this style - * of event loop. - */ -exports.setImmediate = eventLoop$$setImmediate; -exports.setTimeout = eventLoop$$setTimeout; -exports.setInterval = eventLoop$$setInterval; -exports.clearTimeout = eventLoop$$clearTimeout; -exports.clearInterval = eventLoop$$clearTimeout; -exports.clearImmediate = eventLoop$$clearTimeout; - -/* Not enumerable -> not part of official/public API */ -Object.defineProperty(exports, 'unrefEverything', { - value: eventLoop$$unrefEverything, - enumerable: false -}); diff --git a/python/pythonmonkey/lib/pmjs/global-init.js b/python/pythonmonkey/lib/pmjs/global-init.js index 99c2bd5b..fa60b757 100644 --- a/python/pythonmonkey/lib/pmjs/global-init.js +++ b/python/pythonmonkey/lib/pmjs/global-init.js @@ -22,22 +22,12 @@ const python = globalThis.python = new EventEmitter('python'); Object.assign(python, originalPython); /* Emulate node's process.on('error') behaviour with python.on('error'). */ -python.on('error', function unhandledError() { +python.on('error', function unhandledError(error) { if (python.listenerCount('error') > 1) return; - if (python.listenerCount('error') === 0 || python.listeners('error')[0] === unhandledErrror) + if (python.listenerCount('error') === 0 || python.listeners('error')[0] === unhandledError) python.emit('unhandledException', error); }); - -exports.prepareEventLoop = function globalInit$$prepareEventLoops() -{ - /* Patch the global object so that our event loop methods are the kind that understand references */ - const loopHnd = require('./event-loop-asyncio').makeLoop(); - const eventLoopMethods = require('./event-loop'); - for (let name in eventLoopMethods) - globalThis[name] = eventLoopMethods[name]; - return loopHnd; -} /** * Set the global arguments array, which is just the program's argv. We use an argvBuilder function to From 92d454fef504ad31ed3c1ef07c5963dff4881e89 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 2 Aug 2023 07:26:24 +0000 Subject: [PATCH 025/428] fix(pmjs): exception catching in event-loop --- python/pythonmonkey/cli/pmjs.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/python/pythonmonkey/cli/pmjs.py b/python/pythonmonkey/cli/pmjs.py index 7b70d43a..fd29a27c 100755 --- a/python/pythonmonkey/cli/pmjs.py +++ b/python/pythonmonkey/cli/pmjs.py @@ -358,13 +358,24 @@ def main(): if (len(args) > 0): async def runJS(): + loop = asyncio.get_running_loop() + # See https://docs.python.org/3.11/library/asyncio-eventloop.html#error-handling-api + def exceptionHandler(loop, context): + error = context["exception"] + try: + globalInitModule.uncaughtExceptionHandler(error) + except: + pass + finally: + os._exit(1) + loop.set_exception_handler(exceptionHandler) + + globalThis.python.exit = lambda status: os._exit(int(status)) + try: globalInitModule.patchGlobalRequire() pm.runProgramModule(args[0], args, requirePath) await pm.wait() # blocks until all asynchronous calls finish - except pm.SpiderMonkeyError as error: - globalInitModule.uncaughtExceptionHandler(error) - sys.exit(1) except Exception as error: print(error, file=sys.stderr) sys.exit(1) From aa8f8e81c3b666b2341cbdaef8d6a62c270b1eb2 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Fri, 4 Aug 2023 09:26:21 +0000 Subject: [PATCH 026/428] feat(event-loop): `pm.stop()` to stop all pending asynchronous jobs --- include/PyEventLoop.hh | 6 ++++++ python/pythonmonkey/cli/pmjs.py | 15 ++++++++++++--- python/pythonmonkey/pythonmonkey.pyi | 5 +++++ src/PyEventLoop.cc | 8 ++++++++ src/modules/pythonmonkey/pythonmonkey.cc | 6 ++++++ 5 files changed, 37 insertions(+), 3 deletions(-) diff --git a/include/PyEventLoop.hh b/include/PyEventLoop.hh index 36fdb03c..5c07e30d 100644 --- a/include/PyEventLoop.hh +++ b/include/PyEventLoop.hh @@ -65,6 +65,12 @@ public: } } + /** + * @brief Cancel all pending event-loop jobs. + * @return success + */ + static bool cancelAll(); + /** * @brief Get the underlying `asyncio.Handle` Python object */ diff --git a/python/pythonmonkey/cli/pmjs.py b/python/pythonmonkey/cli/pmjs.py index fd29a27c..55bc7419 100755 --- a/python/pythonmonkey/cli/pmjs.py +++ b/python/pythonmonkey/cli/pmjs.py @@ -358,24 +358,33 @@ def main(): if (len(args) > 0): async def runJS(): + hasUncaughtException = False loop = asyncio.get_running_loop() # See https://docs.python.org/3.11/library/asyncio-eventloop.html#error-handling-api def exceptionHandler(loop, context): error = context["exception"] try: globalInitModule.uncaughtExceptionHandler(error) - except: + except SystemExit: # the "exception" raised by `sys.exit()` call pass finally: - os._exit(1) + pm.stop() # unblock `await pm.wait()` to gracefully exit the program + nonlocal hasUncaughtException + hasUncaughtException = True loop.set_exception_handler(exceptionHandler) - globalThis.python.exit = lambda status: os._exit(int(status)) + def cleanupExit(code): + pm.stop() + realExit(code) + realExit = globalThis.python.exit + globalThis.python.exit = cleanupExit try: globalInitModule.patchGlobalRequire() pm.runProgramModule(args[0], args, requirePath) await pm.wait() # blocks until all asynchronous calls finish + if hasUncaughtException: + sys.exit(1) except Exception as error: print(error, file=sys.stderr) sys.exit(1) diff --git a/python/pythonmonkey/pythonmonkey.pyi b/python/pythonmonkey/pythonmonkey.pyi index 15bed09d..8318a562 100644 --- a/python/pythonmonkey/pythonmonkey.pyi +++ b/python/pythonmonkey/pythonmonkey.pyi @@ -33,6 +33,11 @@ def wait() -> _typing.Awaitable[None]: This is the event-loop shield that protects the loop from being prematurely terminated. """ +def stop() -> None: + """ + Stop all pending asynchronous jobs, and unblock `await pm.wait()` + """ + def isCompilableUnit(code: str) -> bool: """ Hint if a string might be compilable Javascript without actual evaluation diff --git a/src/PyEventLoop.cc b/src/PyEventLoop.cc index d5b7f0a9..4b98980c 100644 --- a/src/PyEventLoop.cc +++ b/src/PyEventLoop.cc @@ -154,6 +154,14 @@ void PyEventLoop::AsyncHandle::cancel() { Py_XDECREF(ret); } +/* static */ +bool PyEventLoop::AsyncHandle::cancelAll() { + for (AsyncHandle &handle: _timeoutIdMap) { + handle.cancel(); + } + return true; +} + void PyEventLoop::Future::setResult(PyObject *result) { // https://docs.python.org/3/library/asyncio-future.html#asyncio.Future.set_result PyObject *ret = PyObject_CallMethod(_future, "set_result", "O", result); // returns None diff --git a/src/modules/pythonmonkey/pythonmonkey.cc b/src/modules/pythonmonkey/pythonmonkey.cc index 21b92ec7..f35c395b 100644 --- a/src/modules/pythonmonkey/pythonmonkey.cc +++ b/src/modules/pythonmonkey/pythonmonkey.cc @@ -279,6 +279,11 @@ static PyObject *waitForEventLoop(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED return PyObject_CallMethod(waiter, "wait", NULL); } +static PyObject *closeAllPending(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(_)) { + if (!PyEventLoop::AsyncHandle::cancelAll()) return NULL; + Py_RETURN_NONE; +} + static PyObject *isCompilableUnit(PyObject *self, PyObject *args) { StrType *buffer = new StrType(PyTuple_GetItem(args, 0)); const char *bufferUtf8; @@ -301,6 +306,7 @@ static PyObject *isCompilableUnit(PyObject *self, PyObject *args) { PyMethodDef PythonMonkeyMethods[] = { {"eval", eval, METH_VARARGS, "Javascript evaluator in Python"}, {"wait", waitForEventLoop, METH_NOARGS, "The event-loop shield. Blocks until all asynchronous jobs finish."}, + {"stop", closeAllPending, METH_NOARGS, "Cancel all pending event-loop jobs."}, {"isCompilableUnit", isCompilableUnit, METH_VARARGS, "Hint if a string might be compilable Javascript"}, {"collect", collect, METH_VARARGS, "Calls the spidermonkey garbage collector"}, {NULL, NULL, 0, NULL} From 4da2838c0754f2c802be820fd1a10196dab74823 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Fri, 4 Aug 2023 09:33:40 +0000 Subject: [PATCH 027/428] fix(event-loop): `decCounter()` fails if python error indicator is set --- src/PyEventLoop.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/PyEventLoop.cc b/src/PyEventLoop.cc index 4b98980c..ca597a5b 100644 --- a/src/PyEventLoop.cc +++ b/src/PyEventLoop.cc @@ -8,7 +8,12 @@ static PyObject *eventLoopJobWrapper(PyObject *jobFn, PyObject *Py_UNUSED(_)) { PyObject *ret = PyObject_CallObject(jobFn, NULL); // jobFn() Py_XDECREF(ret); // don't care about its return value + + PyObject *type, *value, *traceback; + PyErr_Fetch(&type, &value, &traceback); // Protects `decCounter()`. If the error indicator is set, Python cannot make further function calls. PyEventLoop::_locker->decCounter(); + PyErr_Restore(type, value, traceback); + if (PyErr_Occurred()) { return NULL; } else { From c868ff4249f888b96d5aecd3c5915456f286a66a Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 8 May 2024 20:13:42 +0000 Subject: [PATCH 028/428] refactor(pmpm): support any abstract working directory --- python/pminit/pmpm.py | 17 ++++++----------- python/pminit/post-install-hook.py | 8 +++++++- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/python/pminit/pmpm.py b/python/pminit/pmpm.py index d9986b7f..59a78a14 100644 --- a/python/pminit/pmpm.py +++ b/python/pminit/pmpm.py @@ -13,11 +13,6 @@ import urllib.request from typing import List, Union -WORK_DIR = os.path.join( - os.path.realpath(os.path.dirname(__file__)), - "pythonmonkey" -) - @dataclass class PackageItem: installation_path: str @@ -47,8 +42,8 @@ def download_package(tarball_url: str) -> bytes: tarball_data: bytes = response.read() return tarball_data -def unpack_package(installation_path: str, tarball_data: bytes): - installation_path = os.path.join(WORK_DIR, installation_path) +def unpack_package(work_dir:str, installation_path: str, tarball_data: bytes): + installation_path = os.path.join(work_dir, installation_path) shutil.rmtree(installation_path, ignore_errors=True) with tempfile.TemporaryDirectory(prefix="pmpm_cache-") as tmpdir: @@ -60,13 +55,13 @@ def unpack_package(installation_path: str, tarball_data: bytes): installation_path ) -def main(): - with open(os.path.join(WORK_DIR, "package-lock.json"), encoding="utf-8") as f: +def main(work_dir: str): + with open(os.path.join(work_dir, "package-lock.json"), encoding="utf-8") as f: items = parse_package_lock_json(f.read()) for i in items: print("Installing " + i.installation_path) tarball_data = download_package(i.tarball_url) - unpack_package(i.installation_path, tarball_data) + unpack_package(work_dir, i.installation_path, tarball_data) if __name__ == "__main__": - main() + main(os.getcwd()) diff --git a/python/pminit/post-install-hook.py b/python/pminit/post-install-hook.py index 58deb01e..36256974 100644 --- a/python/pminit/post-install-hook.py +++ b/python/pminit/post-install-hook.py @@ -1,7 +1,13 @@ +import os from . import pmpm +WORK_DIR = os.path.join( + os.path.realpath(os.path.dirname(__file__)), + "pythonmonkey" +) + def main(): - pmpm.main() # cd pythonmonkey && npm i + pmpm.main(WORK_DIR) # cd pythonmonkey && npm i if __name__ == "__main__": main() From fb4b0af66a4ca7254903c2198e22c4144af0e87a Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 8 May 2024 20:35:55 +0000 Subject: [PATCH 029/428] fix(pmpm): import pmpm for post-install-hook --- python/pminit/post-install-hook.py | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/python/pminit/post-install-hook.py b/python/pminit/post-install-hook.py index 36256974..bf6ed7ab 100644 --- a/python/pminit/post-install-hook.py +++ b/python/pminit/post-install-hook.py @@ -1,13 +1,28 @@ import os -from . import pmpm +import sys +import importlib +import importlib.util WORK_DIR = os.path.join( - os.path.realpath(os.path.dirname(__file__)), - "pythonmonkey" + os.path.realpath(os.path.dirname(__file__)), + "pythonmonkey" ) +def import_file(module_name: str, file_path: str): + """ + Import a Python file from its relative path directly. + + See https://docs.python.org/3/library/importlib.html#importing-a-source-file-directly + """ + spec = importlib.util.spec_from_file_location(module_name, file_path) + module = importlib.util.module_from_spec(spec) # type: ignore + sys.modules[module_name] = module + spec.loader.exec_module(module) # type: ignore + return module + def main(): - pmpm.main(WORK_DIR) # cd pythonmonkey && npm i + pmpm = import_file("pmpm", os.path.join(os.path.dirname(__file__), "./pmpm.py")) # from . import pmpm + pmpm.main(WORK_DIR) # cd pythonmonkey && npm i if __name__ == "__main__": - main() + main() From 2b99eebdd172941f3a3b86e0647acef2f0f7e1d4 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 8 May 2024 20:50:13 +0000 Subject: [PATCH 030/428] fix(pmpm): fix importing pmpm for post-install-hook --- python/pminit/post-install-hook.py | 17 +---------------- python/pminit/pyproject.toml | 1 + 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/python/pminit/post-install-hook.py b/python/pminit/post-install-hook.py index bf6ed7ab..061492c1 100644 --- a/python/pminit/post-install-hook.py +++ b/python/pminit/post-install-hook.py @@ -1,27 +1,12 @@ import os -import sys -import importlib -import importlib.util +import pmpm WORK_DIR = os.path.join( os.path.realpath(os.path.dirname(__file__)), "pythonmonkey" ) -def import_file(module_name: str, file_path: str): - """ - Import a Python file from its relative path directly. - - See https://docs.python.org/3/library/importlib.html#importing-a-source-file-directly - """ - spec = importlib.util.spec_from_file_location(module_name, file_path) - module = importlib.util.module_from_spec(spec) # type: ignore - sys.modules[module_name] = module - spec.loader.exec_module(module) # type: ignore - return module - def main(): - pmpm = import_file("pmpm", os.path.join(os.path.dirname(__file__), "./pmpm.py")) # from . import pmpm pmpm.main(WORK_DIR) # cd pythonmonkey && npm i if __name__ == "__main__": diff --git a/python/pminit/pyproject.toml b/python/pminit/pyproject.toml index 9910cc72..31dce5b7 100644 --- a/python/pminit/pyproject.toml +++ b/python/pminit/pyproject.toml @@ -9,6 +9,7 @@ authors = [ "Hamada Gasmallah " ] include = [ + "pmpm.py", # Install extra files into the pythonmonkey package "pythonmonkey/package*.json", { path = "pythonmonkey/node_modules/**/*", format = "wheel" }, From 6a0c5cf9b98f430f6d71eeb42c6782d9a84278ff Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 8 May 2024 21:42:55 +0000 Subject: [PATCH 031/428] fix merging errors --- python/pythonmonkey/cli/pmjs.py | 34 ++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/python/pythonmonkey/cli/pmjs.py b/python/pythonmonkey/cli/pmjs.py index a7a50070..27f06d98 100755 --- a/python/pythonmonkey/cli/pmjs.py +++ b/python/pythonmonkey/cli/pmjs.py @@ -378,9 +378,37 @@ async def runEvalPrint(): if (len(args) > 0): async def runJS(): - globalInitModule.patchGlobalRequire() - pm.runProgramModule(args[0], args, requirePath) - await pm.wait() # blocks until all asynchronous calls finish + hasUncaughtException = False + loop = asyncio.get_running_loop() + # See https://docs.python.org/3.11/library/asyncio-eventloop.html#error-handling-api + + def exceptionHandler(loop, context): + error = context["exception"] + try: + globalInitModule.uncaughtExceptionHandler(error) + except SystemExit: # the "exception" raised by `sys.exit()` call + pass + finally: + pm.stop() # unblock `await pm.wait()` to gracefully exit the program + nonlocal hasUncaughtException + hasUncaughtException = True + loop.set_exception_handler(exceptionHandler) + + def cleanupExit(code=0): + pm.stop() + realExit(code) + realExit = globalThis.python.exit + globalThis.python.exit = cleanupExit + + try: + globalInitModule.patchGlobalRequire() + pm.runProgramModule(args[0], args, requirePath) + await pm.wait() # blocks until all asynchronous calls finish + if hasUncaughtException: + sys.exit(1) + except Exception as error: + print(error, file=sys.stderr) + sys.exit(1) try: asyncio.run(runJS()) except KeyboardInterrupt: From 065fbf8939dcc16d53a518305e22c93ead2eb123 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 8 May 2024 21:45:36 +0000 Subject: [PATCH 032/428] style: comment for function --- python/pythonmonkey/cli/pmjs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/pythonmonkey/cli/pmjs.py b/python/pythonmonkey/cli/pmjs.py index 27f06d98..1e48f83e 100755 --- a/python/pythonmonkey/cli/pmjs.py +++ b/python/pythonmonkey/cli/pmjs.py @@ -380,9 +380,9 @@ async def runEvalPrint(): async def runJS(): hasUncaughtException = False loop = asyncio.get_running_loop() - # See https://docs.python.org/3.11/library/asyncio-eventloop.html#error-handling-api def exceptionHandler(loop, context): + "See https://docs.python.org/3.11/library/asyncio-eventloop.html#error-handling-api" error = context["exception"] try: globalInitModule.uncaughtExceptionHandler(error) From b14aac4b8ed4d6608aba1133b51f058c43e8b00e Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 14 May 2024 21:17:20 +0000 Subject: [PATCH 033/428] feat(XHR): report HTTP errors to the `onerror` event handler --- python/pythonmonkey/builtin_modules/XMLHttpRequest.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/python/pythonmonkey/builtin_modules/XMLHttpRequest.js b/python/pythonmonkey/builtin_modules/XMLHttpRequest.js index 82dc4a99..6db9bc04 100644 --- a/python/pythonmonkey/builtin_modules/XMLHttpRequest.js +++ b/python/pythonmonkey/builtin_modules/XMLHttpRequest.js @@ -49,7 +49,7 @@ class ProgressEvent extends Event { /** * @param {string} type - * @param {{ lengthComputable?: boolean; loaded?: number; total?: number; }} eventInitDict + * @param {{ lengthComputable?: boolean; loaded?: number; total?: number; error?: Error; }} eventInitDict */ constructor (type, eventInitDict = {}) { @@ -57,6 +57,7 @@ class ProgressEvent extends Event this.lengthComputable = eventInitDict.lengthComputable ?? false; this.loaded = eventInitDict.loaded ?? 0; this.total = eventInitDict.total ?? 0; + this.error = eventInitDict.error ?? null; this.debugTag = 'xhr:'; } } @@ -446,12 +447,12 @@ class XMLHttpRequest extends XMLHttpRequestEventTarget this.#uploadCompleteFlag = true; if (this.#uploadListenerFlag) { - this.#uploadObject.dispatchEvent(new ProgressEvent(event, { loaded:0, total:0 })); + this.#uploadObject.dispatchEvent(new ProgressEvent(event, { loaded:0, total:0, error: exception })); this.#uploadObject.dispatchEvent(new ProgressEvent('loadend', { loaded:0, total:0 })); } } - this.dispatchEvent(new ProgressEvent(event, { loaded:0, total:0 })); // step 7 + this.dispatchEvent(new ProgressEvent(event, { loaded:0, total:0, error: exception })); // step 7 this.dispatchEvent(new ProgressEvent('loadend', { loaded:0, total:0 })); // step 8 } From ebdef836c0e880585f63f9d564af79791d9e5452 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 14 May 2024 21:37:49 +0000 Subject: [PATCH 034/428] test(XHR): fix error throwing Passing an object to `new Error` will result in `Error: [object Object]`. --- tests/js/xhr.simple | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/tests/js/xhr.simple b/tests/js/xhr.simple index 2afddb55..8c61e6dc 100644 --- a/tests/js/xhr.simple +++ b/tests/js/xhr.simple @@ -69,19 +69,16 @@ new Promise(function (resolve, reject) } else { - reject(new Error({ + reject(new Error(JSON.stringify({ status: this.status, - statusText: this.statusText - })); + statusText: this.statusText + }))); } }; - xhr.onerror = function () + xhr.onerror = function (ev) { - reject(new Error({ - status: this.status, - statusText: this.statusText - })); + reject(ev.error); }; xhr.send(); @@ -112,19 +109,16 @@ new Promise(function (resolve, reject) } else { - reject(new Error({ + reject(new Error(JSON.stringify({ status: this.status, - statusText: this.statusText - })); + statusText: this.statusText + }))); } }; - xhr.onerror = function () + xhr.onerror = function (ev) { - reject(new Error({ - status: this.status, - statusText: this.statusText - })); + reject(ev.error); }; xhr.send(); From a1ae6488c2b4539d230560bca683a9f3dfaac3ad Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 14 May 2024 22:33:53 +0000 Subject: [PATCH 035/428] fix(console): fix Error object printing when there's no error stack --- python/pythonmonkey/builtin_modules/util.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/python/pythonmonkey/builtin_modules/util.js b/python/pythonmonkey/builtin_modules/util.js index 91aba2f5..ad7090c5 100644 --- a/python/pythonmonkey/builtin_modules/util.js +++ b/python/pythonmonkey/builtin_modules/util.js @@ -773,10 +773,12 @@ function formatError(ctx, error) .split('\n') .filter(a => a.length > 0) .map(a => ` ${a}`); - const retstr - = `${error.name}: ${error.message}\n` - + stackEls[0] + '\n' - + style(stackEls.slice(1).join('\n')); + let retstr = `${error.name}: ${error.message}\n`; + if (stackEls.length) + { + retstr += stackEls[0] + '\n'; + if (stackEls.length > 1) retstr += style(stackEls.slice(1).join('\n')); + } return retstr; } From 1bcb1f85f1c4ad3a2264e37732733f043d85fb6b Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 14 May 2024 22:39:05 +0000 Subject: [PATCH 036/428] fix(console): extra `name` property is printed after changing the Error name See also commit 0a71c83020a75fd39097b7f3e211f419f1763a86 --- python/pythonmonkey/builtin_modules/util.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/pythonmonkey/builtin_modules/util.js b/python/pythonmonkey/builtin_modules/util.js index ad7090c5..358bfcf6 100644 --- a/python/pythonmonkey/builtin_modules/util.js +++ b/python/pythonmonkey/builtin_modules/util.js @@ -629,9 +629,9 @@ function formatValue(ctx, value, recurseTimes, ln) else if (isError(value)) { // Make error with message first say the error - if (keyLength === 0 || keys.every(k => k === 'stack')) // There's only a 'stack' property + if (keyLength === 0 || keys.every(k => k === 'stack' || k === 'name')) // There's only a 'stack' or 'name' property return formatError(ctx, value); - keys = keys.filter(k => k !== 'stack'); // When changing the 'stack' property in SpiderMonkey, it becomes enumerable. + keys = keys.filter(k => k !== 'stack' && k !== 'name'); // When changing the 'stack' or the 'name' property in SpiderMonkey, it becomes enumerable. base = ` ${formatError(ctx, value)}\n`; braces.length=0; } From c3b615fe15f0d505d55b6e62fbda8e2ffb9543ba Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 14 May 2024 23:36:23 +0000 Subject: [PATCH 037/428] feat(exception-propagation): preserve the original JS Error object as the Python Exception's `__cause__` attribute for lossless two-way conversion --- src/ExceptionType.cc | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/ExceptionType.cc b/src/ExceptionType.cc index 6c2d8ee7..cf58f1d4 100644 --- a/src/ExceptionType.cc +++ b/src/ExceptionType.cc @@ -13,6 +13,8 @@ #include "include/ExceptionType.hh" #include "include/StrType.hh" +#include "include/DictType.hh" +#include "include/JSObjectProxy.hh" #include #include @@ -20,8 +22,6 @@ #include -// TODO (Tom Tang): preserve the original Python exception object somewhere in the JS obj for lossless two-way conversion - PyObject *ExceptionType::getPyObject(JSContext *cx, JS::HandleObject error) { // Convert the JS Error object to a Python string JS::RootedValue errValue(cx, JS::ObjectValue(*error)); // err @@ -36,6 +36,10 @@ PyObject *ExceptionType::getPyObject(JSContext *cx, JS::HandleObject error) { #endif Py_XDECREF(errStr); + // Preserve the original JS Error object as the Python Exception's `__cause__` attribute for lossless two-way conversion + PyObject *originalJsErrWrapper = DictType::getPyObject(cx, errValue); + PyException_SetCause(pyObject, originalJsErrWrapper); // https://docs.python.org/3/c-api/exceptions.html#c.PyException_SetCause + return pyObject; } @@ -79,6 +83,11 @@ tb_print_line_repeated(_PyUnicodeWriter *writer, long cnt) JSObject *ExceptionType::toJsError(JSContext *cx, PyObject *exceptionValue, PyObject *traceBack) { assert(exceptionValue != NULL); + PyObject *originalJsErrWrapper = PyException_GetCause(exceptionValue); + if (originalJsErrWrapper && PyObject_TypeCheck(originalJsErrWrapper, &JSObjectProxyType)) { + return *((JSObjectProxy *)originalJsErrWrapper)->jsObject; + } + // Gather JS context #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wformat-zero-length" From 4b6712b676e2563bdc564391c7aca1fc1989fc18 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 14 May 2024 23:54:38 +0000 Subject: [PATCH 038/428] fix(exception-propagation): the `__cause__` attribute of a Python Exception must strictly be another Exception object. So we use `jsError` attribute instead. --- src/ExceptionType.cc | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/ExceptionType.cc b/src/ExceptionType.cc index cf58f1d4..fc9b44b6 100644 --- a/src/ExceptionType.cc +++ b/src/ExceptionType.cc @@ -36,9 +36,9 @@ PyObject *ExceptionType::getPyObject(JSContext *cx, JS::HandleObject error) { #endif Py_XDECREF(errStr); - // Preserve the original JS Error object as the Python Exception's `__cause__` attribute for lossless two-way conversion + // Preserve the original JS Error object as the Python Exception's `jsError` attribute for lossless two-way conversion PyObject *originalJsErrWrapper = DictType::getPyObject(cx, errValue); - PyException_SetCause(pyObject, originalJsErrWrapper); // https://docs.python.org/3/c-api/exceptions.html#c.PyException_SetCause + PyObject_SetAttrString(pyObject, "jsError", originalJsErrWrapper); return pyObject; } @@ -83,9 +83,11 @@ tb_print_line_repeated(_PyUnicodeWriter *writer, long cnt) JSObject *ExceptionType::toJsError(JSContext *cx, PyObject *exceptionValue, PyObject *traceBack) { assert(exceptionValue != NULL); - PyObject *originalJsErrWrapper = PyException_GetCause(exceptionValue); - if (originalJsErrWrapper && PyObject_TypeCheck(originalJsErrWrapper, &JSObjectProxyType)) { - return *((JSObjectProxy *)originalJsErrWrapper)->jsObject; + if (PyObject_HasAttrString(exceptionValue, "jsError")) { + PyObject *originalJsErrWrapper = PyObject_GetAttrString(exceptionValue, "jsError"); + if (originalJsErrWrapper && PyObject_TypeCheck(originalJsErrWrapper, &JSObjectProxyType)) { + return *((JSObjectProxy *)originalJsErrWrapper)->jsObject; + } } // Gather JS context From 28dcb36595f7e3c7e6eec8887395d556b0d50e7e Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 15 May 2024 07:31:25 +0000 Subject: [PATCH 039/428] fix(exception-propagation): preserve the original JS value as well for non-Error-object thrown --- src/ExceptionType.cc | 10 +++++----- src/PromiseType.cc | 4 ++++ 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/ExceptionType.cc b/src/ExceptionType.cc index fc9b44b6..5e797e1f 100644 --- a/src/ExceptionType.cc +++ b/src/ExceptionType.cc @@ -37,8 +37,8 @@ PyObject *ExceptionType::getPyObject(JSContext *cx, JS::HandleObject error) { Py_XDECREF(errStr); // Preserve the original JS Error object as the Python Exception's `jsError` attribute for lossless two-way conversion - PyObject *originalJsErrWrapper = DictType::getPyObject(cx, errValue); - PyObject_SetAttrString(pyObject, "jsError", originalJsErrWrapper); + PyObject *originalJsErrCapsule = DictType::getPyObject(cx, errValue); + PyObject_SetAttrString(pyObject, "jsError", originalJsErrCapsule); return pyObject; } @@ -84,9 +84,9 @@ JSObject *ExceptionType::toJsError(JSContext *cx, PyObject *exceptionValue, PyOb assert(exceptionValue != NULL); if (PyObject_HasAttrString(exceptionValue, "jsError")) { - PyObject *originalJsErrWrapper = PyObject_GetAttrString(exceptionValue, "jsError"); - if (originalJsErrWrapper && PyObject_TypeCheck(originalJsErrWrapper, &JSObjectProxyType)) { - return *((JSObjectProxy *)originalJsErrWrapper)->jsObject; + PyObject *originalJsErrCapsule = PyObject_GetAttrString(exceptionValue, "jsError"); + if (originalJsErrCapsule && PyObject_TypeCheck(originalJsErrCapsule, &JSObjectProxyType)) { + return *((JSObjectProxy *)originalJsErrCapsule)->jsObject; } } diff --git a/src/PromiseType.cc b/src/PromiseType.cc index 18cd872b..104b8444 100644 --- a/src/PromiseType.cc +++ b/src/PromiseType.cc @@ -10,6 +10,7 @@ #include "include/modules/pythonmonkey/pythonmonkey.hh" #include "include/PromiseType.hh" +#include "include/DictType.hh" #include "include/PyEventLoop.hh" #include "include/pyTypeFactory.hh" #include "include/jsTypeFactory.hh" @@ -42,6 +43,9 @@ static bool onResolvedCb(JSContext *cx, unsigned argc, JS::Value *vp) { #else PyObject *wrapped = PyObject_CallFunction(SpiderMonkeyError, "O", result); // PyObject_CallOneArg is not available in Python < 3.9 #endif + // Preserve the original JS value as the `jsError` attribute for lossless conversion back + PyObject *originalJsErrCapsule = DictType::getPyObject(cx, resultArg); + PyObject_SetAttrString(wrapped, "jsError", originalJsErrCapsule); Py_DECREF(result); result = wrapped; } From e953f0b8386d2c1d77fc0d194b58ff22b1526bd8 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 15 May 2024 07:35:53 +0000 Subject: [PATCH 040/428] fix: change how an uncaught exception is printed out If the uncaught exception is not an Error object, setting `error.name` would get unexpected results. E.g. `throw 1123` would give out a very strange `{ [Number: 1123] name: 'Uncaught undefined' }` --- python/pythonmonkey/lib/pmjs/global-init.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/python/pythonmonkey/lib/pmjs/global-init.js b/python/pythonmonkey/lib/pmjs/global-init.js index a04d0ad9..e5518172 100644 --- a/python/pythonmonkey/lib/pmjs/global-init.js +++ b/python/pythonmonkey/lib/pmjs/global-init.js @@ -73,12 +73,11 @@ exports.initReplLibs = function pmjs$$initReplLibs() */ exports.uncaughtExceptionHandler = function globalInit$$uncaughtExceptionHandler(error) { - error.name = 'Uncaught ' + error.name; if (python._events && python._events['uncaughtException']) python.emit('uncaughtException', error); else { - console.error(error); + console.error('Uncaught', error); python.exit(1); } }; From 1021e7df4ff30fa2c9b12a3cf38c87b536d08c15 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 15 May 2024 21:50:48 +0000 Subject: [PATCH 041/428] test(timers): `timers-segfault.simple` is no longer failing --- tests/js/timers-segfault.simple | 13 +++++++++++++ tests/js/timers-segfault.simple.failing | 12 ------------ 2 files changed, 13 insertions(+), 12 deletions(-) create mode 100644 tests/js/timers-segfault.simple delete mode 100644 tests/js/timers-segfault.simple.failing diff --git a/tests/js/timers-segfault.simple b/tests/js/timers-segfault.simple new file mode 100644 index 00000000..afe42df3 --- /dev/null +++ b/tests/js/timers-segfault.simple @@ -0,0 +1,13 @@ +/** + * @file timers-segfault.simple + * Test using the builtin_modules/timers.js module. + * @author Wes Garland, wes@distributive.network + * @date July 2023 + * + * timeout: 10 + */ +/* eslint-disable brace-style */ + +setTimeout(() => { console.log(0); }); +const interval = setInterval(() => { console.log(1); }, 500); +setTimeout(() => { clearInterval(interval); console.log(2); }, 1000); diff --git a/tests/js/timers-segfault.simple.failing b/tests/js/timers-segfault.simple.failing deleted file mode 100644 index a902ecf2..00000000 --- a/tests/js/timers-segfault.simple.failing +++ /dev/null @@ -1,12 +0,0 @@ -/** - * @file timers-segfault.simlpe - * MRTC for a segfault when using the pmjs-lib/event-timers.js module. - * @author Wes Garland, wes@distributive.network - * @date July 2023 - * - * timeout: 10 - */ - -setTimeout(() => { /* a.push(1) */ 1 }); -const interval = setInterval(() => { 1 }, 500); -setTimeout(() => { 2 }, 1000); From 5d54009b6908f18a98154e79926d9cb33c8c5c4c Mon Sep 17 00:00:00 2001 From: philippedistributive <151072087+philippedistributive@users.noreply.github.com> Date: Wed, 15 May 2024 18:56:39 -0400 Subject: [PATCH 042/428] Update python/pythonmonkey/lib/pmjs/global-init.js --- python/pythonmonkey/lib/pmjs/global-init.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/pythonmonkey/lib/pmjs/global-init.js b/python/pythonmonkey/lib/pmjs/global-init.js index e5518172..0004973c 100644 --- a/python/pythonmonkey/lib/pmjs/global-init.js +++ b/python/pythonmonkey/lib/pmjs/global-init.js @@ -69,7 +69,7 @@ exports.initReplLibs = function pmjs$$initReplLibs() }; /** - * Temporary API until we get EventEmitters working. Replace this export for a custom handler. + * Temporary API until we get EventEmitters working. Replace this export with a custom handler. */ exports.uncaughtExceptionHandler = function globalInit$$uncaughtExceptionHandler(error) { From d351c07cbc2128ca47ef1e28e30a47d103639bf6 Mon Sep 17 00:00:00 2001 From: philippedistributive <151072087+philippedistributive@users.noreply.github.com> Date: Wed, 15 May 2024 18:56:59 -0400 Subject: [PATCH 043/428] Update python/pythonmonkey/lib/pmjs/global-init.js --- python/pythonmonkey/lib/pmjs/global-init.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/pythonmonkey/lib/pmjs/global-init.js b/python/pythonmonkey/lib/pmjs/global-init.js index 0004973c..26e2050a 100644 --- a/python/pythonmonkey/lib/pmjs/global-init.js +++ b/python/pythonmonkey/lib/pmjs/global-init.js @@ -83,7 +83,7 @@ exports.uncaughtExceptionHandler = function globalInit$$uncaughtExceptionHandler }; /** - * Temporary API until we get EventEmitters working. Replace this export for a custom handler. + * Temporary API until we get EventEmitters working. Replace this export with a custom handler. */ exports.unhandledRejectionHandler = function globalInit$$unhandledRejectionHandler(error) { From 6e1a80601e847f67f06d896f9c8314c7c983e697 Mon Sep 17 00:00:00 2001 From: philippedistributive <151072087+philippedistributive@users.noreply.github.com> Date: Wed, 15 May 2024 19:12:28 -0400 Subject: [PATCH 044/428] Update python/pythonmonkey/lib/pmjs/global-init.js --- python/pythonmonkey/lib/pmjs/global-init.js | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/python/pythonmonkey/lib/pmjs/global-init.js b/python/pythonmonkey/lib/pmjs/global-init.js index 26e2050a..87f3a5be 100644 --- a/python/pythonmonkey/lib/pmjs/global-init.js +++ b/python/pythonmonkey/lib/pmjs/global-init.js @@ -32,22 +32,6 @@ python.on('error', function unhandledError(error) python.emit('unhandledException', error); }); -/** - * Set the global arguments array, which is just the program's argv. We use an argvBuilder function to - * get around PythonMonkey's missing list->Array coercion. /wg june 2023 - */ -exports.makeArgvBuilder = function globalInit$$makeArgvBuilder() -{ - const argv = []; - globalThis.arguments = argv; - return argvBuilder; - - function argvBuilder(arg) - { - globalThis.arguments.push(arg); - } -}; - /** * runProgramModule wants to include the require.cache from the pre-program loads (e.g. via -r or -e), but * due to current bugs in PythonMonkey, we can't access the cache property of require because it is a JS From f3c6b9955cf67a2a2720e1621e48f0ef7fb0df9c Mon Sep 17 00:00:00 2001 From: Caleb Aikens Date: Thu, 23 May 2024 08:43:17 -0400 Subject: [PATCH 045/428] fix(strings): JSStrings returned by eval are no longer rooted for the lifetime of the program --- include/JSStringProxy.hh | 16 ++++- include/StrType.hh | 4 +- src/ExceptionType.cc | 3 +- src/JSStringProxy.cc | 16 +++++ src/StrType.cc | 87 +++++++++++++----------- src/jsTypeFactory.cc | 2 +- src/modules/pythonmonkey/pythonmonkey.cc | 17 ++--- src/pyTypeFactory.cc | 2 +- src/setSpiderMonkeyException.cc | 3 +- 9 files changed, 90 insertions(+), 60 deletions(-) create mode 100644 src/JSStringProxy.cc diff --git a/include/JSStringProxy.hh b/include/JSStringProxy.hh index 8c82374c..955f2830 100644 --- a/include/JSStringProxy.hh +++ b/include/JSStringProxy.hh @@ -21,9 +21,23 @@ */ typedef struct { PyUnicodeObject str; - JS::PersistentRootedValue jsString; + JS::PersistentRootedValue *jsString; } JSStringProxy; +/** + * @brief This struct is a bundle of methods used by the JSStringProxy type + * + */ +struct JSStringProxyMethodDefinitions { +public: + /** + * @brief Deallocation method (.tp_dealloc), removes the reference to the underlying JSString before freeing the JSStringProxy + * + * @param self - The JSStringProxy to be free'd + */ + static void JSStringProxy_dealloc(JSStringProxy *self); +}; + /** * @brief Struct for the JSStringProxyType, used by all JSStringProxy objects */ diff --git a/include/StrType.hh b/include/StrType.hh index 7d516485..927d0195 100644 --- a/include/StrType.hh +++ b/include/StrType.hh @@ -34,9 +34,9 @@ public: * * @returns PyObject* pointer to the resulting PyObject */ - static PyObject *getPyObject(JSContext *cx, JSString *str); + static PyObject *getPyObject(JSContext *cx, JS::HandleValue str); - static const char *getValue(JSContext *cx, JSString *str); + static const char *getValue(JSContext *cx, JS::HandleValue str); }; #endif \ No newline at end of file diff --git a/src/ExceptionType.cc b/src/ExceptionType.cc index 6c2d8ee7..bf914db3 100644 --- a/src/ExceptionType.cc +++ b/src/ExceptionType.cc @@ -96,7 +96,8 @@ JSObject *ExceptionType::toJsError(JSContext *cx, PyObject *exceptionValue, PyOb if (stackObj.get()) { JS::RootedString stackStr(cx); JS::BuildStackString(cx, nullptr, stackObj, &stackStr, 2, js::StackFormat::SpiderMonkey); - stackStream << "\nJS Stack Trace:\n" << StrType::getValue(cx, stackStr); + JS::RootedValue stackStrVal(cx, JS::StringValue(stackStr)); + stackStream << "\nJS Stack Trace:\n" << StrType::getValue(cx, stackStrVal); } diff --git a/src/JSStringProxy.cc b/src/JSStringProxy.cc new file mode 100644 index 00000000..01c1ad7d --- /dev/null +++ b/src/JSStringProxy.cc @@ -0,0 +1,16 @@ +/** + * @file JSStringProxy.cc + * @author Caleb Aikens (caleb@distributive.network) + * @brief JSStringProxy is a custom C-implemented python type that derives from str. It acts as a proxy for JSStrings from Spidermonkey, and behaves like a str would. + * @date 2024-05-15 + * + * @copyright Copyright (c) 2024 Distributive Corp. + * + */ + +#include "include/JSStringProxy.hh" + +void JSStringProxyMethodDefinitions::JSStringProxy_dealloc(JSStringProxy *self) +{ + delete self->jsString; +} \ No newline at end of file diff --git a/src/StrType.cc b/src/StrType.cc index 546e6979..53a92f0d 100644 --- a/src/StrType.cc +++ b/src/StrType.cc @@ -58,15 +58,15 @@ static bool containsSurrogatePair(const char16_t *chars, size_t length) { * @return PyObject* - the UCS4-encoding of the pyObject string * */ -static PyObject *asUCS4(PyObject *pyObject) { - if (PyUnicode_KIND(pyObject) != PyUnicode_2BYTE_KIND) { +static PyObject *asUCS4(PyObject *pyString) { + if (PyUnicode_KIND(pyString) != PyUnicode_2BYTE_KIND) { // return a new reference to match the behaviour of `PyUnicode_FromKindAndData` - Py_INCREF(pyObject); - return pyObject; + Py_INCREF(pyString); + return pyString; } - uint16_t *chars = PY_UNICODE_OBJECT_DATA_UCS2(pyObject); - size_t length = PY_UNICODE_OBJECT_LENGTH(pyObject); + uint16_t *chars = PY_UNICODE_OBJECT_DATA_UCS2(pyString); + size_t length = PY_UNICODE_OBJECT_LENGTH(pyString); uint32_t *ucs4String = new uint32_t[length]; size_t ucs4Length = 0; @@ -94,45 +94,52 @@ static PyObject *asUCS4(PyObject *pyObject) { return ret; } -static PyObject *processString(JSContext *cx, JSString *str) { +static PyObject *processString(JSContext *cx, JS::HandleValue strVal) { + JS::RootedString str(cx, strVal.toString()); JSLinearString *lstr = JS_EnsureLinearString(cx, str); JS::AutoCheckCannotGC nogc; PyObject *p; size_t length = JS::GetLinearStringLength(lstr); - PyObject *pyObject = (PyObject *)PyObject_New(JSStringProxy, &JSStringProxyType); // new reference - Py_INCREF(pyObject); + JSStringProxy *pyString = PyObject_New(JSStringProxy, &JSStringProxyType); // new reference + Py_INCREF(pyString); - ((JSStringProxy *)pyObject)->jsString.setString((JSString *)lstr); + if (pyString == NULL) { + return NULL; + } + + JS::RootedObject obj(cx); + pyString->jsString = new JS::PersistentRootedValue(cx); + pyString->jsString->setString((JSString *)lstr); // Initialize as legacy string (https://github.com/python/cpython/blob/v3.12.0b1/Include/cpython/unicodeobject.h#L78-L93) // see https://github.com/python/cpython/blob/v3.11.3/Objects/unicodeobject.c#L1230-L1245 - PY_UNICODE_OBJECT_HASH(pyObject) = -1; - PY_UNICODE_OBJECT_STATE(pyObject).interned = 0; - PY_UNICODE_OBJECT_STATE(pyObject).compact = 0; - PY_UNICODE_OBJECT_STATE(pyObject).ascii = 0; - PY_UNICODE_OBJECT_UTF8(pyObject) = NULL; - PY_UNICODE_OBJECT_UTF8_LENGTH(pyObject) = 0; + PY_UNICODE_OBJECT_HASH(pyString) = -1; + PY_UNICODE_OBJECT_STATE(pyString).interned = 0; + PY_UNICODE_OBJECT_STATE(pyString).compact = 0; + PY_UNICODE_OBJECT_STATE(pyString).ascii = 0; + PY_UNICODE_OBJECT_UTF8(pyString) = NULL; + PY_UNICODE_OBJECT_UTF8_LENGTH(pyString) = 0; if (JS::LinearStringHasLatin1Chars(lstr)) { // latin1 spidermonkey, latin1 python const JS::Latin1Char *chars = JS::GetLatin1LinearStringChars(nogc, lstr); - PY_UNICODE_OBJECT_DATA_ANY(pyObject) = (void *)chars; - PY_UNICODE_OBJECT_KIND(pyObject) = PyUnicode_1BYTE_KIND; - PY_UNICODE_OBJECT_LENGTH(pyObject) = length; + PY_UNICODE_OBJECT_DATA_ANY(pyString) = (void *)chars; + PY_UNICODE_OBJECT_KIND(pyString) = PyUnicode_1BYTE_KIND; + PY_UNICODE_OBJECT_LENGTH(pyString) = length; #if PY_UNICODE_HAS_WSTR - PY_UNICODE_OBJECT_WSTR(pyObject) = NULL; - PY_UNICODE_OBJECT_WSTR_LENGTH(pyObject) = 0; - PY_UNICODE_OBJECT_READY(pyObject) = 1; + PY_UNICODE_OBJECT_WSTR(pyString) = NULL; + PY_UNICODE_OBJECT_WSTR_LENGTH(pyString) = 0; + PY_UNICODE_OBJECT_READY(pyString) = 1; #endif } else { // utf16 spidermonkey, ucs2 python const char16_t *chars = JS::GetTwoByteLinearStringChars(nogc, lstr); - PY_UNICODE_OBJECT_DATA_ANY(pyObject) = (void *)chars; - PY_UNICODE_OBJECT_KIND(pyObject) = PyUnicode_2BYTE_KIND; - PY_UNICODE_OBJECT_LENGTH(pyObject) = length; + PY_UNICODE_OBJECT_DATA_ANY(pyString) = (void *)chars; + PY_UNICODE_OBJECT_KIND(pyString) = PyUnicode_2BYTE_KIND; + PY_UNICODE_OBJECT_LENGTH(pyString) = length; #if PY_UNICODE_HAS_WSTR // python unicode objects take advantage of a possible performance gain on systems where @@ -141,38 +148,38 @@ static PyObject *processString(JSContext *cx, JSString *str) { // On systems where sizeof(wchar_t) == 4, i.e. Unixy systems, a similar performance gain happens if the // string is using UCS4 encoding [this is automatically handled by asUCS4()] if (sizeof(wchar_t) == 2) { - PY_UNICODE_OBJECT_WSTR(pyObject) = (wchar_t *)chars; - PY_UNICODE_OBJECT_WSTR_LENGTH(pyObject) = length; + PY_UNICODE_OBJECT_WSTR(pyString) = (wchar_t *)chars; + PY_UNICODE_OBJECT_WSTR_LENGTH(pyString) = length; } else { - PY_UNICODE_OBJECT_WSTR(pyObject) = NULL; - PY_UNICODE_OBJECT_WSTR_LENGTH(pyObject) = 0; + PY_UNICODE_OBJECT_WSTR(pyString) = NULL; + PY_UNICODE_OBJECT_WSTR_LENGTH(pyString) = 0; } - PY_UNICODE_OBJECT_READY(pyObject) = 1; + PY_UNICODE_OBJECT_READY(pyString) = 1; #endif if (containsSurrogatePair(chars, length)) { // We must convert to UCS4 here because Python does not support decoding string containing surrogate pairs to bytes - PyObject *ucs4Obj = asUCS4(pyObject); // convert to a new PyUnicodeObject with UCS4 data + PyObject *ucs4Obj = asUCS4((PyObject *)pyString); // convert to a new PyUnicodeObject with UCS4 data if (!ucs4Obj) { - // conversion fails, keep the original `pyObject` - return pyObject; + // conversion fails, keep the original `pyString` + return (PyObject *)pyString; } - Py_DECREF(pyObject); + Py_DECREF(pyString); return ucs4Obj; } } - return pyObject; + return (PyObject *)pyString; } -PyObject *StrType::getPyObject(JSContext *cx, JSString *str) { +PyObject *StrType::getPyObject(JSContext *cx, JS::HandleValue str) { return processString(cx, str); } -const char *StrType::getValue(JSContext *cx, JSString *str) { - PyObject *pyObject = processString(cx, str); - const char *value = PyUnicode_AsUTF8(pyObject); - Py_DECREF(pyObject); +const char *StrType::getValue(JSContext *cx, JS::HandleValue str) { + PyObject *pyString = processString(cx, str); + const char *value = PyUnicode_AsUTF8(pyString); + Py_DECREF(pyString); return value; } \ No newline at end of file diff --git a/src/jsTypeFactory.cc b/src/jsTypeFactory.cc index d00860d0..eb211466 100644 --- a/src/jsTypeFactory.cc +++ b/src/jsTypeFactory.cc @@ -112,7 +112,7 @@ JS::Value jsTypeFactory(JSContext *cx, PyObject *object) { returnType.setNumber(PyFloat_AsDouble(object)); } else if (PyObject_TypeCheck(object, &JSStringProxyType)) { - returnType.setString(((JSStringProxy *)object)->jsString.toString()); + returnType.setString(((JSStringProxy *)object)->jsString->toString()); } else if (PyUnicode_Check(object)) { switch (PyUnicode_KIND(object)) { diff --git a/src/modules/pythonmonkey/pythonmonkey.cc b/src/modules/pythonmonkey/pythonmonkey.cc index 600a986d..4b1a06b2 100644 --- a/src/modules/pythonmonkey/pythonmonkey.cc +++ b/src/modules/pythonmonkey/pythonmonkey.cc @@ -128,6 +128,7 @@ PyTypeObject JSObjectProxyType = { PyTypeObject JSStringProxyType = { .tp_name = PyUnicode_Type.tp_name, .tp_basicsize = sizeof(JSStringProxy), + .tp_dealloc = (destructor)JSStringProxyMethodDefinitions::JSStringProxy_dealloc, .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_UNICODE_SUBCLASS, .tp_doc = PyDoc_STR("Javascript String value"), .tp_base = &PyUnicode_Type @@ -419,7 +420,7 @@ static PyObject *eval(PyObject *self, PyObject *args) { // compile the code to execute JS::RootedScript script(GLOBAL_CX); - JS::Rooted *rval = new JS::Rooted(GLOBAL_CX); + JS::Rooted rval(GLOBAL_CX); if (code) { JS::SourceText source; const char *codeChars = PyUnicode_AsUTF8(code); @@ -440,27 +441,17 @@ static PyObject *eval(PyObject *self, PyObject *args) { } // execute the compiled code; last expr goes to rval - if (!JS_ExecuteScript(GLOBAL_CX, script, rval)) { + if (!JS_ExecuteScript(GLOBAL_CX, script, &rval)) { setSpiderMonkeyException(GLOBAL_CX); return NULL; } // translate to the proper python type - PyObject *returnValue = pyTypeFactory(GLOBAL_CX, *rval); + PyObject *returnValue = pyTypeFactory(GLOBAL_CX, rval); if (PyErr_Occurred()) { return NULL; } - // TODO: Find a way to root strings for the lifetime of a proxying python string - js::ESClass cls = js::ESClass::Other; // placeholder if `rval` is not a JSObject - if (rval->isObject()) { - JS::GetBuiltinClass(GLOBAL_CX, JS::RootedObject(GLOBAL_CX, &rval->toObject()), &cls); - } - - if (!(rval->isString() || cls == js::ESClass::String)) { // rval may be a string which must be kept alive. - delete rval; - } - if (returnValue) { return returnValue; } diff --git a/src/pyTypeFactory.cc b/src/pyTypeFactory.cc index fbe42b11..63a0a34f 100644 --- a/src/pyTypeFactory.cc +++ b/src/pyTypeFactory.cc @@ -50,7 +50,7 @@ PyObject *pyTypeFactory(JSContext *cx, JS::HandleValue rval) { return FloatType::getPyObject(rval.toNumber()); } else if (rval.isString()) { - return StrType::getPyObject(cx, rval.toString()); + return StrType::getPyObject(cx, rval); } else if (rval.isSymbol()) { printf("symbol type is not handled by PythonMonkey yet"); diff --git a/src/setSpiderMonkeyException.cc b/src/setSpiderMonkeyException.cc index 96d4c830..8fcefe41 100644 --- a/src/setSpiderMonkeyException.cc +++ b/src/setSpiderMonkeyException.cc @@ -61,7 +61,8 @@ PyObject *getExceptionString(JSContext *cx, const JS::ExceptionStack &exceptionS if (stackObj.get()) { JS::RootedString stackStr(cx); BuildStackString(cx, nullptr, stackObj, &stackStr, 2, js::StackFormat::SpiderMonkey); - outStrStream << "Stack Trace:\n" << StrType::getValue(cx, stackStr); + JS::RootedValue stackStrVal(cx, JS::StringValue(stackStr)); + outStrStream << "Stack Trace:\n" << StrType::getValue(cx, stackStrVal); } } From b429913d45c843d051ee2db766b2ff9b1e5be309 Mon Sep 17 00:00:00 2001 From: Caleb Aikens Date: Thu, 23 May 2024 10:21:08 -0400 Subject: [PATCH 046/428] fix(strings): JSExternalStrings passed to python now pass the exact same underlying PyUnicodeObject --- include/jsTypeFactory.hh | 21 ++++++++++++++++++++- src/StrType.cc | 14 ++++++++++++++ src/jsTypeFactory.cc | 38 ++++++++++++++++++++++---------------- 3 files changed, 56 insertions(+), 17 deletions(-) diff --git a/include/jsTypeFactory.hh b/include/jsTypeFactory.hh index f791a257..e500908e 100644 --- a/include/jsTypeFactory.hh +++ b/include/jsTypeFactory.hh @@ -16,7 +16,26 @@ #include -struct PythonExternalString; +struct PythonExternalString : public JSExternalStringCallbacks { +public: + /** + * @brief Get the PyObject using the given char buffer + * + * @param chars - the char buffer of the PyObject + * @return PyObject* - the PyObject string + */ + static PyObject *getPyString(const char16_t *chars); + + /** + * @brief decrefs the underlying PyObject string when the JSString is finalized + * + * @param chars - The char buffer of the string + */ + void finalize(char16_t *chars) const override; + + size_t sizeOfBuffer(const char16_t *chars, mozilla::MallocSizeOf mallocSizeOf) const override; +}; +extern PythonExternalString PythonExternalStringCallbacks; /** * @brief Function that makes a UTF16-encoded copy of a UCS4 string diff --git a/src/StrType.cc b/src/StrType.cc index 53a92f0d..eeb95af9 100644 --- a/src/StrType.cc +++ b/src/StrType.cc @@ -10,6 +10,7 @@ #include "include/StrType.hh" #include "include/JSStringProxy.hh" +#include "include/jsTypeFactory.hh" #include #include @@ -174,6 +175,19 @@ static PyObject *processString(JSContext *cx, JS::HandleValue strVal) { } PyObject *StrType::getPyObject(JSContext *cx, JS::HandleValue str) { + const PythonExternalString *callbacks; + const char16_t *chars; + + if (JS::IsExternalString(str.toString(), (const JSExternalStringCallbacks **)&callbacks, &chars)) { + if (callbacks == &PythonExternalStringCallbacks) { + PyObject *pyString = callbacks->getPyString(chars); + Py_INCREF(pyString); + return pyString; + } + + } + + return processString(cx, str); } diff --git a/src/jsTypeFactory.cc b/src/jsTypeFactory.cc index eb211466..ac8667ac 100644 --- a/src/jsTypeFactory.cc +++ b/src/jsTypeFactory.cc @@ -49,24 +49,30 @@ static PyObjectProxyHandler pyObjectProxyHandler; static PyListProxyHandler pyListProxyHandler; static PyIterableProxyHandler pyIterableProxyHandler; -std::unordered_map charToPyObjectMap; // a map of char16_t buffers to their corresponding PyObjects, used when finalizing JSExternalStrings - -struct PythonExternalString : public JSExternalStringCallbacks { - void finalize(char16_t *chars) const override { - // We cannot call Py_DECREF here when shutting down as the thread state is gone. - // Then, when shutting down, there is only on reference left, and we don't need - // to free the object since the entire process memory is being released. - PyObject *object = charToPyObjectMap[chars]; - if (Py_REFCNT(object) > 1) { - Py_DECREF(object); - } - } - size_t sizeOfBuffer(const char16_t *chars, mozilla::MallocSizeOf mallocSizeOf) const override { - return 0; +std::unordered_map charToPyObjectMap; // a map of char16_t buffers to their corresponding PyObjects, used when finalizing JSExternalStrings + +PyObject *PythonExternalString::getPyString(const char16_t *chars) +{ + return charToPyObjectMap[chars]; +} + +void PythonExternalString::finalize(char16_t *chars) const +{ + // We cannot call Py_DECREF here when shutting down as the thread state is gone. + // Then, when shutting down, there is only on reference left, and we don't need + // to free the object since the entire process memory is being released. + PyObject *object = charToPyObjectMap[chars]; + if (Py_REFCNT(object) > 1) { + Py_DECREF(object); } -}; +} + +size_t PythonExternalString::sizeOfBuffer(const char16_t *chars, mozilla::MallocSizeOf mallocSizeOf) const +{ + return 0; +} -static constexpr PythonExternalString PythonExternalStringCallbacks; +PythonExternalString PythonExternalStringCallbacks = {}; size_t UCS4ToUTF16(const uint32_t *chars, size_t length, uint16_t **outStr) { uint16_t *utf16String = (uint16_t *)malloc(sizeof(uint16_t) * length*2); From 6a73f86464aa23dfbe102373f93e6953fca397c2 Mon Sep 17 00:00:00 2001 From: Caleb Aikens Date: Thu, 23 May 2024 10:24:54 -0400 Subject: [PATCH 047/428] test(JSStringProxy): add test for string identity --- tests/python/test_strings.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/python/test_strings.py b/tests/python/test_strings.py index 694de79f..cb3d37ae 100644 --- a/tests/python/test_strings.py +++ b/tests/python/test_strings.py @@ -3,6 +3,12 @@ import random +def test_identity(): + py_string = "abc" + js_string = pm.eval("(str) => str")(py_string) + assert py_string is js_string + + def test_eval_ascii_string_matches_evaluated_string(): py_ascii_string = "abc" js_ascii_string = pm.eval(repr(py_ascii_string)) From 22a160580c6dfa356d39aa920aae2a79d8f56d21 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Thu, 23 May 2024 17:27:02 +0000 Subject: [PATCH 048/428] feat(XHR): support HTTP-Keep-Alive --- python/pythonmonkey/builtin_modules/XMLHttpRequest-internal.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/python/pythonmonkey/builtin_modules/XMLHttpRequest-internal.py b/python/pythonmonkey/builtin_modules/XMLHttpRequest-internal.py index 19c5a0d6..a7ae2e70 100644 --- a/python/pythonmonkey/builtin_modules/XMLHttpRequest-internal.py +++ b/python/pythonmonkey/builtin_modules/XMLHttpRequest-internal.py @@ -12,6 +12,8 @@ import pythonmonkey as pm from typing import Union, ByteString, Callable, TypedDict +keepAliveConnector = aiohttp.TCPConnector(keepalive_timeout=15) # seconds before closing Keep-Alive connection + class XHRResponse(TypedDict, total=True): """ @@ -80,6 +82,7 @@ async def write(self, writer) -> None: headers=headers, data=BytesPayloadWithProgress(body) if body else None, timeout=timeoutOptions, + connector=keepAliveConnector, ) as res: debug('xhr:aiohttp')('got', res.content_type, 'result') From 77e4143eb4a2aeda3db6ff6566be1fddc36f3c28 Mon Sep 17 00:00:00 2001 From: Ben West <73724178+bwest2397@users.noreply.github.com> Date: Fri, 24 May 2024 14:18:27 -0400 Subject: [PATCH 049/428] When running as root, skip sudo When installing within a Docker container, the user in use may be `root` and `sudo` might not be installed. This patch allows pythonmonkey to be installed in a Docker container without having to install `sudo` first --- setup.sh | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/setup.sh b/setup.sh index e07bd680..683226ff 100755 --- a/setup.sh +++ b/setup.sh @@ -12,14 +12,18 @@ CPUS=$(getconf _NPROCESSORS_ONLN 2>/dev/null || getconf NPROCESSORS_ONLN 2>/dev/ echo "Installing dependencies" if [[ "$OSTYPE" == "linux-gnu"* ]]; then # Linux - sudo apt-get update --yes - sudo apt-get install --yes cmake graphviz llvm clang pkg-config m4 \ + SUDO='' + if [[ $EUID != 0 ]]; then + SUDO='sudo' + fi + $SUDO apt-get update --yes + $SUDO apt-get install --yes cmake graphviz llvm clang pkg-config m4 \ wget curl python3-distutils python3-dev # Install Doxygen # the newest version in Ubuntu 20.04 repository is 1.8.17, but we need Doxygen 1.9 series wget -c -q https://www.doxygen.nl/files/doxygen-1.9.7.linux.bin.tar.gz tar xf doxygen-1.9.7.linux.bin.tar.gz - cd doxygen-1.9.7 && sudo make install && cd - + cd doxygen-1.9.7 && $SUDO make install && cd - rm -rf doxygen-1.9.7 doxygen-1.9.7.linux.bin.tar.gz elif [[ "$OSTYPE" == "darwin"* ]]; then # macOS brew update || true # allow failure From 117a0d67bf6d7f1983fa0887a2aeda0913e2ed77 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 28 May 2024 04:44:53 +0000 Subject: [PATCH 050/428] feat(exception-propagation): Errors thrown in an async function can now be handled on `uncaughtExceptionHandler` --- include/JobQueue.hh | 13 +++++++++++++ src/JobQueue.cc | 19 +++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/include/JobQueue.hh b/include/JobQueue.hh index c8bf1a95..5fae6c1d 100644 --- a/include/JobQueue.hh +++ b/include/JobQueue.hh @@ -120,6 +120,19 @@ js::UniquePtr saveJobQueue(JSContext *) override; */ static bool dispatchToEventLoop(void *closure, JS::Dispatchable *dispatchable); +/** + * @brief The callback that gets invoked whenever a Promise is rejected without a rejection handler (uncaught/unhandled exception) + * see https://hg.mozilla.org/releases/mozilla-esr102/file/tip/js/public/Promise.h#l268 + * https://hg.mozilla.org/releases/mozilla-esr102/file/tip/js/src/vm/Runtime.cpp#l600 + * @param promise - The Promise object + * @param state - Is the Promise unhandled? + * @param mutedErrors - unused + * @param privateData - unused + */ +static void promiseRejectionTracker(JSContext *cx, bool mutedErrors, + JS::HandleObject promise, JS::PromiseRejectionHandlingState state, + void *privateData); + }; // class /** diff --git a/src/JobQueue.cc b/src/JobQueue.cc index 9a79789f..01cf73a6 100644 --- a/src/JobQueue.cc +++ b/src/JobQueue.cc @@ -12,6 +12,7 @@ #include "include/PyEventLoop.hh" #include "include/pyTypeFactory.hh" +#include "include/PromiseType.hh" #include @@ -72,6 +73,7 @@ js::UniquePtr JobQueue::saveJobQueue(JSContext *cx) bool JobQueue::init(JSContext *cx) { JS::SetJobQueue(cx, this); JS::InitDispatchToEventLoop(cx, dispatchToEventLoop, cx); + JS::SetPromiseRejectionTrackerCallback(cx, promiseRejectionTracker); return true; } @@ -117,6 +119,23 @@ bool sendJobToMainLoop(PyObject *pyFunc) { return true; } +void JobQueue::promiseRejectionTracker(JSContext *cx, + [[maybe_unused]] bool mutedErrors, + JS::HandleObject promise, + JS::PromiseRejectionHandlingState state, + [[maybe_unused]] void *privateData) { + + // We only care about unhandled Promises + if (state != JS::PromiseRejectionHandlingState::Unhandled) { + return; + } + + PyObject *pyFuture = PromiseType::getPyObject(cx, promise); + // Unhandled Future object calls the event-loop exception handler in its destructor (the `__del__` magic method) + // See https://github.com/python/cpython/blob/v3.9.16/Lib/asyncio/futures.py#L108 + Py_SET_REFCNT(pyFuture, 0); +} + void JobQueue::queueFinalizationRegistryCallback(JSFunction *callback) { mozilla::Unused << finalizationRegistryCallbacks->append(callback); } From 53ae986be0b8bff036877752491e05b9016be4bc Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 28 May 2024 04:56:43 +0000 Subject: [PATCH 051/428] fix: `Py_SET_REFCNT` macro does not exist in Python 3.8 See https://docs.python.org/3.9/c-api/structures.html#c.Py_SET_REFCNT --- src/JobQueue.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/JobQueue.cc b/src/JobQueue.cc index 01cf73a6..c2bf30e7 100644 --- a/src/JobQueue.cc +++ b/src/JobQueue.cc @@ -133,7 +133,7 @@ void JobQueue::promiseRejectionTracker(JSContext *cx, PyObject *pyFuture = PromiseType::getPyObject(cx, promise); // Unhandled Future object calls the event-loop exception handler in its destructor (the `__del__` magic method) // See https://github.com/python/cpython/blob/v3.9.16/Lib/asyncio/futures.py#L108 - Py_SET_REFCNT(pyFuture, 0); + pyFuture->ob_refcnt = 0; // Py_SET_REFCNT does not exist in Python 3.8 } void JobQueue::queueFinalizationRegistryCallback(JSFunction *callback) { From d9a8ebec19529110de4aaf08ae5a06cf991ff7c3 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 28 May 2024 06:57:21 +0000 Subject: [PATCH 052/428] docs(event-loop): document how the reference count works for `PromiseType::getPyObject` --- src/JobQueue.cc | 5 +++-- src/PromiseType.cc | 11 +++++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/JobQueue.cc b/src/JobQueue.cc index c2bf30e7..1ddcbea8 100644 --- a/src/JobQueue.cc +++ b/src/JobQueue.cc @@ -130,10 +130,11 @@ void JobQueue::promiseRejectionTracker(JSContext *cx, return; } - PyObject *pyFuture = PromiseType::getPyObject(cx, promise); + PyObject *pyFuture = PromiseType::getPyObject(cx, promise); // ref count == 2 // Unhandled Future object calls the event-loop exception handler in its destructor (the `__del__` magic method) // See https://github.com/python/cpython/blob/v3.9.16/Lib/asyncio/futures.py#L108 - pyFuture->ob_refcnt = 0; // Py_SET_REFCNT does not exist in Python 3.8 + // or https://github.com/python/cpython/blob/v3.9.16/Modules/_asynciomodule.c#L1457-L1467 (It will actually use the C module by default, see futures.py#L417-L423) + Py_DECREF(pyFuture); // decreasing the reference count from 2 to 1, leaving one for the `onResolved` callback in `PromiseType::getPyObject`, which will be called very soon and clean up the reference } void JobQueue::queueFinalizationRegistryCallback(JSFunction *callback) { diff --git a/src/PromiseType.cc b/src/PromiseType.cc index 104b8444..9ca94cb0 100644 --- a/src/PromiseType.cc +++ b/src/PromiseType.cc @@ -55,7 +55,7 @@ static bool onResolvedCb(JSContext *cx, unsigned argc, JS::Value *vp) { PyObject *futureObj = (PyObject *)(futureObjVal.toPrivate()); // Settle the Python asyncio.Future by the Promise's result - PyEventLoop::Future future = PyEventLoop::Future(futureObj); + PyEventLoop::Future future = PyEventLoop::Future(futureObj); // will decrease the reference count of `futureObj` in its destructor when the `onResolvedCb` function ends if (state == JS::PromiseState::Fulfilled) { future.setResult(result); } else { // state == JS::PromiseState::Rejected @@ -63,6 +63,7 @@ static bool onResolvedCb(JSContext *cx, unsigned argc, JS::Value *vp) { } Py_DECREF(result); + // Py_DECREF(futureObj) // the destructor for the `PyEventLoop::Future` above already does this return true; } @@ -70,15 +71,17 @@ PyObject *PromiseType::getPyObject(JSContext *cx, JS::HandleObject promise) { // Create a python asyncio.Future on the running python event-loop PyEventLoop loop = PyEventLoop::getRunningLoop(); if (!loop.initialized()) return NULL; - PyEventLoop::Future future = loop.createFuture(); + PyEventLoop::Future future = loop.createFuture(); // ref count == 1 // Callbacks to settle the Python asyncio.Future once the JS Promise is resolved JS::RootedObject onResolved = JS::RootedObject(cx, (JSObject *)js::NewFunctionWithReserved(cx, onResolvedCb, 1, 0, NULL)); - js::SetFunctionNativeReserved(onResolved, PY_FUTURE_OBJ_SLOT, JS::PrivateValue(future.getFutureObject())); + js::SetFunctionNativeReserved(onResolved, PY_FUTURE_OBJ_SLOT, JS::PrivateValue(future.getFutureObject())); // ref count == 2 js::SetFunctionNativeReserved(onResolved, PROMISE_OBJ_SLOT, JS::ObjectValue(*promise)); AddPromiseReactions(cx, promise, onResolved, onResolved); - return future.getFutureObject(); // must be a new reference + return future.getFutureObject(); // must be a new reference, ref count == 3 + // Here the ref count for the `future` object is 3, but will immediately decrease to 2 in `PyEventLoop::Future`'s destructor when the `PromiseType::getPyObject` function ends + // Leaving one reference for the returned Python object, and another one for the `onResolved` callback function } // Callback to resolve or reject the JS Promise when the Future is done From 597ad094b6458630b4dce66eaba1cdadbe9db43f Mon Sep 17 00:00:00 2001 From: Ben West Date: Tue, 28 May 2024 13:59:52 -0400 Subject: [PATCH 053/428] Use sudo in setup.sh if present --- setup.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setup.sh b/setup.sh index 683226ff..fd553fdb 100755 --- a/setup.sh +++ b/setup.sh @@ -13,7 +13,8 @@ CPUS=$(getconf _NPROCESSORS_ONLN 2>/dev/null || getconf NPROCESSORS_ONLN 2>/dev/ echo "Installing dependencies" if [[ "$OSTYPE" == "linux-gnu"* ]]; then # Linux SUDO='' - if [[ $EUID != 0 ]]; then + if command -v sudo >/dev/null; then + # sudo is present on the system, so use it SUDO='sudo' fi $SUDO apt-get update --yes From 553d9287ef25d4a6c903e8458c06dc147846180d Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 28 May 2024 22:53:06 +0000 Subject: [PATCH 054/428] test(exception-propagation): add tests for sending JS errors caught in Python back to the JS land --- tests/python/test_pythonmonkey_eval.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/python/test_pythonmonkey_eval.py b/tests/python/test_pythonmonkey_eval.py index e21cdbe2..94c6d0a3 100644 --- a/tests/python/test_pythonmonkey_eval.py +++ b/tests/python/test_pythonmonkey_eval.py @@ -164,6 +164,17 @@ def b(x): assert ("Caught in Py Error in" in ret) and ("TypeError: this is an exception" in ret) +def test_eval_exceptions_preserve_js_py_js(): + # Tests for https://github.com/Distributive-Network/PythonMonkey/blob/d9a8ebe/src/ExceptionType.cc#L39-L41 + # and https://github.com/Distributive-Network/PythonMonkey/blob/d9a8ebe/src/ExceptionType.cc#L86-L91 + obj = pm.eval("({ err: new TypeError('JS Error') })") + py_err = obj.err + assert type(py_err) is pm.SpiderMonkeyError + assert pm.eval("(e) => e instanceof TypeError")(py_err) + assert pm.eval("(e) => e.message == 'JS Error'")(py_err) + assert pm.eval("(e, obj) => Object.is(e, obj.err)")(py_err, obj) + + def test_eval_undefined(): x = pm.eval("undefined") assert x is None From 4d14c8b035ba52a76567a6972e2e1c7de41aae13 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 28 May 2024 23:03:16 +0000 Subject: [PATCH 055/428] test(exception-propagation): add tests for handling errors thrown in a Promise or an async function --- tests/python/test_event_loop.py | 60 ++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/tests/python/test_event_loop.py b/tests/python/test_event_loop.py index 3f3adf6b..8eecd58c 100644 --- a/tests/python/test_event_loop.py +++ b/tests/python/test_event_loop.py @@ -350,10 +350,68 @@ def py_sleep(seconds): # asyncio.sleep has issues on Python 3.8 match="PythonMonkey cannot find a running Python event-loop to make asynchronous calls."): pm.eval("new Promise(() => { })") -# off-thread promises + +def test_errors_thrown_in_promise(): + async def async_fn(): + loop = asyncio.get_running_loop() + future = loop.create_future() + + def exceptionHandler(loop, context): + future.set_exception(context["exception"]) + loop.set_exception_handler(exceptionHandler) + + pm.eval(""" + new Promise(function (resolve, reject) + { + reject(new Error('in Promise')); + }); + + new Promise(function (resolve, reject) + { + console.log('ok'); + }); + """) + with pytest.raises(pm.SpiderMonkeyError, match="Error: in Promise"): + await asyncio.wait_for(future, timeout=0.1) + + loop.set_exception_handler(None) + return True + assert asyncio.run(async_fn()) + + +def test_errors_thrown_in_async_function(): + async def async_fn(): + loop = asyncio.get_running_loop() + future = loop.create_future() + + def exceptionHandler(loop, context): + future.set_exception(context["exception"]) + loop.set_exception_handler(exceptionHandler) + + pm.eval(""" + async function aba() { + throw new Error('in async function'); + } + + async function abb() { + console.log('ok'); + } + + aba(); + abb(); + """) + with pytest.raises(pm.SpiderMonkeyError, match="Error: in async function"): + await asyncio.wait_for(future, timeout=0.1) + + loop.set_exception_handler(None) + return True + assert asyncio.run(async_fn()) def test_webassembly(): + """ + Tests for off-thread promises + """ async def async_fn(): # off-thread promises can run assert 'instantiated' == await pm.eval(""" From 4f5dc6e1b1da554456c69f465ff5b478288a4564 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 29 May 2024 00:10:58 +0000 Subject: [PATCH 056/428] feat(exception-propagation): honor the `mutedErrors` option for `pm.eval` when unhandled rejections occurred --- include/JobQueue.hh | 3 ++- src/JobQueue.cc | 6 +++++- src/PromiseType.cc | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/include/JobQueue.hh b/include/JobQueue.hh index 5fae6c1d..40bfc73b 100644 --- a/include/JobQueue.hh +++ b/include/JobQueue.hh @@ -126,7 +126,8 @@ static bool dispatchToEventLoop(void *closure, JS::Dispatchable *dispatchable); * https://hg.mozilla.org/releases/mozilla-esr102/file/tip/js/src/vm/Runtime.cpp#l600 * @param promise - The Promise object * @param state - Is the Promise unhandled? - * @param mutedErrors - unused + * @param mutedErrors - When the `mutedErrors` option in `pm.eval` is set to true, unhandled rejections are ignored ("muted"). + * See also https://hg.mozilla.org/releases/mozilla-esr102/file/tip/js/public/CompileOptions.h#l129 * @param privateData - unused */ static void promiseRejectionTracker(JSContext *cx, bool mutedErrors, diff --git a/src/JobQueue.cc b/src/JobQueue.cc index 1ddcbea8..25ae9c16 100644 --- a/src/JobQueue.cc +++ b/src/JobQueue.cc @@ -120,7 +120,7 @@ bool sendJobToMainLoop(PyObject *pyFunc) { } void JobQueue::promiseRejectionTracker(JSContext *cx, - [[maybe_unused]] bool mutedErrors, + bool mutedErrors, JS::HandleObject promise, JS::PromiseRejectionHandlingState state, [[maybe_unused]] void *privateData) { @@ -129,6 +129,10 @@ void JobQueue::promiseRejectionTracker(JSContext *cx, if (state != JS::PromiseRejectionHandlingState::Unhandled) { return; } + // The `mutedErrors` option is set to True in `pm.eval`, eval errors or unhandled rejections should be ignored. + if (mutedErrors) { + return; + } PyObject *pyFuture = PromiseType::getPyObject(cx, promise); // ref count == 2 // Unhandled Future object calls the event-loop exception handler in its destructor (the `__del__` magic method) diff --git a/src/PromiseType.cc b/src/PromiseType.cc index 9ca94cb0..4983e8db 100644 --- a/src/PromiseType.cc +++ b/src/PromiseType.cc @@ -77,7 +77,7 @@ PyObject *PromiseType::getPyObject(JSContext *cx, JS::HandleObject promise) { JS::RootedObject onResolved = JS::RootedObject(cx, (JSObject *)js::NewFunctionWithReserved(cx, onResolvedCb, 1, 0, NULL)); js::SetFunctionNativeReserved(onResolved, PY_FUTURE_OBJ_SLOT, JS::PrivateValue(future.getFutureObject())); // ref count == 2 js::SetFunctionNativeReserved(onResolved, PROMISE_OBJ_SLOT, JS::ObjectValue(*promise)); - AddPromiseReactions(cx, promise, onResolved, onResolved); + JS::AddPromiseReactions(cx, promise, onResolved, onResolved); return future.getFutureObject(); // must be a new reference, ref count == 3 // Here the ref count for the `future` object is 3, but will immediately decrease to 2 in `PyEventLoop::Future`'s destructor when the `PromiseType::getPyObject` function ends From e02cb1f072b5ae045f6592d2162306f76d59372a Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 29 May 2024 00:53:22 +0000 Subject: [PATCH 057/428] test(exception-propagation): add tests for sending Promise rejections caught in Python back to JS --- tests/python/test_pythonmonkey_eval.py | 32 ++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/tests/python/test_pythonmonkey_eval.py b/tests/python/test_pythonmonkey_eval.py index 94c6d0a3..cd7d6719 100644 --- a/tests/python/test_pythonmonkey_eval.py +++ b/tests/python/test_pythonmonkey_eval.py @@ -5,6 +5,7 @@ import math from io import StringIO import sys +import asyncio def test_passes(): @@ -138,6 +139,7 @@ def test_eval_exceptions(): def test_eval_exceptions_nested_py_js_py(): def c(): raise Exception('this is an exception') + err_line_number = sys._getframe().f_lineno - 1 b = pm.eval('''(x) => { try { x() @@ -145,10 +147,11 @@ def c(): return "Caught in JS " + e; } }''') - assert str(b(c)).__contains__("Caught in JS Error: Python Exception: this is an exception") - assert str(b(c)).__contains__("test_pythonmonkey_eval.py") - assert str(b(c)).__contains__("line 140") - assert str(b(c)).__contains__("in c") + err = b(c) + assert "Caught in JS Error: Python Exception: this is an exception" in str(err) + assert "test_pythonmonkey_eval.py" in str(err) + assert "line {}".format(err_line_number) in str(err) + assert "in c" in str(err) def test_eval_exceptions_nested_js_py_js(): @@ -175,6 +178,27 @@ def test_eval_exceptions_preserve_js_py_js(): assert pm.eval("(e, obj) => Object.is(e, obj.err)")(py_err, obj) +def test_eval_exceptions_preserve_promise_rejection(): + # Tests for https://github.com/Distributive-Network/PythonMonkey/blob/d9a8ebe/src/PromiseType.cc#L46-L48 + async def async_fn(): + try: + await pm.eval("Promise.reject(Number(123))", {'mutedErrors': True}) + # The mutedErrors option is required to avoid sending this to uncaughtExceptionHandler prematurely + except Exception as py_err: + assert type(py_err) is pm.SpiderMonkeyError + assert repr(py_err) == "SpiderMonkeyError(123.0)" + assert pm.eval("(e) => e instanceof Number")(py_err) + assert pm.eval("(e) => e == 123")(py_err) + try: + await pm.eval("Promise.reject(new TypeError('Promise rejection'))", {'mutedErrors': True}) + except Exception as py_err: + assert type(py_err) is pm.SpiderMonkeyError + assert pm.eval("(e) => e instanceof TypeError")(py_err) + assert pm.eval("(e) => e.message == 'Promise rejection'")(py_err) + return True + assert asyncio.run(async_fn()) + + def test_eval_undefined(): x = pm.eval("undefined") assert x is None From dc753a065dfae2a1aa2beedde859571565d5d24a Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 29 May 2024 01:27:32 +0000 Subject: [PATCH 058/428] feat(exception-propagation): preserve the original JS Error object as the Python Exception's `jsError` attribute for normal throws (`setSpiderMonkeyException`) as well --- src/setSpiderMonkeyException.cc | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/setSpiderMonkeyException.cc b/src/setSpiderMonkeyException.cc index 96d4c830..ee691d87 100644 --- a/src/setSpiderMonkeyException.cc +++ b/src/setSpiderMonkeyException.cc @@ -11,6 +11,7 @@ #include "include/modules/pythonmonkey/pythonmonkey.hh" #include "include/setSpiderMonkeyException.hh" #include "include/StrType.hh" +#include "include/DictType.hh" #include #include @@ -102,6 +103,14 @@ void setSpiderMonkeyException(JSContext *cx) { // `PyErr_SetString` uses `PyErr_SetObject` with `PyUnicode_FromString` under the hood // see https://github.com/python/cpython/blob/3.9/Python/errors.c#L234-L236 PyObject *errStr = getExceptionString(cx, exceptionStack, printStack); - PyErr_SetObject(SpiderMonkeyError, errStr); + PyObject *errObj = PyObject_CallFunction(SpiderMonkeyError, "O", errStr); // errObj = SpiderMonkeyError(errStr) Py_XDECREF(errStr); + // Preserve the original JS value as the `jsError` attribute for lossless conversion back + PyObject *originalJsErrCapsule = DictType::getPyObject(cx, exn); + PyObject_SetAttrString(errObj, "jsError", originalJsErrCapsule); + Py_XDECREF(originalJsErrCapsule); + // `PyErr_SetObject` can accept either an already created Exception instance or the containing exception value as the second argument + // see https://github.com/python/cpython/blob/v3.9.16/Python/errors.c#L134-L150 + PyErr_SetObject(SpiderMonkeyError, errObj); + Py_XDECREF(errObj); } From e1571ec787819b6a51c384627910eb9e7fa1cea2 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 29 May 2024 01:34:42 +0000 Subject: [PATCH 059/428] test(exception-propagation): add tests for sending JS Errors caught in Python back to JS --- tests/python/test_pythonmonkey_eval.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/python/test_pythonmonkey_eval.py b/tests/python/test_pythonmonkey_eval.py index cd7d6719..f741c3ad 100644 --- a/tests/python/test_pythonmonkey_eval.py +++ b/tests/python/test_pythonmonkey_eval.py @@ -199,6 +199,23 @@ async def async_fn(): assert asyncio.run(async_fn()) +def test_eval_exceptions_preserve_original_js_error_object(): + # Test for https://github.com/Distributive-Network/PythonMonkey/blob/dc753a0/src/setSpiderMonkeyException.cc#L108-L111 + obj = pm.eval("({ err: new TypeError('JS Error') })") + c = pm.eval("(obj) => { throw obj.err; }") + + def b(fn): + try: + fn(obj) + except Exception as e: + return e + + py_err = b(c) + assert pm.eval("(err) => err instanceof TypeError")(py_err) + assert pm.eval("(e) => e.message == 'JS Error'")(py_err) + assert pm.eval("(e, obj) => Object.is(e, obj.err)")(py_err, obj) + + def test_eval_undefined(): x = pm.eval("undefined") assert x is None From dffe510e25b17ce61f9fe72e4ce8df3231a4bde8 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Thu, 30 May 2024 17:31:32 +0000 Subject: [PATCH 060/428] fix(XHR): `keepAliveConnector` attached to a different loop --- .../builtin_modules/XMLHttpRequest-internal.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/python/pythonmonkey/builtin_modules/XMLHttpRequest-internal.py b/python/pythonmonkey/builtin_modules/XMLHttpRequest-internal.py index a7ae2e70..af11208b 100644 --- a/python/pythonmonkey/builtin_modules/XMLHttpRequest-internal.py +++ b/python/pythonmonkey/builtin_modules/XMLHttpRequest-internal.py @@ -12,7 +12,7 @@ import pythonmonkey as pm from typing import Union, ByteString, Callable, TypedDict -keepAliveConnector = aiohttp.TCPConnector(keepalive_timeout=15) # seconds before closing Keep-Alive connection +keepAliveConnector: Union[aiohttp.TCPConnector, None] = None class XHRResponse(TypedDict, total=True): @@ -48,6 +48,11 @@ async def request( ): debug = pm.bootstrap.require("debug") + # to support HTTP-Keep-Alive + global keepAliveConnector + if (not keepAliveConnector): + keepAliveConnector = aiohttp.TCPConnector(keepalive_timeout=15) # seconds before closing Keep-Alive connection + class BytesPayloadWithProgress(aiohttp.BytesPayload): _chunkMaxLength = 2**16 # aiohttp default From f2f0e1e9f10603dc85049f276b81d804bd9c096e Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Thu, 30 May 2024 18:44:43 +0000 Subject: [PATCH 061/428] test(XHR): test HTTP-Keep-Alive automatically in the CI by tracing system calls that open a TCP connection --- tests/js/xhr-http-keep-alive.bash | 72 +++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 tests/js/xhr-http-keep-alive.bash diff --git a/tests/js/xhr-http-keep-alive.bash b/tests/js/xhr-http-keep-alive.bash new file mode 100644 index 00000000..3ac6a421 --- /dev/null +++ b/tests/js/xhr-http-keep-alive.bash @@ -0,0 +1,72 @@ +#! /bin/bash +# +# @file xhr-http-keep-alive.bash +# For testing HTTP-Keep-Alive automatically in the CI. +# +# We use `strace` to track system calls within the process that open a TCP connection. +# If HTTP-Keep-Alive is working, the total number of TCP connections opened should be 1 for a single remote host. +# +# @author Tom Tang (xmader@distributive.network) +# @date May 2024 + +set -u +set -o pipefail + +panic() +{ + echo "FAIL: $*" >&2 + exit 2 +} + +cd `dirname "$0"` || panic "could not change to test directory" + +if [[ "$OSTYPE" != "linux-gnu"* ]]; then + exit 0 + # Skip non-Linux for this test + # TODO: add tests on Windows and macOS. What's the equivalence of `strace`? +fi + +code=' +function newRequest(url) { + return new Promise(function (resolve, reject) + { + let xhr = new XMLHttpRequest(); + xhr.open("GET", url); + xhr.onload = function () + { + if (this.status >= 200 && this.status < 300) resolve(this.response); + else reject(new Error(this.status)); + }; + xhr.onerror = (ev) => reject(ev.error); + xhr.send(); + }); +} + +async function main() { + await newRequest("http://www.example.org/"); + await newRequest("http://www.example.org/"); + await newRequest("http://http.badssl.com/"); +} + +main(); +' + +# Trace the `socket` system call https://man.archlinux.org/man/socket.2 +# AF_INET: IPv4, IPPROTO_TCP: TCP connection +TRACE=$(strace -f -e socket \ + "${PMJS:-pmjs}" -e "$code" \ + < /dev/null 2>&1 +) + +# We have 3 HTTP requests, but we should only have 2 TCP connections open, +# as HTTP-Keep-Alive reuses the socket for a single remote host. +echo "$TRACE" \ +| tr -d '\r' \ +| grep -c -E 'socket\(AF_INET, \w*(\|\w*)+, IPPROTO_TCP\)' \ +| while read qty + do + echo "$TRACE" + echo "TCP connections opened: $qty" + [ "$qty" != "2" ] && panic qty should not be $qty + break + done || exit $? From c207baccee39940095b9d7fa154e7b9239456702 Mon Sep 17 00:00:00 2001 From: philippedistributive <151072087+philippedistributive@users.noreply.github.com> Date: Mon, 3 Jun 2024 11:48:09 -0400 Subject: [PATCH 062/428] Update src/JobQueue.cc --- src/JobQueue.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/JobQueue.cc b/src/JobQueue.cc index 25ae9c16..429a4acb 100644 --- a/src/JobQueue.cc +++ b/src/JobQueue.cc @@ -129,7 +129,7 @@ void JobQueue::promiseRejectionTracker(JSContext *cx, if (state != JS::PromiseRejectionHandlingState::Unhandled) { return; } - // The `mutedErrors` option is set to True in `pm.eval`, eval errors or unhandled rejections should be ignored. + // If the `mutedErrors` option is set to True in `pm.eval`, eval errors or unhandled rejections should be ignored. if (mutedErrors) { return; } From 1d1873bf3cfa9e19b703b6265b914454e0e4ac14 Mon Sep 17 00:00:00 2001 From: philippedistributive <151072087+philippedistributive@users.noreply.github.com> Date: Mon, 3 Jun 2024 12:08:07 -0400 Subject: [PATCH 063/428] Update src/setSpiderMonkeyException.cc --- src/setSpiderMonkeyException.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/setSpiderMonkeyException.cc b/src/setSpiderMonkeyException.cc index ee691d87..e59549c3 100644 --- a/src/setSpiderMonkeyException.cc +++ b/src/setSpiderMonkeyException.cc @@ -105,7 +105,7 @@ void setSpiderMonkeyException(JSContext *cx) { PyObject *errStr = getExceptionString(cx, exceptionStack, printStack); PyObject *errObj = PyObject_CallFunction(SpiderMonkeyError, "O", errStr); // errObj = SpiderMonkeyError(errStr) Py_XDECREF(errStr); - // Preserve the original JS value as the `jsError` attribute for lossless conversion back + // Preserve the original JS value as the `jsError` attribute for lossless back conversion PyObject *originalJsErrCapsule = DictType::getPyObject(cx, exn); PyObject_SetAttrString(errObj, "jsError", originalJsErrCapsule); Py_XDECREF(originalJsErrCapsule); From 427950fb80ab1236e29372724c33dd185f496960 Mon Sep 17 00:00:00 2001 From: philippedistributive <151072087+philippedistributive@users.noreply.github.com> Date: Mon, 3 Jun 2024 12:08:34 -0400 Subject: [PATCH 064/428] Update src/setSpiderMonkeyException.cc --- src/setSpiderMonkeyException.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/setSpiderMonkeyException.cc b/src/setSpiderMonkeyException.cc index e59549c3..7b0e2bab 100644 --- a/src/setSpiderMonkeyException.cc +++ b/src/setSpiderMonkeyException.cc @@ -110,7 +110,7 @@ void setSpiderMonkeyException(JSContext *cx) { PyObject_SetAttrString(errObj, "jsError", originalJsErrCapsule); Py_XDECREF(originalJsErrCapsule); // `PyErr_SetObject` can accept either an already created Exception instance or the containing exception value as the second argument - // see https://github.com/python/cpython/blob/v3.9.16/Python/errors.c#L134-L150 + // see https://github.com/python/cpython/blob/v3.9.16/Python/errors.c#L134-L150 PyErr_SetObject(SpiderMonkeyError, errObj); Py_XDECREF(errObj); } From d495fddd7585bb70c334e627b0ad784467a4ab08 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Mon, 3 Jun 2024 19:36:23 +0000 Subject: [PATCH 065/428] feat(XHR): change the default HTTP-Keep-Alive to 5s 5s is the default for Node.js's `http.globalAgent`, see the change history in https://nodejs.org/dist/latest/docs/api/http.html#httpglobalagent --- python/pythonmonkey/builtin_modules/XMLHttpRequest-internal.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/python/pythonmonkey/builtin_modules/XMLHttpRequest-internal.py b/python/pythonmonkey/builtin_modules/XMLHttpRequest-internal.py index af11208b..e3ea1824 100644 --- a/python/pythonmonkey/builtin_modules/XMLHttpRequest-internal.py +++ b/python/pythonmonkey/builtin_modules/XMLHttpRequest-internal.py @@ -51,7 +51,8 @@ async def request( # to support HTTP-Keep-Alive global keepAliveConnector if (not keepAliveConnector): - keepAliveConnector = aiohttp.TCPConnector(keepalive_timeout=15) # seconds before closing Keep-Alive connection + # seconds before closing Keep-Alive connection. + keepAliveConnector = aiohttp.TCPConnector(keepalive_timeout=5) # 5s is the default for Node.js's `http.globalAgent` class BytesPayloadWithProgress(aiohttp.BytesPayload): _chunkMaxLength = 2**16 # aiohttp default From 76640de80a25af63144f87f72e259279f48fa2bf Mon Sep 17 00:00:00 2001 From: Caleb Aikens Date: Wed, 5 Jun 2024 11:15:46 -0400 Subject: [PATCH 066/428] fix(JSStringProxy): fix reference count management of JSStringProxies never reaching 0 --- src/JSObjectIterProxy.cc | 4 ++-- src/StrType.cc | 3 --- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/JSObjectIterProxy.cc b/src/JSObjectIterProxy.cc index eb7c9fc6..0163e713 100644 --- a/src/JSObjectIterProxy.cc +++ b/src/JSObjectIterProxy.cc @@ -78,11 +78,11 @@ PyObject *JSObjectIterProxyMethodDefinitions::JSObjectIterProxy_nextkey(JSObject ret = key; } + Py_INCREF(ret); if (self->it.kind != KIND_KEYS) { Py_DECREF(value); } - Py_INCREF(ret); return ret; } } else { @@ -108,11 +108,11 @@ PyObject *JSObjectIterProxyMethodDefinitions::JSObjectIterProxy_nextkey(JSObject ret = key; } + Py_INCREF(ret); if (self->it.kind != KIND_KEYS) { Py_DECREF(value); } - Py_INCREF(ret); return ret; } } diff --git a/src/StrType.cc b/src/StrType.cc index eeb95af9..0e4abf63 100644 --- a/src/StrType.cc +++ b/src/StrType.cc @@ -104,7 +104,6 @@ static PyObject *processString(JSContext *cx, JS::HandleValue strVal) { size_t length = JS::GetLinearStringLength(lstr); JSStringProxy *pyString = PyObject_New(JSStringProxy, &JSStringProxyType); // new reference - Py_INCREF(pyString); if (pyString == NULL) { return NULL; @@ -184,10 +183,8 @@ PyObject *StrType::getPyObject(JSContext *cx, JS::HandleValue str) { Py_INCREF(pyString); return pyString; } - } - return processString(cx, str); } From 13b13b7932e0db7ab52e5a697bc344af77c6aee4 Mon Sep 17 00:00:00 2001 From: Caleb Aikens Date: Wed, 5 Jun 2024 11:21:16 -0400 Subject: [PATCH 067/428] fix(Makefile): fix typo --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index a15c4035..5eece9f1 100644 --- a/Makefile +++ b/Makefile @@ -27,7 +27,7 @@ else ifeq ($(BUILD),Debug) PYTHON_BUILD_ENV += BUILD_TYPE=Debug else ifeq ($(BUILD),DRelease) PYTHON_BUILD_ENV += BUILD_TYPE=DRelease -else ifeq($(BUILD), None) +else ifeq ($(BUILD), None) PYTHON_BUILD_ENV += BUILD_TYPE=None else # Release build PYTHON_BUILD_ENV += BUILD_TYPE=Release From 84f00c40d0032103b2a825b908558facb9f79b4a Mon Sep 17 00:00:00 2001 From: Caleb Aikens Date: Wed, 5 Jun 2024 11:21:46 -0400 Subject: [PATCH 068/428] fix(PythonExternalString): sizeOfBuffer now correctly returns the length of the python string --- src/jsTypeFactory.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jsTypeFactory.cc b/src/jsTypeFactory.cc index ac8667ac..b0998160 100644 --- a/src/jsTypeFactory.cc +++ b/src/jsTypeFactory.cc @@ -69,7 +69,7 @@ void PythonExternalString::finalize(char16_t *chars) const size_t PythonExternalString::sizeOfBuffer(const char16_t *chars, mozilla::MallocSizeOf mallocSizeOf) const { - return 0; + return PyUnicode_GetLength(charToPyObjectMap[chars]); } PythonExternalString PythonExternalStringCallbacks = {}; From 5145f1ceb2f82befecf8c979de4c93489c78fd29 Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Wed, 5 Jun 2024 12:59:50 -0400 Subject: [PATCH 069/428] Do not print the internal implementation line in the trace method --- python/pythonmonkey/builtin_modules/console.js | 12 +++++++----- tests/js/console-methods.simple | 1 + 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/python/pythonmonkey/builtin_modules/console.js b/python/pythonmonkey/builtin_modules/console.js index bae4fc62..efbdde51 100644 --- a/python/pythonmonkey/builtin_modules/console.js +++ b/python/pythonmonkey/builtin_modules/console.js @@ -98,11 +98,13 @@ class Console const header = args.length > 0 ? `Trace: ${format(...args)}\n` : 'Trace\n'; - const stacks = new Error().stack - .split('\n') - .filter(s => s !== '') // filter out empty lines - .map(s => ' '+s) // add indent - .join('\n'); + + let stacks = new Error().stack.split('\n') + stacks.shift(); // skip the first line which is this.trace itself + stacks = stacks + .filter(s => s !== '') // filter out empty lines + .map(s => ' '+s) // add indent + .join('\n'); return this.debug(header + stacks); }; diff --git a/tests/js/console-methods.simple b/tests/js/console-methods.simple index 4c52923e..6c9a4f14 100644 --- a/tests/js/console-methods.simple +++ b/tests/js/console-methods.simple @@ -73,6 +73,7 @@ expectOutput('stderr', /^Assertion failed: abc undefined$/m, (console) => consol expectOutput('stdout', /^Trace\n/, (console) => console.trace()); expectOutput('stdout', /^Trace: \x1b\[90mundefined\x1b\[39m\n/, (console) => console.trace(undefined)); expectOutput('stdout', /^Trace: \x1b\[33m123\x1b\[39m\n/, (console) => console.trace(123)); +expectOutput('stdout', /^((?!console\.js)[\s\S])*$/, (console) => console.trace()); // implementation details should not show up in the trace // console.count() let keptConsole; From 84c9c65212f35bb0d25517ab085a36c2f098f6df Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Wed, 5 Jun 2024 13:04:58 -0400 Subject: [PATCH 070/428] improved formatting --- python/pythonmonkey/builtin_modules/console.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/python/pythonmonkey/builtin_modules/console.js b/python/pythonmonkey/builtin_modules/console.js index efbdde51..a2024d8c 100644 --- a/python/pythonmonkey/builtin_modules/console.js +++ b/python/pythonmonkey/builtin_modules/console.js @@ -99,7 +99,8 @@ class Console ? `Trace: ${format(...args)}\n` : 'Trace\n'; - let stacks = new Error().stack.split('\n') + let stacks = new Error().stack + .split('\n') stacks.shift(); // skip the first line which is this.trace itself stacks = stacks .filter(s => s !== '') // filter out empty lines From 1bd9b4dda072cbb35d63c2c31ceef0927be47969 Mon Sep 17 00:00:00 2001 From: Caleb Aikens Date: Fri, 7 Jun 2024 17:04:35 -0400 Subject: [PATCH 071/428] feat(PyFunctionProxy): support calling python functions from JS with too many or too few arguments --- src/jsTypeFactory.cc | 110 +++++++++++++++++++++++++++++++++---------- 1 file changed, 84 insertions(+), 26 deletions(-) diff --git a/src/jsTypeFactory.cc b/src/jsTypeFactory.cc index b0998160..6d1aee41 100644 --- a/src/jsTypeFactory.cc +++ b/src/jsTypeFactory.cc @@ -294,11 +294,11 @@ JS::Value jsTypeFactorySafe(JSContext *cx, PyObject *object) { return v; } -void setPyException(JSContext *cx) { +bool setPyException(JSContext *cx) { // Python `exit` and `sys.exit` only raise a SystemExit exception to end the program // We definitely don't want to catch it in JS if (PyErr_ExceptionMatches(PyExc_SystemExit)) { - return; + return false; } PyObject *type, *value, *traceback; @@ -314,52 +314,110 @@ void setPyException(JSContext *cx) { JS::RootedValue jsExceptionValue(cx, JS::ObjectValue(*jsException)); JS_SetPendingException(cx, jsExceptionValue); } + return true; } bool callPyFunc(JSContext *cx, unsigned int argc, JS::Value *vp) { JS::CallArgs callargs = JS::CallArgsFromVp(argc, vp); // get the python function from the 0th reserved slot - JS::Value pyFuncVal = js::GetFunctionNativeReserved(&(callargs.callee()), 0); - PyObject *pyFunc = (PyObject *)(pyFuncVal.toPrivate()); - - unsigned int callArgsLength = callargs.length(); + PyObject *pyFunc = (PyObject *)js::GetFunctionNativeReserved(&(callargs.callee()), 0).toPrivate(); + Py_INCREF(pyFunc); + PyObject *pyRval = NULL; + PyObject *pyArgs = NULL; + Py_ssize_t nNormalArgs = 0; // number of positional non-default arguments + Py_ssize_t nDefaultArgs = 0; // number of positional default arguments + bool varargs = false; + bool unknownNargs = false; + + if (PyCFunction_Check(pyFunc)) { + if (((PyCFunctionObject *)pyFunc)->m_ml->ml_flags & METH_NOARGS) { // 0 arguments + nNormalArgs = 0; + } + else if (((PyCFunctionObject *)pyFunc)->m_ml->ml_flags & METH_O) { // 1 argument + nNormalArgs = 1; + } + else { // unknown number of arguments + nNormalArgs = 0; + unknownNargs = true; + varargs = true; + } + } + else { + nNormalArgs = 1; + PyObject *f = pyFunc; + if (PyMethod_Check(pyFunc)) { + f = PyMethod_Function(pyFunc); // borrowed reference + nNormalArgs -= 1; // don't include the implicit `self` of the method as an argument + } + PyCodeObject *bytecode = (PyCodeObject *)PyFunction_GetCode(f); // borrowed reference + PyObject *defaults = PyFunction_GetDefaults(f); // borrowed reference + nDefaultArgs = defaults ? PyTuple_Size(defaults) : 0; + nNormalArgs += bytecode->co_argcount - nDefaultArgs - 1; + if (bytecode->co_flags & CO_VARARGS) { + varargs = true; + } + } - if (!callArgsLength) { + // use faster calling if no arguments are needed + if (((nNormalArgs + nDefaultArgs) == 0 && !varargs)) { #if PY_VERSION_HEX >= 0x03090000 - PyObject *pyRval = PyObject_CallNoArgs(pyFunc); + pyRval = PyObject_CallNoArgs(pyFunc); #else - PyObject *pyRval = _PyObject_CallNoArg(pyFunc); // in Python 3.8, the API is only available under the name with a leading underscore + pyRval = _PyObject_CallNoArg(pyFunc); // in Python 3.8, the API is only available under the name with a leading underscore #endif - if (PyErr_Occurred()) { // Check if an exception has already been set in Python error stack - setPyException(cx); - return false; + if (PyErr_Occurred() && setPyException(cx)) { // Check if an exception has already been set in Python error stack + goto failure; } - callargs.rval().set(jsTypeFactory(cx, pyRval)); - return true; + goto success; } // populate python args tuple - PyObject *pyArgs = PyTuple_New(callArgsLength); - for (size_t i = 0; i < callArgsLength; i++) { + Py_ssize_t argTupleLength; + if (unknownNargs) { // pass all passed arguments + argTupleLength = callargs.length(); + } + else if (varargs) { // if passed arguments is less than number of non-default positionals, rest will be set to `None` + argTupleLength = std::max((Py_ssize_t)callargs.length(), nNormalArgs); + } + else if (nNormalArgs > callargs.length()) { // if passed arguments is less than number of non-default positionals, rest will be set to `None` + argTupleLength = nNormalArgs; + } + else { // passed arguments greater than non-default positionals, so we may be replacing default positional arguments + argTupleLength = std::min((Py_ssize_t)callargs.length(), nNormalArgs+nDefaultArgs); + } + pyArgs = PyTuple_New(argTupleLength); + + for (size_t i = 0; i < callargs.length() && i < argTupleLength; i++) { JS::RootedValue jsArg(cx, callargs[i]); PyObject *pyArgObj = pyTypeFactory(cx, jsArg); if (!pyArgObj) return false; // error occurred PyTuple_SetItem(pyArgs, i, pyArgObj); } - PyObject *pyRval = PyObject_Call(pyFunc, pyArgs, NULL); - if (PyErr_Occurred()) { - setPyException(cx); - return false; + // set unspecified args to None, to match JS behaviour of setting unspecified args to undefined + for (Py_ssize_t i = callargs.length(); i < argTupleLength; i++) { + PyTuple_SetItem(pyArgs, i, Py_None); } - callargs.rval().set(jsTypeFactory(cx, pyRval)); - if (PyErr_Occurred()) { - Py_DECREF(pyRval); - setPyException(cx); - return false; + + pyRval = PyObject_Call(pyFunc, pyArgs, NULL); + if (PyErr_Occurred() && setPyException(cx)) { + goto failure; } + goto success; - Py_DECREF(pyRval); +success: + if (pyRval) { // can be NULL if SystemExit was raised + callargs.rval().set(jsTypeFactory(cx, pyRval)); + Py_DECREF(pyRval); + } + Py_DECREF(pyFunc); + Py_XDECREF(pyArgs); return true; + +failure: + Py_XDECREF(pyRval); + Py_DECREF(pyFunc); + Py_XDECREF(pyArgs); + return false; } \ No newline at end of file From df531fd4d3d644d6f7c8f9d00bd1b5b8bdb15a28 Mon Sep 17 00:00:00 2001 From: Caleb Aikens Date: Fri, 7 Jun 2024 17:05:20 -0400 Subject: [PATCH 072/428] chore(tests): remove outdated tests regarding number of function arguments --- tests/python/test_arrays.py | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/tests/python/test_arrays.py b/tests/python/test_arrays.py index 2f340ea5..8df49c03 100644 --- a/tests/python/test_arrays.py +++ b/tests/python/test_arrays.py @@ -894,33 +894,6 @@ def myFunc(e, f): assert "@evaluate:1:27" in str(e) -def test_sort_with_one_arg_keyfunc(): - items = ['Four', 'Three', 'One'] - - def myFunc(e): - return len(e) - try: - pm.eval("(arr, compareFun) => {arr.sort(compareFun)}")(items, myFunc) - assert (False) - except Exception as e: - assert str(type(e)) == "" - assert "takes 1 positional argument but 2 were given" in str(e) - assert "JS Stack Trace" in str(e) - assert "@evaluate:1:27" in str(e) - - -def test_sort_with_builtin_keyfunc(): - items = ['Four', 'Three', 'One'] - try: - pm.eval("(arr, compareFun) => {arr.sort(compareFun)}")(items, len) - assert (False) - except Exception as e: - assert str(type(e)) == "" - assert "len() takes exactly one argument (2 given)" in str(e) - assert "JS Stack Trace" in str(e) - assert "@evaluate:1:27" in str(e) - - def test_sort_with_js_func(): items = ['Four', 'Three', 'One'] result = [None] From 3b7fb97537c961d07b5c4e3ad2320d7f571e378f Mon Sep 17 00:00:00 2001 From: Caleb Aikens Date: Fri, 7 Jun 2024 17:07:47 -0400 Subject: [PATCH 073/428] tests(PyFunctionProxy): write tests for using python functions with too few or too many arguments --- tests/python/test_functions.py | 121 +++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 tests/python/test_functions.py diff --git a/tests/python/test_functions.py b/tests/python/test_functions.py new file mode 100644 index 00000000..5b61acb8 --- /dev/null +++ b/tests/python/test_functions.py @@ -0,0 +1,121 @@ +import pythonmonkey as pm + + +def test_func_no_args(): + def f(): + return 42 + assert 42 == pm.eval("(f) => f()")(f) + + +def test_func_too_many_args(): + def f(a, b): + return [a, b] + assert [1, 2] == pm.eval("(f) => f(1, 2, 3)")(f) + + +def test_func_equal_args(): + def f(a, b): + return [a, b] + assert [1, 2] == pm.eval("(f) => f(1, 2)")(f) + + +def test_func_too_few_args(): + def f(a, b): + return [a, b] + assert [1, None] == pm.eval("(f) => f(1)")(f) + + +def test_default_func_no_args(): + def f(a, b, c=42, d=43): + return [a, b, c, d] + assert [None, None, 42, 43] == pm.eval("(f) => f()")(f) + + +def test_default_func_too_many_default_args(): + def f(a, b, c=42, d=43): + return [a, b, c, d] + assert [1, 2, 3, 4] == pm.eval("(f) => f(1, 2, 3, 4, 5)")(f) + + +def test_default_func_equal_default_args(): + def f(a, b, c=42, d=43): + return [a, b, c, d] + assert [1, 2, 3, 4] == pm.eval("(f) => f(1, 2, 3, 4)")(f) + + +def test_default_func_too_few_default_args(): + def f(a, b, c=42, d=43): + return [a, b, c, d] + assert [1, 2, 3, 43] == pm.eval("(f) => f(1, 2, 3)")(f) + + +def test_default_func_equal_args(): + def f(a, b, c=42, d=43): + return [a, b, c, d] + assert [1, 2, 42, 43] == pm.eval("(f) => f(1, 2)")(f) + + +def test_default_func_too_few_args(): + def f(a, b, c=42, d=43): + return [a, b, c, d] + assert [1, None, 42, 43] == pm.eval("(f) => f(1)")(f) + + +def test_vararg_func_no_args(): + def f(a, b, *args): + return [a, b, *args] + assert [None, None] == pm.eval("(f) => f()")(f) + + +def test_vararg_func_too_many_args(): + def f(a, b, *args): + return [a, b, *args] + assert [1, 2, 3] == pm.eval("(f) => f(1, 2, 3)")(f) + + +def test_vararg_func_equal_args(): + def f(a, b, *args): + return [a, b, *args] + assert [1, 2] == pm.eval("(f) => f(1, 2)")(f) + + +def test_vararg_func_too_few_args(): + def f(a, b, *args): + return [a, b, *args] + assert [1, None] == pm.eval("(f) => f(1)")(f) + + +def test_default_vararg_func_no_args(): + def f(a, b, c=42, d=43, *args): + return [a, b, c, d, *args] + assert [None, None, 42, 43] == pm.eval("(f) => f()")(f) + + +def test_default_vararg_func_too_many_default_args(): + 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) + + +def test_default_vararg_func_equal_default_args(): + def f(a, b, c=42, d=43, *args): + return [a, b, c, d, *args] + assert [1, 2, 3, 4] == pm.eval("(f) => f(1, 2, 3, 4)")(f) + + +def test_default_vararg_func_too_few_default_args(): + def f(a, b, c=42, d=43, *args): + return [a, b, c, d, *args] + assert [1, 2, 3, 43] == pm.eval("(f) => f(1, 2, 3)")(f) + + +def test_default_vararg_func_equal_args(): + def f(a, b, c=42, d=43, *args): + return [a, b, c, d, *args] + assert [1, 2, 42, 43] == pm.eval("(f) => f(1, 2)")(f) + + +def test_default_vararg_func_too_few_args(): + def f(a, b, c=42, d=43, *args): + return [a, b, c, d, *args] + assert [1, None, 42, 43] == pm.eval("(f) => f(1)")(f) From d614916c75578fab349a2ece13ecddb64c03e5c4 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 12 Jun 2024 09:34:24 +0000 Subject: [PATCH 074/428] feat(pmjs): forcibly run the program module, discards the return value of the script --- python/pythonmonkey/require.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/python/pythonmonkey/require.py b/python/pythonmonkey/require.py index 957dd585..fcbf096b 100644 --- a/python/pythonmonkey/require.py +++ b/python/pythonmonkey/require.py @@ -409,7 +409,8 @@ def runProgramModule(filename, argv, extraPaths=[]): globalThis.__filename = fullFilename globalThis.__dirname = os.path.dirname(fullFilename) with open(fullFilename, encoding="utf-8", mode="r") as mainModuleSource: - pm.eval(mainModuleSource.read(), {'filename': fullFilename}) + pm.eval(mainModuleSource.read(), {'filename': fullFilename, 'noScriptRval': True}) + # forcibly run in file mode. We shouldn't be getting the last statement of the script as the result value. # The pythonmonkey require export. Every time it is used, the stack is inspected so that the filename # passed to createRequire is correct. This is necessary so that relative requires work. If the filename From 4767860b563335587a8949114b700d3793f64eba Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 12 Jun 2024 09:39:00 +0000 Subject: [PATCH 075/428] docs: update README for eval options --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 1b799f0c..8f6a9550 100644 --- a/README.md +++ b/README.md @@ -164,11 +164,11 @@ They are largely based on SpiderMonkey's `CompileOptions`. The supported option - `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`: experimental -- `noScriptRval`: experimental -- `selfHosting`: experimental -- `strict`: experimental -- `module`: experimental +- `mutedErrors`: if set to `True`, eval errors or unhandled rejections are ignored ("muted"). Default `False`. +- `noScriptRval`: if `False`, return the last expression value of the script as the result value to the caller. Default `False`. +- `selfHosting`: *experimental* +- `strict`: forcibly evaluate in strict mode (`"use strict"`). Default `False`. +- `module`: indicate the file is an ECMAScript module (always strict mode code and disallow HTML comments). Default `False`. - `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. From 61eeeada3ca34dc07f89df9e5086db09554e53e6 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 12 Jun 2024 10:17:16 +0000 Subject: [PATCH 076/428] fix(pyTypeFactory): properly print the error message for JS `symbol`s --- src/pyTypeFactory.cc | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/pyTypeFactory.cc b/src/pyTypeFactory.cc index 63a0a34f..818a320b 100644 --- a/src/pyTypeFactory.cc +++ b/src/pyTypeFactory.cc @@ -53,7 +53,7 @@ PyObject *pyTypeFactory(JSContext *cx, JS::HandleValue rval) { return StrType::getPyObject(cx, rval); } else if (rval.isSymbol()) { - printf("symbol type is not handled by PythonMonkey yet"); + printf("symbol type is not handled by PythonMonkey yet\n"); } else if (rval.isBigInt()) { return IntType::getPyObject(cx, rval.toBigInt()); @@ -121,8 +121,13 @@ PyObject *pyTypeFactory(JSContext *cx, JS::HandleValue rval) { } std::string errorString("pythonmonkey cannot yet convert Javascript value of: "); - JS::RootedString str(cx, JS::ToString(cx, rval)); - errorString += JS_EncodeStringToUTF8(cx, str).get(); + JSString *valToStr = JS::ToString(cx, rval); + if (!valToStr) { // `JS::ToString` returns `nullptr` for JS symbols, see https://hg.mozilla.org/releases/mozilla-esr102/file/3b574e1/js/src/vm/StringType.cpp#l2208 + // TODO (Tom Tang): Revisit this once we have Symbol coercion support + valToStr = JS_ValueToSource(cx, rval); + } + JS::RootedString valToStrRooted(cx, valToStr); + errorString += JS_EncodeStringToUTF8(cx, valToStrRooted).get(); PyErr_SetString(PyExc_TypeError, errorString.c_str()); return NULL; } \ No newline at end of file From 91355f225f67fa8284a92a8614533f0e5cff6b00 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 12 Jun 2024 10:25:31 +0000 Subject: [PATCH 077/428] fix(pyTypeFactory): we shouldn't use `printf` here. Print to the Python error message instead. --- src/pyTypeFactory.cc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/pyTypeFactory.cc b/src/pyTypeFactory.cc index 818a320b..62212ee4 100644 --- a/src/pyTypeFactory.cc +++ b/src/pyTypeFactory.cc @@ -37,6 +37,8 @@ #include PyObject *pyTypeFactory(JSContext *cx, JS::HandleValue rval) { + std::string errorString; + if (rval.isUndefined()) { return NoneType::getPyObject(); } @@ -53,7 +55,7 @@ PyObject *pyTypeFactory(JSContext *cx, JS::HandleValue rval) { return StrType::getPyObject(cx, rval); } else if (rval.isSymbol()) { - printf("symbol type is not handled by PythonMonkey yet\n"); + errorString = "symbol type is not handled by PythonMonkey yet.\n"; } else if (rval.isBigInt()) { return IntType::getPyObject(cx, rval.toBigInt()); @@ -117,10 +119,10 @@ PyObject *pyTypeFactory(JSContext *cx, JS::HandleValue rval) { return DictType::getPyObject(cx, rval); } else if (rval.isMagic()) { - printf("magic type is not handled by PythonMonkey yet\n"); + errorString = "magic type is not handled by PythonMonkey yet.\n"; } - std::string errorString("pythonmonkey cannot yet convert Javascript value of: "); + errorString += "pythonmonkey cannot yet convert Javascript value of: "; JSString *valToStr = JS::ToString(cx, rval); if (!valToStr) { // `JS::ToString` returns `nullptr` for JS symbols, see https://hg.mozilla.org/releases/mozilla-esr102/file/3b574e1/js/src/vm/StringType.cpp#l2208 // TODO (Tom Tang): Revisit this once we have Symbol coercion support From a99f2701724d0a7c65ee52b00472b4c922c422ca Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 12 Jun 2024 10:53:29 +0000 Subject: [PATCH 078/428] feat(pminit): pminit should exit directly if npm ends with a non-zero exit code --- python/pminit/pminit/cli.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/python/pminit/pminit/cli.py b/python/pminit/pminit/cli.py index 700ba00c..f7a005a2 100644 --- a/python/pminit/pminit/cli.py +++ b/python/pminit/pminit/cli.py @@ -11,8 +11,8 @@ def execute(cmd: str, cwd: str): popen.stdout.close() return_code = popen.wait() - if return_code: - raise subprocess.CalledProcessError(return_code, cmd) + if return_code != 0: + sys.exit(return_code) def commandType(value: str): if value != "npm": @@ -34,7 +34,3 @@ def main(): ) execute(' '.join( args.executable + args.args ), pythonmonkey_path) - - - - From f1f324162cf1ae3e7cf79d29964e2e9892524733 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 12 Jun 2024 11:24:08 +0000 Subject: [PATCH 079/428] feat(typing): add back root type hints in the pyi file I have absolutely no idea why they were deleted. The changes are hidden in commit d946421c2ef75e10f7c7f527f0d473bb087b3cde and 1f42778740b89e8f6947b13b2c6b4c80267f298c --- python/pythonmonkey/pythonmonkey.pyi | 29 ++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/python/pythonmonkey/pythonmonkey.pyi b/python/pythonmonkey/pythonmonkey.pyi index 920db2e3..b553d38b 100644 --- a/python/pythonmonkey/pythonmonkey.pyi +++ b/python/pythonmonkey/pythonmonkey.pyi @@ -1,4 +1,5 @@ """ +stub file for type hints & documentations for the native module @see https://typing.readthedocs.io/en/latest/source/stubs.html """ @@ -55,6 +56,14 @@ def collect() -> None: """ +def internalBinding(namespace: str) -> JSObjectProxy: + """ + INTERNAL USE ONLY + + See function declarations in ./builtin_modules/internal-binding.d.ts + """ + + class JSFunctionProxy(): """ JavaScript Function proxy @@ -87,6 +96,26 @@ class JSMethodProxy(JSFunctionProxy, object): """ +class JSObjectProxy(dict): + """ + JavaScript Object proxy dict + """ + + def __init__(self) -> None: ... + + +class bigint(int): + """ + Representing JavaScript BigInt in Python + """ + + +class SpiderMonkeyError(Exception): + """ + Representing a corresponding JS Error in Python + """ + + null = _typing.Annotated[ _typing.NewType("pythonmonkey.null", object), "Representing the JS null type in Python using a singleton object", From 3b06c0e48336fa00b1dd995a88f58fd70bedd88d Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 12 Jun 2024 11:44:36 +0000 Subject: [PATCH 080/428] feat(typing): add typings for the helper functions --- python/pythonmonkey/pythonmonkey.pyi | 35 ++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/python/pythonmonkey/pythonmonkey.pyi b/python/pythonmonkey/pythonmonkey.pyi index b553d38b..4fec946f 100644 --- a/python/pythonmonkey/pythonmonkey.pyi +++ b/python/pythonmonkey/pythonmonkey.pyi @@ -26,6 +26,25 @@ def eval(code: str, evalOpts: EvalOptions = {}, /) -> _typing.Any: """ +def require(moduleIdentifier: str, /) -> JSObjectProxy: + """ + Return the exports of a CommonJS module identified by `moduleIdentifier`, using standard CommonJS semantics + """ + + +def new(ctor: JSFunctionProxy) -> _typing.Callable[..., _typing.Any]: + """ + Wrap the JS new operator, emitting a lambda which constructs a new + JS object upon invocation + """ + + +def typeof(jsval: _typing.Any, /): + """ + This is the JS `typeof` operator, wrapped in a function so that it can be used easily from Python. + """ + + def wait() -> _typing.Awaitable[None]: """ Block until all asynchronous jobs (Promise/setTimeout/etc.) finish. @@ -44,6 +63,12 @@ def stop() -> None: """ +def runProgramModule(filename: str, argv: _typing.List[str], extraPaths: _typing.List[str] = []) -> None: + """ + Load and evaluate a program (main) module. Program modules must be written in JavaScript. + """ + + def isCompilableUnit(code: str) -> bool: """ Hint if a string might be compilable Javascript without actual evaluation @@ -117,6 +142,12 @@ class SpiderMonkeyError(Exception): null = _typing.Annotated[ - _typing.NewType("pythonmonkey.null", object), - "Representing the JS null type in Python using a singleton object", + _typing.NewType("pythonmonkey.null", object), + "Representing the JS null type in Python using a singleton object", +] + + +globalThis = _typing.Annotated[ + JSObjectProxy, + "A Python Dict which is equivalent to the globalThis object in JavaScript", ] From 03f3b8a28bd84479dee619dad3b564740b9a6a76 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 12 Jun 2024 12:02:22 +0000 Subject: [PATCH 081/428] feat(typing): add typings for `JSStringProxy` and `JSArrayProxy` --- python/pythonmonkey/pythonmonkey.pyi | 31 +++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/python/pythonmonkey/pythonmonkey.pyi b/python/pythonmonkey/pythonmonkey.pyi index 4fec946f..b6e81761 100644 --- a/python/pythonmonkey/pythonmonkey.pyi +++ b/python/pythonmonkey/pythonmonkey.pyi @@ -115,10 +115,7 @@ class JSMethodProxy(JSFunctionProxy, object): print(myObject.value) # 42.0 """ - def __init__(self) -> None: - """ - PythonMonkey init function - """ + def __init__(self) -> None: "deleted" class JSObjectProxy(dict): @@ -126,7 +123,31 @@ class JSObjectProxy(dict): JavaScript Object proxy dict """ - def __init__(self) -> None: ... + def __init__(self) -> None: "deleted" + + +class JSArrayProxy(list): + """ + JavaScript Array proxy + """ + + def __init__(self) -> None: "deleted" + + +class JSArrayIterProxy(_typing.Iterator): + """ + JavaScript Array Iterator proxy + """ + + def __init__(self) -> None: "deleted" + + +class JSStringProxy(str): + """ + JavaScript String proxy + """ + + def __init__(self) -> None: "deleted" class bigint(int): From 1c70c9065ca0f6cec3705c56f4eba97e449b0de3 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 12 Jun 2024 13:05:32 +0000 Subject: [PATCH 082/428] feat(event-loop): do not propagate unhandled Promise rejection if there's no user-defined exception handler on the Python event-loop --- src/JobQueue.cc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/JobQueue.cc b/src/JobQueue.cc index 429a4acb..a07b9a6b 100644 --- a/src/JobQueue.cc +++ b/src/JobQueue.cc @@ -134,6 +134,15 @@ void JobQueue::promiseRejectionTracker(JSContext *cx, return; } + // Test if there's no user-defined (or pmjs defined) exception handler on the Python event-loop + PyEventLoop loop = PyEventLoop::getRunningLoop(); + if (!loop.initialized()) return; + PyObject *customHandler = PyObject_GetAttrString(loop._loop, "_exception_handler"); // see https://github.com/python/cpython/blob/v3.9.16/Lib/asyncio/base_events.py#L1782 + if (customHandler == Py_None) { // we only have the default exception handler + return; + } + + // Otherwise, go ahead and send this unhandled Promise rejection to the exception handler on the Python event-loop PyObject *pyFuture = PromiseType::getPyObject(cx, promise); // ref count == 2 // Unhandled Future object calls the event-loop exception handler in its destructor (the `__del__` magic method) // See https://github.com/python/cpython/blob/v3.9.16/Lib/asyncio/futures.py#L108 From 2e3eb177cd7d016ed91080736658e936412d841c Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 12 Jun 2024 13:52:13 +0000 Subject: [PATCH 083/428] feat(exception-propagation): print out the actual JS error for uncaught rejections instead of a Python `Future exception was never retrieved` error message when not using pmjs --- python/pythonmonkey/helpers.py | 13 ++++++++++++- src/JobQueue.cc | 10 ++++++++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/python/pythonmonkey/helpers.py b/python/pythonmonkey/helpers.py index 5a1c718f..76970edc 100644 --- a/python/pythonmonkey/helpers.py +++ b/python/pythonmonkey/helpers.py @@ -43,8 +43,19 @@ def new(ctor): return (lambda *args: newCtor(list(args))) +def simpleUncaughtExceptionHandler(loop, context): + """ + A simple exception handler for uncaught JS Promise rejections sent to the Python event-loop + + See https://docs.python.org/3.11/library/asyncio-eventloop.html#error-handling-api + """ + error = context["exception"] + pm.eval("(err) => console.error('Uncaught', err)")(error) + pm.stop() # unblock `await pm.wait()` to gracefully exit the program + + # List which symbols are exposed to the pythonmonkey module. -__all__ = ["new", "typeof"] +__all__ = ["new", "typeof", "simpleUncaughtExceptionHandler"] # Add the non-enumerable properties of globalThis which don't collide with pythonmonkey.so as exports: globalThis = pm.eval('globalThis') diff --git a/src/JobQueue.cc b/src/JobQueue.cc index a07b9a6b..d2a10efe 100644 --- a/src/JobQueue.cc +++ b/src/JobQueue.cc @@ -9,6 +9,7 @@ */ #include "include/JobQueue.hh" +#include "include/modules/pythonmonkey/pythonmonkey.hh" #include "include/PyEventLoop.hh" #include "include/pyTypeFactory.hh" @@ -139,10 +140,15 @@ void JobQueue::promiseRejectionTracker(JSContext *cx, if (!loop.initialized()) return; PyObject *customHandler = PyObject_GetAttrString(loop._loop, "_exception_handler"); // see https://github.com/python/cpython/blob/v3.9.16/Lib/asyncio/base_events.py#L1782 if (customHandler == Py_None) { // we only have the default exception handler - return; + // Set an exception handler to the event-loop + PyObject *pmModule = PyImport_ImportModule("pythonmonkey"); + PyObject *exceptionHandler = PyObject_GetAttrString(pmModule, "simpleUncaughtExceptionHandler"); + PyObject_CallMethod(loop._loop, "set_exception_handler", "O", exceptionHandler); + Py_DECREF(pmModule); + Py_DECREF(exceptionHandler); } - // Otherwise, go ahead and send this unhandled Promise rejection to the exception handler on the Python event-loop + // Go ahead and send this unhandled Promise rejection to the exception handler on the Python event-loop PyObject *pyFuture = PromiseType::getPyObject(cx, promise); // ref count == 2 // Unhandled Future object calls the event-loop exception handler in its destructor (the `__del__` magic method) // See https://github.com/python/cpython/blob/v3.9.16/Lib/asyncio/futures.py#L108 From 2462173bd0bbe0c429ee694eff1f1b864a2ee06c Mon Sep 17 00:00:00 2001 From: philippedistributive <151072087+philippedistributive@users.noreply.github.com> Date: Wed, 12 Jun 2024 10:52:58 -0400 Subject: [PATCH 084/428] Update python/pythonmonkey/require.py --- python/pythonmonkey/require.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/pythonmonkey/require.py b/python/pythonmonkey/require.py index fcbf096b..39043796 100644 --- a/python/pythonmonkey/require.py +++ b/python/pythonmonkey/require.py @@ -410,7 +410,7 @@ def runProgramModule(filename, argv, extraPaths=[]): globalThis.__dirname = os.path.dirname(fullFilename) with open(fullFilename, encoding="utf-8", mode="r") as mainModuleSource: pm.eval(mainModuleSource.read(), {'filename': fullFilename, 'noScriptRval': True}) - # forcibly run in file mode. We shouldn't be getting the last statement of the script as the result value. + # forcibly run in file mode. We shouldn't be getting the last expression of the script as the result value. # The pythonmonkey require export. Every time it is used, the stack is inspected so that the filename # passed to createRequire is correct. This is necessary so that relative requires work. If the filename From 842c15826b928304afa8c3caf429b816a41e5e77 Mon Sep 17 00:00:00 2001 From: Tom Wenzheng Tang Date: Thu, 13 Jun 2024 18:21:51 -0400 Subject: [PATCH 085/428] fix: reference count Co-authored-by: philippedistributive <151072087+philippedistributive@users.noreply.github.com> --- src/JobQueue.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/JobQueue.cc b/src/JobQueue.cc index d2a10efe..fc71e0cf 100644 --- a/src/JobQueue.cc +++ b/src/JobQueue.cc @@ -147,7 +147,7 @@ void JobQueue::promiseRejectionTracker(JSContext *cx, Py_DECREF(pmModule); Py_DECREF(exceptionHandler); } - +Py_DECREF(customHandler); // Go ahead and send this unhandled Promise rejection to the exception handler on the Python event-loop PyObject *pyFuture = PromiseType::getPyObject(cx, promise); // ref count == 2 // Unhandled Future object calls the event-loop exception handler in its destructor (the `__del__` magic method) From 06d8288e2c416099ec3cbc190618b059e2dc6205 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Thu, 13 Jun 2024 22:24:55 +0000 Subject: [PATCH 086/428] fix: reference count --- src/JobQueue.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/JobQueue.cc b/src/JobQueue.cc index fc71e0cf..19cc0cf5 100644 --- a/src/JobQueue.cc +++ b/src/JobQueue.cc @@ -147,7 +147,8 @@ void JobQueue::promiseRejectionTracker(JSContext *cx, Py_DECREF(pmModule); Py_DECREF(exceptionHandler); } -Py_DECREF(customHandler); + Py_DECREF(customHandler); + // Go ahead and send this unhandled Promise rejection to the exception handler on the Python event-loop PyObject *pyFuture = PromiseType::getPyObject(cx, promise); // ref count == 2 // Unhandled Future object calls the event-loop exception handler in its destructor (the `__del__` magic method) From 665af9f3a8b09d72cd720c32092f3a11bcd45250 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Fri, 14 Jun 2024 05:52:26 +0000 Subject: [PATCH 087/428] test(exception-propagation): add test for the uncaught Promise rejections handler when not in the pmjs environment --- tests/js/uncaught-rejection-handler.bash | 53 ++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 tests/js/uncaught-rejection-handler.bash diff --git a/tests/js/uncaught-rejection-handler.bash b/tests/js/uncaught-rejection-handler.bash new file mode 100644 index 00000000..837d286c --- /dev/null +++ b/tests/js/uncaught-rejection-handler.bash @@ -0,0 +1,53 @@ +#! /bin/bash +# +# @file uncaught-rejection-handler.bash +# For testing if the actual JS error gets printed out for uncaught Promise rejections, +# instead of printing out a Python `Future exception was never retrieved` error message when not in pmjs +# +# @author Tom Tang (xmader@distributive.network) +# @date June 2024 + +set -u +set -o pipefail + +panic() +{ + echo "FAIL: $*" >&2 + exit 2 +} + +cd `dirname "$0"` || panic "could not change to test directory" + +code=' +import asyncio +import pythonmonkey as pm + +async def pythonmonkey_main(): + pm.eval("""void Promise.reject(new TypeError("abc"));""") + await pm.wait() + +asyncio.run(pythonmonkey_main()) +' + +OUTPUT=$(python -c "$code" \ + < /dev/null 2>&1 +) + +echo "$OUTPUT" \ +| tr -d '\r' \ +| (grep -c 'Future exception was never retrieved' || true) \ +| while read qty + do + echo "$OUTPUT" + [ "$qty" != "0" ] && panic "There shouldn't be a 'Future exception was never retrieved' error massage" + break + done || exit $? + +echo "$OUTPUT" \ +| tr -d '\r' \ +| grep -c 'Uncaught TypeError: abc' \ +| while read qty + do + [ "$qty" != "1" ] && panic "It should print out 'Uncaught TypeError' directly" + break + done || exit $? From 7b6e71f3f51903b5823a44791833fb54d048c0f9 Mon Sep 17 00:00:00 2001 From: Caleb Aikens Date: Fri, 14 Jun 2024 11:31:36 -0400 Subject: [PATCH 088/428] refactor(jsTypeFactory): evaluate function object flags once --- src/jsTypeFactory.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/jsTypeFactory.cc b/src/jsTypeFactory.cc index 6d1aee41..bcf40e4c 100644 --- a/src/jsTypeFactory.cc +++ b/src/jsTypeFactory.cc @@ -331,10 +331,11 @@ bool callPyFunc(JSContext *cx, unsigned int argc, JS::Value *vp) { bool unknownNargs = false; if (PyCFunction_Check(pyFunc)) { - if (((PyCFunctionObject *)pyFunc)->m_ml->ml_flags & METH_NOARGS) { // 0 arguments + const int funcFlags = ((PyCFunctionObject *)pyFunc)->m_ml->ml_flags; + if (funcFlags & METH_NOARGS) { // 0 arguments nNormalArgs = 0; } - else if (((PyCFunctionObject *)pyFunc)->m_ml->ml_flags & METH_O) { // 1 argument + else if (funcFlags & METH_O) { // 1 argument nNormalArgs = 1; } else { // unknown number of arguments From 77a8c0f9ed2e760a8d5e182f738badfd15cf24dc Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 19 Jun 2024 04:36:52 +0000 Subject: [PATCH 089/428] chore: build SpiderMonkey from mozilla-central Switching to mozilla-central from the ESR versions could save us from bugs that were solved several months ago in upstream SpiderMonkey tip but haven't been backported to ESR. The mozilla-central commit hash to be used is stored in the `mozcentral.version` file. --- .github/workflows/test-and-publish.yaml | 16 +++++++++++----- .gitignore | 4 +++- cmake/modules/FindSpiderMonkey.cmake | 23 ++++++++++++++++++----- mozcentral.version | 1 + setup.sh | 13 ++++++++----- 5 files changed, 41 insertions(+), 16 deletions(-) create mode 100644 mozcentral.version diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 99383de8..b862941c 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -69,13 +69,15 @@ jobs: - uses: actions/setup-python@v5 with: python-version: ${{ matrix.python_version }} + - name: Read the mozilla-central commit hash to be used + run: echo "MOZCENTRAL_VERSION=$(cat mozcentral.version)" >> $GITHUB_ENV - name: Cache spidermonkey build id: cache-spidermonkey uses: actions/cache@v4 with: path: | ./_spidermonkey_install/* - key: spidermonkey115.8.0-${{ runner.os }}-${{ runner.arch }} + key: spidermonkey-${{ env.MOZCENTRAL_VERSION }}-${{ runner.os }}-${{ runner.arch }} lookup-only: true # skip download - name: Setup XCode if: ${{ (matrix.os == 'macos-13' || matrix.os == 'macos-14') && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} @@ -89,13 +91,15 @@ jobs: runs-on: windows-2019 steps: - uses: actions/checkout@v4 + - name: Read the mozilla-central commit hash to be used + run: echo "MOZCENTRAL_VERSION=$(cat mozcentral.version)" >> $GITHUB_ENV - name: Cache spidermonkey build id: cache-spidermonkey uses: actions/cache@v4 with: path: | ./_spidermonkey_install/* - key: spidermonkey115.8.0-${{ runner.os }}-${{ runner.arch }} + key: spidermonkey-${{ env.MOZCENTRAL_VERSION }}-${{ runner.os }}-${{ runner.arch }} lookup-only: true # skip download - name: Install dependencies if: ${{ steps.cache-spidermonkey.outputs.cache-hit != 'true' }} @@ -104,7 +108,7 @@ jobs: # Already installed in Github Actions runner # choco install -y cmake --installargs 'ADD_CMAKE_TO_PATH=System' # add CMake to system PATH # choco install -y llvm gnuwin32-m4 - choco install -y wget make + choco install -y wget make unzip - name: Install MozillaBuild if: ${{ steps.cache-spidermonkey.outputs.cache-hit != 'true' }} run: | @@ -154,7 +158,7 @@ jobs: sudo apt-get install -y cmake llvm elif [[ "$OSTYPE" == "darwin"* ]]; then # macOS brew update || true # allow failure - brew install cmake pkg-config wget coreutils # `coreutils` installs the `realpath` command + brew install cmake pkg-config wget unzip coreutils # `coreutils` installs the `realpath` command fi echo "Installing python deps" poetry self add "poetry-dynamic-versioning[plugin]" @@ -177,12 +181,14 @@ jobs: with: name: docs-${{ github.run_id }}-${{ github.sha }} path: ./build/docs/html/ + - name: Read the mozilla-central commit hash to be used + run: echo "MOZCENTRAL_VERSION=$(cat mozcentral.version)" >> $GITHUB_ENV - name: Use cached spidermonkey build uses: actions/cache@v4 with: path: | ./_spidermonkey_install/* - key: spidermonkey115.8.0-${{ runner.os }}-${{ runner.arch }} + key: spidermonkey-${{ env.MOZCENTRAL_VERSION }}-${{ runner.os }}-${{ runner.arch }} fail-on-cache-miss: true # SpiderMonkey is expected to be cached in its dedicated job - name: Build pminit run: | diff --git a/.gitignore b/.gitignore index 00be16f6..2ce3062a 100644 --- a/.gitignore +++ b/.gitignore @@ -7,10 +7,12 @@ lib/* .pytest_cache .DS_Store firefox-*.tar.xz +firefox-*.zip firefox-*/ +mozilla-central-* __pycache__ Testing/Temporary -_spidermonkey_install +_spidermonkey_install* uncrustify-*.tar.gz uncrustify-*/ uncrustify diff --git a/cmake/modules/FindSpiderMonkey.cmake b/cmake/modules/FindSpiderMonkey.cmake index ab5ae2a2..84fca1ca 100644 --- a/cmake/modules/FindSpiderMonkey.cmake +++ b/cmake/modules/FindSpiderMonkey.cmake @@ -24,8 +24,6 @@ # SPIDERMONKEY_FOUND - True if SpiderMonkey found. # SPIDERMONKEY_THREADSAFE - True if SpiderMonkey is compiled with multi threading support. -#Last Change: 2022-10-03 (Caleb Aikens) - include(CheckIncludeFileCXX) include(CheckCXXSourceCompiles) include(CheckCXXSourceRuns) @@ -36,11 +34,26 @@ if(SPIDERMONKEY_FOUND) set(SPIDERMONKEY_FIND_QUIETLY TRUE) endif() +# Get the SpiderMonkey major version number +# See https://hg.mozilla.org/releases/mozilla-esr102/file/tip/js/src/old-configure.in#l1081 +file(GLOB LIB_PATH "${CMAKE_CURRENT_SOURCE_DIR}/_spidermonkey_install") +execute_process(COMMAND + "sh" "-c" "./js*-config --version" # Run "_spidermonkey_install/bin/js*-config --version" to print the full version number + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/_spidermonkey_install/bin" + OUTPUT_VARIABLE MOZILLA_VERSION +) +string(STRIP ${MOZILLA_VERSION} MOZILLA_VERSION) +string(REGEX REPLACE "^([0-9]+)(\\.[0-9]+)*([ab][0-9]|)?" # Only the MAJOR and the "a1" (indicator of nightly build) part is needed + "\\1\\3" # see https://hg.mozilla.org/releases/mozilla-esr102/file/tip/build/moz.configure/init.configure#l959 + MOZILLA_SYMBOLVERSION + ${MOZILLA_VERSION} +) + # SpiderMonkey search paths set(SPIDERMONKEY_PATHS "${CMAKE_CURRENT_SOURCE_DIR}/_spidermonkey_install" "${CMAKE_CURRENT_SOURCE_DIR}/_spidermonkey_install/lib" - "${CMAKE_CURRENT_SOURCE_DIR}/_spidermonkey_install/include/mozjs-115" + "${CMAKE_CURRENT_SOURCE_DIR}/_spidermonkey_install/include/mozjs-${MOZILLA_SYMBOLVERSION}" ${SPIDERMONKEY_ROOT} $ENV{SPIDERMONKEY_ROOT} ~/Library/Frameworks @@ -60,7 +73,7 @@ set(SPIDERMONKEY_PATHS set(SPIDERMONKEY_HEADERS jsapi.h js/RequiredDefines.h) # SpiderMonkey include suffix paths -set(SPIDERMONKEY_INCLUDE_SUFFIX_PATHS include/mozjs-115/) +set(SPIDERMONKEY_INCLUDE_SUFFIX_PATHS include/mozjs-${MOZILLA_SYMBOLVERSION}/) # Find SpiderMonkey include path find_path(SPIDERMONKEY_INCLUDE_DIR ${SPIDERMONKEY_HEADERS} @@ -71,7 +84,7 @@ find_path(SPIDERMONKEY_INCLUDE_DIR ${SPIDERMONKEY_HEADERS} ) # SpiderMonkey libs -set(SPIDERMONKEY_LIBRARY_NAMES libmozjs-115.so libmozjs-115.dylib mozjs-115.lib) +set(SPIDERMONKEY_LIBRARY_NAMES libmozjs-${MOZILLA_SYMBOLVERSION}.so libmozjs-${MOZILLA_SYMBOLVERSION}.dylib mozjs-${MOZILLA_SYMBOLVERSION}.lib) set(SPIDERMONKEY_LIB_SUFFIX_PATHS js/src/build lib) diff --git a/mozcentral.version b/mozcentral.version new file mode 100644 index 00000000..7b2cc323 --- /dev/null +++ b/mozcentral.version @@ -0,0 +1 @@ +74b39df74a4a38e44f4b3783a5c4e4e8980ccf6f \ No newline at end of file diff --git a/setup.sh b/setup.sh index fd553fdb..b6e53f0c 100755 --- a/setup.sh +++ b/setup.sh @@ -18,7 +18,7 @@ if [[ "$OSTYPE" == "linux-gnu"* ]]; then # Linux SUDO='sudo' fi $SUDO apt-get update --yes - $SUDO apt-get install --yes cmake graphviz llvm clang pkg-config m4 \ + $SUDO apt-get install --yes cmake graphviz llvm clang pkg-config m4 unzip \ wget curl python3-distutils python3-dev # Install Doxygen # the newest version in Ubuntu 20.04 repository is 1.8.17, but we need Doxygen 1.9 series @@ -28,7 +28,7 @@ if [[ "$OSTYPE" == "linux-gnu"* ]]; then # Linux rm -rf doxygen-1.9.7 doxygen-1.9.7.linux.bin.tar.gz elif [[ "$OSTYPE" == "darwin"* ]]; then # macOS brew update || true # allow failure - brew install cmake doxygen pkg-config wget coreutils # `coreutils` installs the `realpath` command + brew install cmake doxygen pkg-config wget unzip coreutils # `coreutils` installs the `realpath` command elif [[ "$OSTYPE" == "msys"* ]]; then # Windows echo "Dependencies are not going to be installed automatically on Windows." else @@ -37,6 +37,7 @@ else fi # Install rust compiler curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.69 # force to use Rust 1.69 because 1.70 has linking issues on Windows +cargo install cbindgen # Setup Poetry curl -sSL https://install.python-poetry.org | python3 - --version "1.7.1" if [[ "$OSTYPE" == "msys"* ]]; then # Windows @@ -65,9 +66,10 @@ cd ../.. echo "Done building uncrustify" echo "Downloading spidermonkey source code" -wget -c -q https://ftp.mozilla.org/pub/firefox/releases/115.8.0esr/source/firefox-115.8.0esr.source.tar.xz -mkdir -p firefox-source -tar xf firefox-115.8.0esr.source.tar.xz -C firefox-source --strip-components=1 # strip the root folder +# Read the commit hash for mozilla-central from the `mozcentral.version` file +MOZCENTRAL_VERSION=$(cat mozcentral.version) +wget -c -q -O firefox-source-${MOZCENTRAL_VERSION}.zip https://hg.mozilla.org/mozilla-central/archive/${MOZCENTRAL_VERSION}.zip +unzip -q firefox-source-${MOZCENTRAL_VERSION}.zip && mv mozilla-central-${MOZCENTRAL_VERSION} firefox-source echo "Done downloading spidermonkey source code" echo "Building spidermonkey" @@ -79,6 +81,7 @@ sed -i'' -e '/"winheap.cpp"/d' ./memory/mozalloc/moz.build # https://bugzilla.mo sed -i'' -e 's/"install-name-tool"/"install_name_tool"/' ./moz.configure # `install-name-tool` does not exist, but we have `install_name_tool` sed -i'' -e 's/bool Unbox/JS_PUBLIC_API bool Unbox/g' ./js/public/Class.h # need to manually add JS_PUBLIC_API to js::Unbox until it gets fixed in Spidermonkey sed -i'' -e 's/bool js::Unbox/JS_PUBLIC_API bool js::Unbox/g' ./js/src/vm/JSObject.cpp # same here +sed -i'' -e 's/shared_lib = self._pretty_path(libdef.output_path, backend_file)/shared_lib = libdef.lib_name/g' ./python/mozbuild/mozbuild/backend/recursivemake.py cd js/src mkdir -p _build cd _build From cb468af06ad6dd07d2fba160b3208064204d7401 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 19 Jun 2024 04:44:47 +0000 Subject: [PATCH 090/428] chore: `mozcentral.version` file is required for building from source --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index b2bc612f..a2d0d1cf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,6 +23,7 @@ include = [ { path = "tests", format = "sdist" }, { path = "CMakeLists.txt", format = "sdist" }, { path = "*.sh", format = "sdist" }, + { path = "mozcentral.version", format = "sdist" }, ] From 5e1d1621725a3fda430df69f9015fe05768245af Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 19 Jun 2024 04:48:10 +0000 Subject: [PATCH 091/428] chore: Rust v1.76 is required to build the latest SpiderMonkey --- setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.sh b/setup.sh index b6e53f0c..cf7fbf2b 100755 --- a/setup.sh +++ b/setup.sh @@ -36,7 +36,7 @@ else exit 1 fi # Install rust compiler -curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.69 # force to use Rust 1.69 because 1.70 has linking issues on Windows +curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.76 cargo install cbindgen # Setup Poetry curl -sSL https://install.python-poetry.org | python3 - --version "1.7.1" From e4c37db8de54ca2ffba9d4a57988f144275ac154 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 19 Jun 2024 05:19:07 +0000 Subject: [PATCH 092/428] chore: force the SpiderMonkey build system not to verify the macOS SDK version The latest version of SpiderMonkey on macOS requires at least Xcode SDK 14.4, but none is available on Github Actions runner's macOS 13 image. See https://github.com/actions/runner-images/blob/main/images/macos/macos-13-Readme.md#installed-sdks ERROR: SDK version "13.3" is too old. Please upgrade to at least 14.4. Try updating your system Xcode. --- .github/workflows/test-and-publish.yaml | 4 ++-- setup.sh | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index b862941c..d498af2c 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -81,9 +81,9 @@ jobs: lookup-only: true # skip download - name: Setup XCode if: ${{ (matrix.os == 'macos-13' || matrix.os == 'macos-14') && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} - # SpiderMonkey 115 ESR requires XCode SDK version at least 13.3 + # The latest SpiderMonkey requires XCode SDK version at least 14.4, but none is available on macOS 13 runners. # https://github.com/actions/runner-images/blob/main/images/macos/macos-13-Readme.md#installed-sdks - run: sudo xcode-select -switch /Applications/Xcode_14.3.app + run: sudo xcode-select -switch /Applications/Xcode_15.2.app - name: Build spidermonkey if: ${{ steps.cache-spidermonkey.outputs.cache-hit != 'true' }} run: ./setup.sh diff --git a/setup.sh b/setup.sh index cf7fbf2b..bfa307ce 100755 --- a/setup.sh +++ b/setup.sh @@ -81,7 +81,8 @@ sed -i'' -e '/"winheap.cpp"/d' ./memory/mozalloc/moz.build # https://bugzilla.mo sed -i'' -e 's/"install-name-tool"/"install_name_tool"/' ./moz.configure # `install-name-tool` does not exist, but we have `install_name_tool` sed -i'' -e 's/bool Unbox/JS_PUBLIC_API bool Unbox/g' ./js/public/Class.h # need to manually add JS_PUBLIC_API to js::Unbox until it gets fixed in Spidermonkey sed -i'' -e 's/bool js::Unbox/JS_PUBLIC_API bool js::Unbox/g' ./js/src/vm/JSObject.cpp # same here -sed -i'' -e 's/shared_lib = self._pretty_path(libdef.output_path, backend_file)/shared_lib = libdef.lib_name/g' ./python/mozbuild/mozbuild/backend/recursivemake.py +sed -i'' -e 's/shared_lib = self._pretty_path(libdef.output_path, backend_file)/shared_lib = libdef.lib_name/' ./python/mozbuild/mozbuild/backend/recursivemake.py +sed -i'' -e 's/if version < Version(mac_sdk_min_version())/if False/' ./build/moz.configure/toolchain.configure # do not verify the macOS SDK version as the reqiuired version is not available on Github Actions runner cd js/src mkdir -p _build cd _build From 12ed88b954c78a0127cbb7dbaa34a8ceffe5c5f3 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 19 Jun 2024 05:37:51 +0000 Subject: [PATCH 093/428] Revert "chore: force the SpiderMonkey build system not to verify the macOS SDK version" The hacky solution doesn't work. This reverts commit e4c37db8de54ca2ffba9d4a57988f144275ac154. --- .github/workflows/test-and-publish.yaml | 4 ++-- setup.sh | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index d498af2c..b862941c 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -81,9 +81,9 @@ jobs: lookup-only: true # skip download - name: Setup XCode if: ${{ (matrix.os == 'macos-13' || matrix.os == 'macos-14') && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} - # The latest SpiderMonkey requires XCode SDK version at least 14.4, but none is available on macOS 13 runners. + # SpiderMonkey 115 ESR requires XCode SDK version at least 13.3 # https://github.com/actions/runner-images/blob/main/images/macos/macos-13-Readme.md#installed-sdks - run: sudo xcode-select -switch /Applications/Xcode_15.2.app + run: sudo xcode-select -switch /Applications/Xcode_14.3.app - name: Build spidermonkey if: ${{ steps.cache-spidermonkey.outputs.cache-hit != 'true' }} run: ./setup.sh diff --git a/setup.sh b/setup.sh index bfa307ce..cf7fbf2b 100755 --- a/setup.sh +++ b/setup.sh @@ -81,8 +81,7 @@ sed -i'' -e '/"winheap.cpp"/d' ./memory/mozalloc/moz.build # https://bugzilla.mo sed -i'' -e 's/"install-name-tool"/"install_name_tool"/' ./moz.configure # `install-name-tool` does not exist, but we have `install_name_tool` sed -i'' -e 's/bool Unbox/JS_PUBLIC_API bool Unbox/g' ./js/public/Class.h # need to manually add JS_PUBLIC_API to js::Unbox until it gets fixed in Spidermonkey sed -i'' -e 's/bool js::Unbox/JS_PUBLIC_API bool js::Unbox/g' ./js/src/vm/JSObject.cpp # same here -sed -i'' -e 's/shared_lib = self._pretty_path(libdef.output_path, backend_file)/shared_lib = libdef.lib_name/' ./python/mozbuild/mozbuild/backend/recursivemake.py -sed -i'' -e 's/if version < Version(mac_sdk_min_version())/if False/' ./build/moz.configure/toolchain.configure # do not verify the macOS SDK version as the reqiuired version is not available on Github Actions runner +sed -i'' -e 's/shared_lib = self._pretty_path(libdef.output_path, backend_file)/shared_lib = libdef.lib_name/g' ./python/mozbuild/mozbuild/backend/recursivemake.py cd js/src mkdir -p _build cd _build From 647d0838f9301edd1fe2d6e272c8accef9a08fd4 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 19 Jun 2024 05:39:41 +0000 Subject: [PATCH 094/428] chore: update `setup.sh` --- setup.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.sh b/setup.sh index cf7fbf2b..55d3026d 100755 --- a/setup.sh +++ b/setup.sh @@ -52,7 +52,7 @@ echo "Done installing dependencies" echo "Downloading uncrustify source code" wget -c -q https://github.com/uncrustify/uncrustify/archive/refs/tags/uncrustify-0.78.1.tar.gz mkdir -p uncrustify-source -tar -xzvf uncrustify-0.78.1.tar.gz -C uncrustify-source --strip-components=1 # strip the root folder +tar -xzf uncrustify-0.78.1.tar.gz -C uncrustify-source --strip-components=1 # strip the root folder echo "Done downloading uncrustify source code" echo "Building uncrustify" @@ -81,7 +81,7 @@ sed -i'' -e '/"winheap.cpp"/d' ./memory/mozalloc/moz.build # https://bugzilla.mo sed -i'' -e 's/"install-name-tool"/"install_name_tool"/' ./moz.configure # `install-name-tool` does not exist, but we have `install_name_tool` sed -i'' -e 's/bool Unbox/JS_PUBLIC_API bool Unbox/g' ./js/public/Class.h # need to manually add JS_PUBLIC_API to js::Unbox until it gets fixed in Spidermonkey sed -i'' -e 's/bool js::Unbox/JS_PUBLIC_API bool js::Unbox/g' ./js/src/vm/JSObject.cpp # same here -sed -i'' -e 's/shared_lib = self._pretty_path(libdef.output_path, backend_file)/shared_lib = libdef.lib_name/g' ./python/mozbuild/mozbuild/backend/recursivemake.py +sed -i'' -e 's/shared_lib = self._pretty_path(libdef.output_path, backend_file)/shared_lib = libdef.lib_name/' ./python/mozbuild/mozbuild/backend/recursivemake.py cd js/src mkdir -p _build cd _build From b685d8337982ba92479153c62aa4ecd0fc3d959c Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 19 Jun 2024 05:42:18 +0000 Subject: [PATCH 095/428] chore: WIP: only macOS 14 runners can use SDK 14.4 (XCode 15.3) --- .github/workflows/test-and-publish.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index b862941c..d51a7a5e 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -80,10 +80,10 @@ jobs: key: spidermonkey-${{ env.MOZCENTRAL_VERSION }}-${{ runner.os }}-${{ runner.arch }} lookup-only: true # skip download - name: Setup XCode - if: ${{ (matrix.os == 'macos-13' || matrix.os == 'macos-14') && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} - # SpiderMonkey 115 ESR requires XCode SDK version at least 13.3 + if: ${{ matrix.os == 'macos-14' && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} + # The latest SpiderMonkey requires XCode SDK version at least 14.4, but none is available on macOS 13 runners. # https://github.com/actions/runner-images/blob/main/images/macos/macos-13-Readme.md#installed-sdks - run: sudo xcode-select -switch /Applications/Xcode_14.3.app + run: sudo xcode-select -switch /Applications/Xcode_15.3.app - name: Build spidermonkey if: ${{ steps.cache-spidermonkey.outputs.cache-hit != 'true' }} run: ./setup.sh From 4fdc92795bf1e7c1e9b1d9cbb71e1ea694e99733 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 19 Jun 2024 05:52:09 +0000 Subject: [PATCH 096/428] chore: WIP: can macOS 13 actually use SDK version 14.4? --- .github/workflows/test-and-publish.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index d51a7a5e..68b814d0 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -80,9 +80,9 @@ jobs: key: spidermonkey-${{ env.MOZCENTRAL_VERSION }}-${{ runner.os }}-${{ runner.arch }} lookup-only: true # skip download - name: Setup XCode - if: ${{ matrix.os == 'macos-14' && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} - # The latest SpiderMonkey requires XCode SDK version at least 14.4, but none is available on macOS 13 runners. - # https://github.com/actions/runner-images/blob/main/images/macos/macos-13-Readme.md#installed-sdks + if: ${{ (matrix.os == 'macos-13' || matrix.os == 'macos-14') && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} + # The latest SpiderMonkey requires XCode SDK version at least 14.4 + # https://github.com/actions/runner-images/blob/main/images/macos/macos-14-Readme.md#installed-sdks run: sudo xcode-select -switch /Applications/Xcode_15.3.app - name: Build spidermonkey if: ${{ steps.cache-spidermonkey.outputs.cache-hit != 'true' }} From 2d73bd57b313511a1ceff3beae5d4e7dd8cfc565 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 19 Jun 2024 07:36:23 +0000 Subject: [PATCH 097/428] chore: SpiderMonkey 125 should be good as it switched to macOS 14.4 SDK in 126 alpha Using the commit for mozilla-central tag `FIREFOX_NIGHTLY_125_END` --- .github/workflows/test-and-publish.yaml | 4 ++-- mozcentral.version | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 68b814d0..862745f7 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -81,9 +81,9 @@ jobs: lookup-only: true # skip download - name: Setup XCode if: ${{ (matrix.os == 'macos-13' || matrix.os == 'macos-14') && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} - # The latest SpiderMonkey requires XCode SDK version at least 14.4 + # SpiderMonkey 125 requires XCode SDK version at least 14.2 # https://github.com/actions/runner-images/blob/main/images/macos/macos-14-Readme.md#installed-sdks - run: sudo xcode-select -switch /Applications/Xcode_15.3.app + run: sudo xcode-select -switch /Applications/Xcode_15.2.app - name: Build spidermonkey if: ${{ steps.cache-spidermonkey.outputs.cache-hit != 'true' }} run: ./setup.sh diff --git a/mozcentral.version b/mozcentral.version index 7b2cc323..636e38c1 100644 --- a/mozcentral.version +++ b/mozcentral.version @@ -1 +1 @@ -74b39df74a4a38e44f4b3783a5c4e4e8980ccf6f \ No newline at end of file +3c5105fce0360bb6708a9ac3f09d06527b316119 \ No newline at end of file From 3a075322329b55aad8338dad00b9dadc95a112b2 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 19 Jun 2024 07:46:20 +0000 Subject: [PATCH 098/428] chore: try SpiderMonkey 120 Using the commit for mozilla-central tag `FIREFOX_NIGHTLY_120_END` --- mozcentral.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mozcentral.version b/mozcentral.version index 636e38c1..a9d6d3b8 100644 --- a/mozcentral.version +++ b/mozcentral.version @@ -1 +1 @@ -3c5105fce0360bb6708a9ac3f09d06527b316119 \ No newline at end of file +fc01df84fa6d91b9dabb4b608eb947cef3230871 \ No newline at end of file From 275b0bf459341c44e45e9686f6422ef1f61b70c1 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 19 Jun 2024 07:56:47 +0000 Subject: [PATCH 099/428] chore: switch back to SpiderMonkey 115 should be fail-proof Using the commit for mozilla-central tag `FIREFOX_NIGHTLY_115_END` --- mozcentral.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mozcentral.version b/mozcentral.version index a9d6d3b8..cc8045d9 100644 --- a/mozcentral.version +++ b/mozcentral.version @@ -1 +1 @@ -fc01df84fa6d91b9dabb4b608eb947cef3230871 \ No newline at end of file +8f983388de8ac77550eb07422e61c0444e7b8eb5 \ No newline at end of file From 8f70da77fbde55343e8620998bf400bd85fde1c0 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 19 Jun 2024 08:06:50 +0000 Subject: [PATCH 100/428] chore: rollback --- .github/workflows/test-and-publish.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 862745f7..b862941c 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -81,9 +81,9 @@ jobs: lookup-only: true # skip download - name: Setup XCode if: ${{ (matrix.os == 'macos-13' || matrix.os == 'macos-14') && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} - # SpiderMonkey 125 requires XCode SDK version at least 14.2 - # https://github.com/actions/runner-images/blob/main/images/macos/macos-14-Readme.md#installed-sdks - run: sudo xcode-select -switch /Applications/Xcode_15.2.app + # SpiderMonkey 115 ESR requires XCode SDK version at least 13.3 + # https://github.com/actions/runner-images/blob/main/images/macos/macos-13-Readme.md#installed-sdks + run: sudo xcode-select -switch /Applications/Xcode_14.3.app - name: Build spidermonkey if: ${{ steps.cache-spidermonkey.outputs.cache-hit != 'true' }} run: ./setup.sh From 21e4719be088a5fc3c24808d58d1792fe9ca1205 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 19 Jun 2024 08:07:14 +0000 Subject: [PATCH 101/428] Revert "chore: switch back to SpiderMonkey 115 should be fail-proof" This reverts commit 275b0bf459341c44e45e9686f6422ef1f61b70c1. --- mozcentral.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mozcentral.version b/mozcentral.version index cc8045d9..a9d6d3b8 100644 --- a/mozcentral.version +++ b/mozcentral.version @@ -1 +1 @@ -8f983388de8ac77550eb07422e61c0444e7b8eb5 \ No newline at end of file +fc01df84fa6d91b9dabb4b608eb947cef3230871 \ No newline at end of file From 72565d79eeab46ea345e979005d57ff505964d57 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 19 Jun 2024 08:08:57 +0000 Subject: [PATCH 102/428] Revert "chore: try SpiderMonkey 120" This reverts commit 3a075322329b55aad8338dad00b9dadc95a112b2. --- mozcentral.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mozcentral.version b/mozcentral.version index a9d6d3b8..636e38c1 100644 --- a/mozcentral.version +++ b/mozcentral.version @@ -1 +1 @@ -fc01df84fa6d91b9dabb4b608eb947cef3230871 \ No newline at end of file +3c5105fce0360bb6708a9ac3f09d06527b316119 \ No newline at end of file From a4ef58c93386181c17ffa38a10c8f0b600c4e539 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 19 Jun 2024 08:11:57 +0000 Subject: [PATCH 103/428] chore: force the build system not to verify the macOS SDK version --- setup.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.sh b/setup.sh index 55d3026d..ee2147ce 100755 --- a/setup.sh +++ b/setup.sh @@ -82,6 +82,7 @@ sed -i'' -e 's/"install-name-tool"/"install_name_tool"/' ./moz.configure # `inst sed -i'' -e 's/bool Unbox/JS_PUBLIC_API bool Unbox/g' ./js/public/Class.h # need to manually add JS_PUBLIC_API to js::Unbox until it gets fixed in Spidermonkey sed -i'' -e 's/bool js::Unbox/JS_PUBLIC_API bool js::Unbox/g' ./js/src/vm/JSObject.cpp # same here sed -i'' -e 's/shared_lib = self._pretty_path(libdef.output_path, backend_file)/shared_lib = libdef.lib_name/' ./python/mozbuild/mozbuild/backend/recursivemake.py +sed -i'' -e 's/if version < Version(mac_sdk_min_version())/if False/' ./build/moz.configure/toolchain.configure # do not verify the macOS SDK version as the reqiuired version is not available on Github Actions runner cd js/src mkdir -p _build cd _build From ff396afd7509f245579a243226d05141df13fff8 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 19 Jun 2024 08:24:10 +0000 Subject: [PATCH 104/428] chore: change back to the tip commit --- mozcentral.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mozcentral.version b/mozcentral.version index 636e38c1..7b2cc323 100644 --- a/mozcentral.version +++ b/mozcentral.version @@ -1 +1 @@ -3c5105fce0360bb6708a9ac3f09d06527b316119 \ No newline at end of file +74b39df74a4a38e44f4b3783a5c4e4e8980ccf6f \ No newline at end of file From 04d028b0e0600d7b0826f325029da5884648b577 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 19 Jun 2024 08:40:15 +0000 Subject: [PATCH 105/428] chore: WIP: ignore Windows builds for now --- .github/workflows/test-and-publish.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index b862941c..52b20016 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -88,6 +88,7 @@ jobs: if: ${{ steps.cache-spidermonkey.outputs.cache-hit != 'true' }} run: ./setup.sh build-spidermonkey-win: + if: false runs-on: windows-2019 steps: - uses: actions/checkout@v4 @@ -122,12 +123,12 @@ jobs: USE_MINTTY: 0 run: /c/mozilla-build/start-shell.bat -use-full-path -here ./setup.sh build-and-test: - needs: [build-spidermonkey-unix, build-spidermonkey-win] + needs: [build-spidermonkey-unix] strategy: fail-fast: false matrix: # The lowest supported version is Ubuntu 20.04 + Python 3.8 or macOS 12 + Python 3.9 - os: [ 'ubuntu-20.04', 'macos-12', 'macos-14', 'windows-2019' ] + os: [ 'ubuntu-20.04', 'macos-12', 'macos-14' ] python_version: [ '3.8', '3.9', '3.10', '3.11', '3.12' ] exclude: # actions/setup-python: The version '3.8'/'3.9' with architecture 'arm64' was not found for macOS. From 492fa8004106891e0e614d3b12f111423d6936cc Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Thu, 20 Jun 2024 06:54:54 +0000 Subject: [PATCH 106/428] fix: passing a column number offset for JS source code now requires the use of `JS::ColumnNumberOneOrigin` class after upgrading SpiderMonkey to mozilla-central tip --- src/ExceptionType.cc | 4 ++-- src/modules/pythonmonkey/pythonmonkey.cc | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ExceptionType.cc b/src/ExceptionType.cc index 3b4cb629..46b3743c 100644 --- a/src/ExceptionType.cc +++ b/src/ExceptionType.cc @@ -276,7 +276,7 @@ JSObject *ExceptionType::toJsError(JSContext *cx, PyObject *exceptionValue, PyOb JS::RootedString filename(cx, JS_NewStringCopyZ(cx, PyUnicode_AsUTF8(fileName))); JS::RootedString message(cx, JS_NewStringCopyZ(cx, msgStream.str().c_str())); // stack argument cannot be passed in as a string anymore (deprecated), and could not find a proper example using the new argument type - if (!JS::CreateError(cx, JSExnType::JSEXN_ERR, nullptr, filename, lineno, 0, nullptr, message, JS::NothingHandleValue, &rval)) { + if (!JS::CreateError(cx, JSExnType::JSEXN_ERR, nullptr, filename, lineno, JS::ColumnNumberOneOrigin(1), nullptr, message, JS::NothingHandleValue, &rval)) { return NULL; } @@ -306,7 +306,7 @@ JSObject *ExceptionType::toJsError(JSContext *cx, PyObject *exceptionValue, PyOb JS::RootedString filename(cx, JS_NewStringCopyZ(cx, "")); // cannot be null or omitted, but is overriden by the errorReport JS::RootedString message(cx, JS_NewStringCopyZ(cx, msgStream.str().c_str())); // filename cannot be null - if (!JS::CreateError(cx, JSExnType::JSEXN_ERR, nullptr, filename, 0, 0, errorReport, message, JS::NothingHandleValue, &rval)) { + if (!JS::CreateError(cx, JSExnType::JSEXN_ERR, nullptr, filename, 0, JS::ColumnNumberOneOrigin(1), errorReport, message, JS::NothingHandleValue, &rval)) { return NULL; } diff --git a/src/modules/pythonmonkey/pythonmonkey.cc b/src/modules/pythonmonkey/pythonmonkey.cc index 9ee013e7..75ae2af6 100644 --- a/src/modules/pythonmonkey/pythonmonkey.cc +++ b/src/modules/pythonmonkey/pythonmonkey.cc @@ -389,7 +389,7 @@ static PyObject *eval(PyObject *self, PyObject *args) { if (getEvalOption(evalOptions, "filename", &s)) options.setFile(s); if (getEvalOption(evalOptions, "lineno", &l)) options.setLine(l); - if (getEvalOption(evalOptions, "column", &l)) options.setColumn(l); + if (getEvalOption(evalOptions, "column", &l)) options.setColumn(JS::ColumnNumberOneOrigin(l)); if (getEvalOption(evalOptions, "mutedErrors", &b)) options.setMutedErrors(b); if (getEvalOption(evalOptions, "noScriptRval", &b)) options.setNoScriptRval(b); if (getEvalOption(evalOptions, "selfHosting", &b)) options.setSelfHostingMode(b); From f3df728c3de02081d281a1a3d0baa31177fa1ad6 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Thu, 20 Jun 2024 07:02:07 +0000 Subject: [PATCH 107/428] fix: extending `JS::JobQueue` class now needs to implement the `isDrainingStopped` virtual method after upgrading SpiderMonkey to mozilla-central tip --- include/JobQueue.hh | 5 +++++ src/JobQueue.cc | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/include/JobQueue.hh b/include/JobQueue.hh index 40bfc73b..fba3c782 100644 --- a/include/JobQueue.hh +++ b/include/JobQueue.hh @@ -78,6 +78,11 @@ void runJobs(JSContext *cx) override; */ bool empty() const override; +/** + * @return true if the job queue stops draining, which results in `empty()` being false after `runJobs()`. + */ +bool isDrainingStopped() const override; + /** * @brief Appends a callback to the queue of FinalizationRegistry callbacks * diff --git a/src/JobQueue.cc b/src/JobQueue.cc index 19cc0cf5..f00943dd 100644 --- a/src/JobQueue.cc +++ b/src/JobQueue.cc @@ -62,6 +62,11 @@ bool JobQueue::empty() const { throw std::logic_error("JobQueue::empty is not implemented\n"); } +bool JobQueue::isDrainingStopped() const { + // TODO (Tom Tang): implement this by detecting if the Python event-loop is still running + return false; +} + js::UniquePtr JobQueue::saveJobQueue(JSContext *cx) { auto saved = js::MakeUnique(); if (!saved) { From 79b6437cb89c58a439c9f5699bce894eeeabc8f8 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Thu, 20 Jun 2024 07:08:26 +0000 Subject: [PATCH 108/428] fix: for `JS::NewExternalArrayBuffer`, the custom destructor is now wrapped in a `mozilla::UniquePtr` instead of passing it directly to the function --- src/BufferType.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/BufferType.cc b/src/BufferType.cc index a97b9aa0..0ee2ec63 100644 --- a/src/BufferType.cc +++ b/src/BufferType.cc @@ -113,9 +113,12 @@ JSObject *BufferType::toJsTypedArray(JSContext *cx, PyObject *pyObject) { // Create a new ExternalArrayBuffer object // Note: data will be copied instead of transferring the ownership when this external ArrayBuffer is "transferred" to a worker thread. // see https://hg.mozilla.org/releases/mozilla-esr102/file/a03fde6/js/public/ArrayBuffer.h#l86 + mozilla::UniquePtr dataPtr( + view->buf /* data pointer */, + {BufferType::_releasePyBuffer, view /* the `bufView` argument to `_releasePyBuffer` */} + ); arrayBuffer = JS::NewExternalArrayBuffer(cx, - view->len /* byteLength */, view->buf /* data pointer */, - BufferType::_releasePyBuffer, view /* the `bufView` argument to `_releasePyBuffer` */ + view->len /* byteLength */, std::move(dataPtr) ); } else { // empty buffer arrayBuffer = JS::NewArrayBuffer(cx, 0); From 09bacb53398d73a89db27b2bd26e2e915ed49a04 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Thu, 20 Jun 2024 07:34:02 +0000 Subject: [PATCH 109/428] fix: `JSErrorReport`'s `filename` property is now a `JS::UniqueChars` (`mozilla::UniquePtr`) instead of a pure `char[]` after upgrading SpiderMonkey to mozilla-central tip --- src/setSpiderMonkeyException.cc | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/setSpiderMonkeyException.cc b/src/setSpiderMonkeyException.cc index ac08cb8c..6706b883 100644 --- a/src/setSpiderMonkeyException.cc +++ b/src/setSpiderMonkeyException.cc @@ -38,11 +38,15 @@ PyObject *getExceptionString(JSContext *cx, const JS::ExceptionStack &exceptionS std::stringstream outStrStream; JSErrorReport *errorReport = reportBuilder.report(); - if (errorReport && errorReport->filename) { // `errorReport->filename` (the source file name) can be null + if (errorReport && !!errorReport->filename) { // `errorReport->filename` (the source file name) can be null std::string offsetSpaces(errorReport->tokenOffset(), ' '); // number of spaces equal to tokenOffset std::string linebuf; // the offending JS line of code (can be empty) - outStrStream << "Error in file " << errorReport->filename << ", on line " << errorReport->lineno << ", column " << errorReport->column << ":\n"; + /* *INDENT-OFF* */ + outStrStream << "Error in file " << errorReport->filename.get() + << ", on line " << errorReport->lineno + << ", column " << errorReport->column.oneOriginValue() << ":\n"; + /* *INDENT-ON* */ if (errorReport->linebuf()) { std::wstring_convert, char16_t> convert; std::u16string u16linebuf(errorReport->linebuf()); @@ -106,7 +110,7 @@ void setSpiderMonkeyException(JSContext *cx) { PyObject *errStr = getExceptionString(cx, exceptionStack, printStack); PyObject *errObj = PyObject_CallFunction(SpiderMonkeyError, "O", errStr); // errObj = SpiderMonkeyError(errStr) Py_XDECREF(errStr); - // Preserve the original JS value as the `jsError` attribute for lossless back conversion + // Preserve the original JS value as the `jsError` attribute for lossless back conversion PyObject *originalJsErrCapsule = DictType::getPyObject(cx, exn); PyObject_SetAttrString(errObj, "jsError", originalJsErrCapsule); Py_XDECREF(originalJsErrCapsule); From 53af133ac3cecc4ff0d20fc871fcd4d121a10916 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Thu, 20 Jun 2024 07:36:53 +0000 Subject: [PATCH 110/428] fix: `setWeakRefsEnabled` and `setIteratorHelpersEnabled` no longer present on `JS::RealmCreationOptions` after upgrading SpiderMonkey to mozilla-central tip --- src/modules/pythonmonkey/pythonmonkey.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/modules/pythonmonkey/pythonmonkey.cc b/src/modules/pythonmonkey/pythonmonkey.cc index 75ae2af6..fb7cb5ca 100644 --- a/src/modules/pythonmonkey/pythonmonkey.cc +++ b/src/modules/pythonmonkey/pythonmonkey.cc @@ -549,8 +549,6 @@ PyMODINIT_FUNC PyInit_pythonmonkey(void) JS::RealmCreationOptions creationOptions = JS::RealmCreationOptions(); JS::RealmBehaviors behaviours = JS::RealmBehaviors(); - creationOptions.setWeakRefsEnabled(JS::WeakRefSpecifier::EnabledWithoutCleanupSome); // enable FinalizationRegistry - creationOptions.setIteratorHelpersEnabled(true); JS::RealmOptions options = JS::RealmOptions(creationOptions, behaviours); static JSClass globalClass = {"global", JSCLASS_GLOBAL_FLAGS, &JS::DefaultGlobalClassOps}; global = new JS::RootedObject(GLOBAL_CX, JS_NewGlobalObject(GLOBAL_CX, &globalClass, nullptr, JS::FireOnNewGlobalHook, options)); From 0415557a72d96ec93260860aaad0c9079775a385 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Thu, 20 Jun 2024 08:08:25 +0000 Subject: [PATCH 111/428] feat: SpiderMonkey now supports APIs for one-byte latin1 JSExternalStrings --- include/jsTypeFactory.hh | 3 +++ src/StrType.cc | 10 ++++++--- src/jsTypeFactory.cc | 45 ++++++++++++++++++++++++++-------------- 3 files changed, 39 insertions(+), 19 deletions(-) diff --git a/include/jsTypeFactory.hh b/include/jsTypeFactory.hh index e500908e..479ef938 100644 --- a/include/jsTypeFactory.hh +++ b/include/jsTypeFactory.hh @@ -25,6 +25,7 @@ public: * @return PyObject* - the PyObject string */ static PyObject *getPyString(const char16_t *chars); + static PyObject *getPyString(const JS::Latin1Char *chars); /** * @brief decrefs the underlying PyObject string when the JSString is finalized @@ -32,8 +33,10 @@ public: * @param chars - The char buffer of the string */ void finalize(char16_t *chars) const override; + void finalize(JS::Latin1Char *chars) const override; size_t sizeOfBuffer(const char16_t *chars, mozilla::MallocSizeOf mallocSizeOf) const override; + size_t sizeOfBuffer(const JS::Latin1Char *chars, mozilla::MallocSizeOf mallocSizeOf) const override; }; extern PythonExternalString PythonExternalStringCallbacks; diff --git a/src/StrType.cc b/src/StrType.cc index 0e4abf63..c5c7ae7e 100644 --- a/src/StrType.cc +++ b/src/StrType.cc @@ -175,11 +175,15 @@ static PyObject *processString(JSContext *cx, JS::HandleValue strVal) { PyObject *StrType::getPyObject(JSContext *cx, JS::HandleValue str) { const PythonExternalString *callbacks; - const char16_t *chars; + const char16_t *ucs2Buffer{}; + const JS::Latin1Char *latin1Buffer{}; - if (JS::IsExternalString(str.toString(), (const JSExternalStringCallbacks **)&callbacks, &chars)) { + if ( + JS::IsExternalUCString(str.toString(), (const JSExternalStringCallbacks **)&callbacks, &ucs2Buffer) || + JS::IsExternalStringLatin1(str.toString(), (const JSExternalStringCallbacks **)&callbacks, &latin1Buffer) + ) { if (callbacks == &PythonExternalStringCallbacks) { - PyObject *pyString = callbacks->getPyString(chars); + PyObject *pyString = ucs2Buffer ? callbacks->getPyString(ucs2Buffer) : callbacks->getPyString(latin1Buffer); Py_INCREF(pyString); return pyString; } diff --git a/src/jsTypeFactory.cc b/src/jsTypeFactory.cc index bcf40e4c..a5ccead4 100644 --- a/src/jsTypeFactory.cc +++ b/src/jsTypeFactory.cc @@ -49,11 +49,17 @@ static PyObjectProxyHandler pyObjectProxyHandler; static PyListProxyHandler pyListProxyHandler; static PyIterableProxyHandler pyIterableProxyHandler; -std::unordered_map charToPyObjectMap; // a map of char16_t buffers to their corresponding PyObjects, used when finalizing JSExternalStrings +std::unordered_map ucs2ToPyObjectMap; // a map of char16_t (UCS-2) buffers to their corresponding PyObjects, used when finalizing JSExternalStrings +std::unordered_map latin1ToPyObjectMap; // a map of Latin-1 char buffers to their corresponding PyObjects, used when finalizing JSExternalStrings PyObject *PythonExternalString::getPyString(const char16_t *chars) { - return charToPyObjectMap[chars]; + return ucs2ToPyObjectMap[chars]; +} + +PyObject *PythonExternalString::getPyString(const JS::Latin1Char *chars) +{ + return latin1ToPyObjectMap[chars]; } void PythonExternalString::finalize(char16_t *chars) const @@ -61,7 +67,15 @@ void PythonExternalString::finalize(char16_t *chars) const // We cannot call Py_DECREF here when shutting down as the thread state is gone. // Then, when shutting down, there is only on reference left, and we don't need // to free the object since the entire process memory is being released. - PyObject *object = charToPyObjectMap[chars]; + PyObject *object = ucs2ToPyObjectMap[chars]; + if (Py_REFCNT(object) > 1) { + Py_DECREF(object); + } +} + +void PythonExternalString::finalize(JS::Latin1Char *chars) const +{ + PyObject *object = latin1ToPyObjectMap[chars]; if (Py_REFCNT(object) > 1) { Py_DECREF(object); } @@ -69,7 +83,12 @@ void PythonExternalString::finalize(char16_t *chars) const size_t PythonExternalString::sizeOfBuffer(const char16_t *chars, mozilla::MallocSizeOf mallocSizeOf) const { - return PyUnicode_GetLength(charToPyObjectMap[chars]); + return PyUnicode_GetLength(ucs2ToPyObjectMap[chars]); +} + +size_t PythonExternalString::sizeOfBuffer(const JS::Latin1Char *chars, mozilla::MallocSizeOf mallocSizeOf) const +{ + return PyUnicode_GetLength(latin1ToPyObjectMap[chars]); } PythonExternalString PythonExternalStringCallbacks = {}; @@ -132,22 +151,16 @@ JS::Value jsTypeFactory(JSContext *cx, PyObject *object) { break; } case (PyUnicode_2BYTE_KIND): { - charToPyObjectMap[(char16_t *)PyUnicode_2BYTE_DATA(object)] = object; - JSString *str = JS_NewExternalString(cx, (char16_t *)PyUnicode_2BYTE_DATA(object), PyUnicode_GET_LENGTH(object), &PythonExternalStringCallbacks); + ucs2ToPyObjectMap[(char16_t *)PyUnicode_2BYTE_DATA(object)] = object; + JSString *str = JS_NewExternalUCString(cx, (char16_t *)PyUnicode_2BYTE_DATA(object), PyUnicode_GET_LENGTH(object), &PythonExternalStringCallbacks); returnType.setString(str); break; } case (PyUnicode_1BYTE_KIND): { - charToPyObjectMap[(char16_t *)PyUnicode_2BYTE_DATA(object)] = object; - JSString *str = JS_NewExternalString(cx, (char16_t *)PyUnicode_1BYTE_DATA(object), PyUnicode_GET_LENGTH(object), &PythonExternalStringCallbacks); - /* TODO (Caleb Aikens): this is a hack to set the JSString::LATIN1_CHARS_BIT, because there isnt an API for latin1 JSExternalStrings. - * Ideally we submit a patch to Spidermonkey to make this part of their API with the following signature: - * JS_NewExternalString(JSContext *cx, const char *chars, size_t length, const JSExternalStringCallbacks *callbacks) - */ - // FIXME: JSExternalString are all treated as two-byte strings when GCed - // see https://hg.mozilla.org/releases/mozilla-esr102/file/tip/js/src/vm/StringType-inl.h#l514 - // https://hg.mozilla.org/releases/mozilla-esr102/file/tip/js/src/vm/StringType.h#l1808 - *(std::atomic *)str |= 512; + latin1ToPyObjectMap[(JS::Latin1Char *)PyUnicode_1BYTE_DATA(object)] = object; + JSString *str = JS_NewExternalStringLatin1(cx, (JS::Latin1Char *)PyUnicode_1BYTE_DATA(object), PyUnicode_GET_LENGTH(object), &PythonExternalStringCallbacks); + // JSExternalString can now be properly treated as either one-byte or two-byte strings when GCed + // see https://hg.mozilla.org/releases/mozilla-esr128/file/tip/js/src/vm/StringType-inl.h#l785 returnType.setString(str); break; } From 42e3f535b6eecc0c94c1bb043be6d194202ca15d Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Thu, 20 Jun 2024 09:07:23 +0000 Subject: [PATCH 112/428] fix: forcibly enable FinalizationRegistry and iterator helpers Probably due to a bug in the build system, we could not use `JS::Prefs::setAtStartup_weakrefs(true);` or `JS::Prefs::setAtStartup_experimental_iterator_helpers(true);`: ``` undefined symbol: _ZN2JS5Prefs9weakrefs_E ``` Further more, the file `js/PrefsGenerated.h` does not get copied into the installation location of SpiderMonkey, but stays in `/js/src/_build/js/public/PrefsGenerated.h`. --- setup.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/setup.sh b/setup.sh index ee2147ce..3bc3f946 100755 --- a/setup.sh +++ b/setup.sh @@ -83,6 +83,8 @@ sed -i'' -e 's/bool Unbox/JS_PUBLIC_API bool Unbox/g' ./js/public/Class.h sed -i'' -e 's/bool js::Unbox/JS_PUBLIC_API bool js::Unbox/g' ./js/src/vm/JSObject.cpp # same here sed -i'' -e 's/shared_lib = self._pretty_path(libdef.output_path, backend_file)/shared_lib = libdef.lib_name/' ./python/mozbuild/mozbuild/backend/recursivemake.py sed -i'' -e 's/if version < Version(mac_sdk_min_version())/if False/' ./build/moz.configure/toolchain.configure # do not verify the macOS SDK version as the reqiuired version is not available on Github Actions runner +sed -i'' -e 's/return JS::GetWeakRefsEnabled() == JS::WeakRefSpecifier::Disabled/return false/' ./js/src/vm/GlobalObject.cpp # forcibly enable FinalizationRegistry +sed -i'' -e 's/return !IsIteratorHelpersEnabled()/return false/' ./js/src/vm/GlobalObject.cpp # forcibly enable iterator helpers cd js/src mkdir -p _build cd _build From ec75f13ef8418754df33c8df616c48cbad55f0ce Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Thu, 20 Jun 2024 09:58:06 +0000 Subject: [PATCH 113/428] fix: `JSErrorReport`'s `filename` property should now be a `JS::ConstUTF8CharsZ` instead of a pure `char*` after upgrading SpiderMonkey to mozilla-central tip --- src/setSpiderMonkeyException.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/setSpiderMonkeyException.cc b/src/setSpiderMonkeyException.cc index 6706b883..d380d87c 100644 --- a/src/setSpiderMonkeyException.cc +++ b/src/setSpiderMonkeyException.cc @@ -43,7 +43,7 @@ PyObject *getExceptionString(JSContext *cx, const JS::ExceptionStack &exceptionS std::string linebuf; // the offending JS line of code (can be empty) /* *INDENT-OFF* */ - outStrStream << "Error in file " << errorReport->filename.get() + outStrStream << "Error in file " << errorReport->filename.c_str() << ", on line " << errorReport->lineno << ", column " << errorReport->column.oneOriginValue() << ":\n"; /* *INDENT-ON* */ From 39ee6afd8b0851a954327be1ecc9be05d9a5511b Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Thu, 20 Jun 2024 10:02:48 +0000 Subject: [PATCH 114/428] WIP: bug in defining the debugger global object, disable pmdb for now --- python/pythonmonkey/lib/pmdb.py | 3 ++- src/modules/pythonmonkey/pythonmonkey.cc | 14 +++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/python/pythonmonkey/lib/pmdb.py b/python/pythonmonkey/lib/pmdb.py index 9f5ffcab..a8e20697 100644 --- a/python/pythonmonkey/lib/pmdb.py +++ b/python/pythonmonkey/lib/pmdb.py @@ -17,7 +17,8 @@ def debuggerInput(prompt: str): return "" -def enable(debuggerGlobalObject=pm.eval("debuggerGlobal")): +def enable(debuggerGlobalObject=pm.eval("void 0")): + return if debuggerGlobalObject._pmdbEnabled: return # already enabled, skipping diff --git a/src/modules/pythonmonkey/pythonmonkey.cc b/src/modules/pythonmonkey/pythonmonkey.cc index fb7cb5ca..816393b5 100644 --- a/src/modules/pythonmonkey/pythonmonkey.cc +++ b/src/modules/pythonmonkey/pythonmonkey.cc @@ -557,16 +557,16 @@ PyMODINIT_FUNC PyInit_pythonmonkey(void) return NULL; } - JS::RootedObject debuggerGlobal(GLOBAL_CX, JS_NewGlobalObject(GLOBAL_CX, &globalClass, nullptr, JS::FireOnNewGlobalHook, options)); - { - JSAutoRealm r(GLOBAL_CX, debuggerGlobal); - JS_DefineProperty(GLOBAL_CX, debuggerGlobal, "mainGlobal", *global, JSPROP_READONLY); - JS_DefineDebuggerObject(GLOBAL_CX, debuggerGlobal); - } + // JS::RootedObject debuggerGlobal(GLOBAL_CX, JS_NewGlobalObject(GLOBAL_CX, &globalClass, nullptr, JS::FireOnNewGlobalHook, options)); + // { + // JSAutoRealm r(GLOBAL_CX, debuggerGlobal); + // JS_DefineProperty(GLOBAL_CX, debuggerGlobal, "mainGlobal", *global, JSPROP_READONLY); + // JS_DefineDebuggerObject(GLOBAL_CX, debuggerGlobal); + // } autoRealm = new JSAutoRealm(GLOBAL_CX, *global); - JS_DefineProperty(GLOBAL_CX, *global, "debuggerGlobal", debuggerGlobal, JSPROP_READONLY); + // JS_DefineProperty(GLOBAL_CX, *global, "debuggerGlobal", debuggerGlobal, JSPROP_READONLY); // XXX: SpiderMonkey bug??? // In https://hg.mozilla.org/releases/mozilla-esr102/file/3b574e1/js/src/jit/CacheIR.cpp#l317, trying to use the callback returned by `js::GetDOMProxyShadowsCheck()` even it's unset (nullptr) From eb153ee6555e1cf0143ce8d612b9e8acb3851bd4 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 25 Jun 2024 15:32:45 +0000 Subject: [PATCH 115/428] fix: update the test suite to reflect the change that property access errors now says `TypeError: can\'t access property` --- tests/python/test_arrays.py | 3 ++- tests/python/test_event_loop.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/python/test_arrays.py b/tests/python/test_arrays.py index 8df49c03..c91b95e5 100644 --- a/tests/python/test_arrays.py +++ b/tests/python/test_arrays.py @@ -1098,7 +1098,8 @@ class Counter { assert (False) except Exception as e: assert str(type(e)) == "" - assert str(e).__contains__("TypeError: this is null") + assert "TypeError:" in str(e) + assert "this is null" in str(e) def test_forEach_too_few_args(): diff --git a/tests/python/test_event_loop.py b/tests/python/test_event_loop.py index 8eecd58c..27c3ba87 100644 --- a/tests/python/test_event_loop.py +++ b/tests/python/test_event_loop.py @@ -312,7 +312,7 @@ async def coro_to_throw1(): # # await pm.eval("Promise.resolve().then(()=>{ throw {a:1,toString(){return'anything'}} })") # not going through the conversion - with pytest.raises(pm.SpiderMonkeyError, match="on line 1, column 31:\nTypeError: undefined has no properties"): + with pytest.raises(pm.SpiderMonkeyError, match="on line 1, column 31:\nTypeError: can\'t access property \"prop\" of undefined"): await pm.eval("Promise.resolve().then(()=>{ (undefined).prop })") # TODO (Tom Tang): Modify this testcase once we support ES2020-style dynamic import From 67d017baf27e0a36090d093227b84a0e8dc6507a Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 25 Jun 2024 20:55:35 +0000 Subject: [PATCH 116/428] fix: `timers-force-exit.simple` to have a longer timeout because 2s is not enough for the teardown in debug mode --- tests/js/timers-force-exit.simple | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/js/timers-force-exit.simple b/tests/js/timers-force-exit.simple index 93e2eb79..a18f63b5 100644 --- a/tests/js/timers-force-exit.simple +++ b/tests/js/timers-force-exit.simple @@ -4,10 +4,10 @@ * @author Wes Garland, wes@distributive.network * @date July 2023 * - * timeout: 2 + * timeout: 4 */ setTimeout(()=>console.log('fired timer'), 500000); setTimeout(()=>console.error('should not have fired timer!'), 0); -console.log('about to exit even though timers are pending') -python.exit(0) +console.log('about to exit even though timers are pending'); +python.exit(0); From d2d9396fb2a2bd9c7529aaae0cbc43ebbb798ef6 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 25 Jun 2024 21:02:28 +0000 Subject: [PATCH 117/428] fix: `tests/js/commonjs-modules.bash` needs a much longer timeout if we build in debug mode --- tests/js/commonjs-modules.bash | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/js/commonjs-modules.bash b/tests/js/commonjs-modules.bash index abd6c411..0bc36f86 100755 --- a/tests/js/commonjs-modules.bash +++ b/tests/js/commonjs-modules.bash @@ -5,6 +5,8 @@ # suite causes this test to fail. # @author Wes Garland, wes@distributive.network # @date June 2023 +# +# timeout: 40 panic() { From 180303f94a761772b43aa987e4f9d43dc48ba2ae Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 25 Jun 2024 22:28:12 +0000 Subject: [PATCH 118/428] fix: pmdb's debugger global object now requires to be in a cross-compartment wrapper to use on the main global object --- python/pythonmonkey/lib/pmdb.py | 7 +++---- src/JSFunctionProxy.cc | 2 +- src/JobQueue.cc | 2 +- src/modules/pythonmonkey/pythonmonkey.cc | 21 +++++++++++++-------- 4 files changed, 18 insertions(+), 14 deletions(-) diff --git a/python/pythonmonkey/lib/pmdb.py b/python/pythonmonkey/lib/pmdb.py index a8e20697..f7afdc30 100644 --- a/python/pythonmonkey/lib/pmdb.py +++ b/python/pythonmonkey/lib/pmdb.py @@ -17,13 +17,12 @@ def debuggerInput(prompt: str): return "" -def enable(debuggerGlobalObject=pm.eval("void 0")): - return +def enable(debuggerGlobalObject=pm.eval("debuggerGlobal")): if debuggerGlobalObject._pmdbEnabled: return # already enabled, skipping debuggerGlobalObject._pmdbEnabled = True - debuggerGlobalObject.eval("""(debuggerInput, _pythonPrint, _pythonExit) => { + pm.eval("debuggerGlobal.eval")("""(mainGlobal, debuggerInput, _pythonPrint, _pythonExit) => { const dbg = new Debugger() const mainDebuggee = dbg.addDebuggee(mainGlobal) dbg.uncaughtExceptionHook = (e) => { @@ -178,4 +177,4 @@ def enable(debuggerGlobalObject=pm.eval("void 0")): // Enter debugger on `debugger;` statement dbg.onDebuggerStatement = (frame) => enterDebuggerLoop(frame) - }""")(debuggerInput, print, lambda status: exit(int(status))) + }""")(pm.globalThis, debuggerInput, print, lambda status: exit(int(status))) diff --git a/src/JSFunctionProxy.cc b/src/JSFunctionProxy.cc index d545f739..99a32552 100644 --- a/src/JSFunctionProxy.cc +++ b/src/JSFunctionProxy.cc @@ -36,7 +36,7 @@ PyObject *JSFunctionProxyMethodDefinitions::JSFunctionProxy_call(PyObject *self, JSContext *cx = GLOBAL_CX; JS::RootedValue jsFunc(GLOBAL_CX, JS::ObjectValue(**((JSFunctionProxy *)self)->jsFunc)); JSObject *jsFuncObj = jsFunc.toObjectOrNull(); - JS::RootedObject thisObj(GLOBAL_CX, JS::GetNonCCWObjectGlobal(jsFuncObj)); // if jsFunc is not bound, assume `this` is `globalThis` + JS::RootedObject thisObj(GLOBAL_CX, JS::CurrentGlobalOrNull(GLOBAL_CX)); // if jsFunc is not bound, assume `this` is `globalThis` JS::RootedVector jsArgsVector(cx); Py_ssize_t nargs = PyTuple_Size(args); diff --git a/src/JobQueue.cc b/src/JobQueue.cc index f00943dd..0ee33b39 100644 --- a/src/JobQueue.cc +++ b/src/JobQueue.cc @@ -59,7 +59,7 @@ void JobQueue::runJobs(JSContext *cx) { bool JobQueue::empty() const { // TODO (Tom Tang): implement using `get_running_loop` and getting job count on loop??? - throw std::logic_error("JobQueue::empty is not implemented\n"); + return true; // see https://hg.mozilla.org/releases/mozilla-esr128/file/tip/js/src/builtin/Promise.cpp#l6946 } bool JobQueue::isDrainingStopped() const { diff --git a/src/modules/pythonmonkey/pythonmonkey.cc b/src/modules/pythonmonkey/pythonmonkey.cc index 816393b5..15e298e8 100644 --- a/src/modules/pythonmonkey/pythonmonkey.cc +++ b/src/modules/pythonmonkey/pythonmonkey.cc @@ -557,17 +557,22 @@ PyMODINIT_FUNC PyInit_pythonmonkey(void) return NULL; } - // JS::RootedObject debuggerGlobal(GLOBAL_CX, JS_NewGlobalObject(GLOBAL_CX, &globalClass, nullptr, JS::FireOnNewGlobalHook, options)); - // { - // JSAutoRealm r(GLOBAL_CX, debuggerGlobal); - // JS_DefineProperty(GLOBAL_CX, debuggerGlobal, "mainGlobal", *global, JSPROP_READONLY); - // JS_DefineDebuggerObject(GLOBAL_CX, debuggerGlobal); - // } + JS::RootedObject debuggerGlobal(GLOBAL_CX, JS_NewGlobalObject(GLOBAL_CX, &globalClass, nullptr, JS::FireOnNewGlobalHook, options)); + { + JSAutoRealm r(GLOBAL_CX, debuggerGlobal); + JS_DefineDebuggerObject(GLOBAL_CX, debuggerGlobal); + } + { + JSAutoRealm r(GLOBAL_CX, *global); + JS::Rooted desc(GLOBAL_CX, JS::PropertyDescriptor::Data( + JS::ObjectValue(*debuggerGlobal) + )); + JS_WrapPropertyDescriptor(GLOBAL_CX, &desc); + JS_DefineUCProperty(GLOBAL_CX, *global, u"debuggerGlobal", 14, desc); + } autoRealm = new JSAutoRealm(GLOBAL_CX, *global); - // JS_DefineProperty(GLOBAL_CX, *global, "debuggerGlobal", debuggerGlobal, JSPROP_READONLY); - // XXX: SpiderMonkey bug??? // In https://hg.mozilla.org/releases/mozilla-esr102/file/3b574e1/js/src/jit/CacheIR.cpp#l317, trying to use the callback returned by `js::GetDOMProxyShadowsCheck()` even it's unset (nullptr) // Temporarily solved by explicitly setting the `domProxyShadowsCheck` callback here From ec74f8baab44b8603757dfed360ff7de9354de1c Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 25 Jun 2024 22:55:36 +0000 Subject: [PATCH 119/428] fix: `JS_Utf8BufferIsCompilableUnit` would still generate exception for invalid inputs --- src/modules/pythonmonkey/pythonmonkey.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/modules/pythonmonkey/pythonmonkey.cc b/src/modules/pythonmonkey/pythonmonkey.cc index 15e298e8..327fc8b5 100644 --- a/src/modules/pythonmonkey/pythonmonkey.cc +++ b/src/modules/pythonmonkey/pythonmonkey.cc @@ -485,10 +485,12 @@ static PyObject *isCompilableUnit(PyObject *self, PyObject *args) { const char *bufferUtf8 = PyUnicode_AsUTF8(item); - if (JS_Utf8BufferIsCompilableUnit(GLOBAL_CX, *global, bufferUtf8, strlen(bufferUtf8))) + if (JS_Utf8BufferIsCompilableUnit(GLOBAL_CX, *global, bufferUtf8, strlen(bufferUtf8))) { Py_RETURN_TRUE; - else + } else { + JS_ClearPendingException(GLOBAL_CX); // JS_Utf8BufferIsCompilableUnit would still generate exception for invalid inputs Py_RETURN_FALSE; + } } PyMethodDef PythonMonkeyMethods[] = { From 3883b623bbc54a5fbd9888cc030c9360e2bf67f2 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Fri, 28 Jun 2024 15:15:25 -0400 Subject: [PATCH 120/428] chore: fix uncrustify build on Windows --- .gitignore | 1 + setup.sh | 12 +++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 00be16f6..30b94f8a 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ _spidermonkey_install uncrustify-*.tar.gz uncrustify-*/ uncrustify +uncrustify.exe *.uncrustify __pycache__/* dist diff --git a/setup.sh b/setup.sh index fd553fdb..6e316a11 100755 --- a/setup.sh +++ b/setup.sh @@ -58,9 +58,15 @@ echo "Building uncrustify" cd uncrustify-source mkdir -p build cd build -cmake ../ -make -j4 -cp uncrustify ../../uncrustify +if [[ "$OSTYPE" == "msys"* ]]; then # Windows + cmake ../ -T ClangCL + cmake --build . -j$CPUS --config Release + cp Release/uncrustify.exe ../../uncrustify.exe +else + cmake ../ + make -j$CPUS + cp uncrustify ../../uncrustify +fi cd ../.. echo "Done building uncrustify" From 46c148a970093e36115ba45e20c49359ce7f37d6 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Fri, 28 Jun 2024 19:39:16 +0000 Subject: [PATCH 121/428] chore: re-enable Windows builds This reverts commit 04d028b0e0600d7b0826f325029da5884648b577. --- .github/workflows/test-and-publish.yaml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 52b20016..b862941c 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -88,7 +88,6 @@ jobs: if: ${{ steps.cache-spidermonkey.outputs.cache-hit != 'true' }} run: ./setup.sh build-spidermonkey-win: - if: false runs-on: windows-2019 steps: - uses: actions/checkout@v4 @@ -123,12 +122,12 @@ jobs: USE_MINTTY: 0 run: /c/mozilla-build/start-shell.bat -use-full-path -here ./setup.sh build-and-test: - needs: [build-spidermonkey-unix] + needs: [build-spidermonkey-unix, build-spidermonkey-win] strategy: fail-fast: false matrix: # The lowest supported version is Ubuntu 20.04 + Python 3.8 or macOS 12 + Python 3.9 - os: [ 'ubuntu-20.04', 'macos-12', 'macos-14' ] + os: [ 'ubuntu-20.04', 'macos-12', 'macos-14', 'windows-2019' ] python_version: [ '3.8', '3.9', '3.10', '3.11', '3.12' ] exclude: # actions/setup-python: The version '3.8'/'3.9' with architecture 'arm64' was not found for macOS. From 82bf020cfceb64aacf2d7d8b357726240794ba5e Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 2 Jul 2024 20:36:04 +0000 Subject: [PATCH 122/428] fix: in SpiderMonkey's `js/src/configure` script, the `--without-system-zlib` option is not available on Windows --- setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.sh b/setup.sh index 26aae672..7a61261b 100755 --- a/setup.sh +++ b/setup.sh @@ -98,7 +98,7 @@ mkdir -p ../../../../_spidermonkey_install/ ../configure \ --prefix=$(realpath $PWD/../../../../_spidermonkey_install) \ --with-intl-api \ - --without-system-zlib \ + $(if [[ "$OSTYPE" != "msys"* ]]; then echo "--without-system-zlib"; fi) \ --disable-debug-symbols \ --disable-jemalloc \ --disable-tests \ From ddfc4243f27aef5cc1f3ed2f8d0beefacc3e1d35 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 2 Jul 2024 21:03:00 +0000 Subject: [PATCH 123/428] chore(CI): switch to the Windows 2022 runner to build SpiderMonkey The current SpiderMonkey requires Visual Studio 2022 or newer. The Windows 2019 runner only has Visual Studio Enterprise 2019 installed. See https://github.com/actions/runner-images/blob/main/images/windows/Windows2019-Readme.md#visual-studio-enterprise-2019 --- .github/workflows/test-and-publish.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index b862941c..0cc62acd 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -88,7 +88,7 @@ jobs: if: ${{ steps.cache-spidermonkey.outputs.cache-hit != 'true' }} run: ./setup.sh build-spidermonkey-win: - runs-on: windows-2019 + runs-on: windows-2022 steps: - uses: actions/checkout@v4 - name: Read the mozilla-central commit hash to be used From 6168acb23549fc76712f9853bebde0e38b7bc83d Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 2 Jul 2024 21:10:05 +0000 Subject: [PATCH 124/428] chore: fix uncrustify build on Windows --- setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.sh b/setup.sh index 7a61261b..a88d77b8 100755 --- a/setup.sh +++ b/setup.sh @@ -60,7 +60,7 @@ cd uncrustify-source mkdir -p build cd build if [[ "$OSTYPE" == "msys"* ]]; then # Windows - cmake ../ -T ClangCL + cmake ../ cmake --build . -j$CPUS --config Release cp Release/uncrustify.exe ../../uncrustify.exe else From 455679907f3f8b86e17e9fe7734d307f93ae117d Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 2 Jul 2024 21:36:35 +0000 Subject: [PATCH 125/428] fix: crash in Debug Build of SpiderMonkey --- setup.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/setup.sh b/setup.sh index a88d77b8..a4cb7292 100755 --- a/setup.sh +++ b/setup.sh @@ -91,6 +91,8 @@ sed -i'' -e 's/shared_lib = self._pretty_path(libdef.output_path, backend_file)/ sed -i'' -e 's/if version < Version(mac_sdk_min_version())/if False/' ./build/moz.configure/toolchain.configure # do not verify the macOS SDK version as the reqiuired version is not available on Github Actions runner sed -i'' -e 's/return JS::GetWeakRefsEnabled() == JS::WeakRefSpecifier::Disabled/return false/' ./js/src/vm/GlobalObject.cpp # forcibly enable FinalizationRegistry sed -i'' -e 's/return !IsIteratorHelpersEnabled()/return false/' ./js/src/vm/GlobalObject.cpp # forcibly enable iterator helpers +sed -i'' -e '/MOZ_CRASH_UNSAFE_PRINTF/,/__PRETTY_FUNCTION__);/d' ./mfbt/LinkedList.h # would crash in Debug Build: in `~LinkedList()` it should have removed all this list's elements before the list's destruction +sed -i'' -e '/MOZ_ASSERT(stackRootPtr == nullptr);/d' ./js/src/vm/JSContext.cpp # would assert false in Debug Build since we extensively use `new JS::Rooted` cd js/src mkdir -p _build cd _build From 3f78041f3397e89f30069a8af64c206e521b2adc Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 2 Jul 2024 21:41:45 +0000 Subject: [PATCH 126/428] docs(CI): explain why we need Windows 2022 runner to build SpiderMonkey --- .github/workflows/test-and-publish.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 0cc62acd..985d1167 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -89,6 +89,8 @@ jobs: run: ./setup.sh build-spidermonkey-win: runs-on: windows-2022 + # SpiderMonkey requires Visual Studio 2022 or newer. + # The Windows 2019 runner only has Visual Studio Enterprise 2019 installed. steps: - uses: actions/checkout@v4 - name: Read the mozilla-central commit hash to be used From 48bda0a954a7afd20276ba9653614275a28a015b Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 2 Jul 2024 21:48:36 +0000 Subject: [PATCH 127/428] chore(CI): use the Windows 2022 runner entirely --- .github/workflows/test-and-publish.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 985d1167..9da1b68f 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -18,7 +18,7 @@ on: - 'ubuntu-20.04' - 'macos-12' - 'macos-14' - - 'windows-2019' + - 'windows-2022' debug_enabled_python: type: choice description: Choose a Python version to run the build with SSH debugging on @@ -129,7 +129,7 @@ jobs: fail-fast: false matrix: # The lowest supported version is Ubuntu 20.04 + Python 3.8 or macOS 12 + Python 3.9 - os: [ 'ubuntu-20.04', 'macos-12', 'macos-14', 'windows-2019' ] + os: [ 'ubuntu-20.04', 'macos-12', 'macos-14', 'windows-2022' ] python_version: [ '3.8', '3.9', '3.10', '3.11', '3.12' ] exclude: # actions/setup-python: The version '3.8'/'3.9' with architecture 'arm64' was not found for macOS. @@ -211,7 +211,7 @@ jobs: name: wheel-${{ github.run_id }}-${{ github.sha }} path: ./dist/ - name: Set cores to get stored in /cores - if: ${{ matrix.os != 'windows-2019' }} + if: ${{ matrix.os != 'windows-2022' }} # TODO (Caleb Aikens) figure out how to get Windows core dumps run: | sudo mkdir -p /cores @@ -246,7 +246,7 @@ jobs: credentials: "admin:admin" - name: Upload core dumps as CI artifacts uses: actions/upload-artifact@v3 - if: ${{ matrix.os != 'windows-2019' && failure() }} + if: ${{ matrix.os != 'windows-2022' && failure() }} # TODO (Caleb Aikens) figure out how to get Windows core dumps with: name: cores-${{ matrix.os }}-${{ matrix.python_version }} From da4f0da5b9992c498e69ea01cb0b996e0d6838e6 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 2 Jul 2024 21:53:49 +0000 Subject: [PATCH 128/428] The `JS_Utf8BufferIsCompilableUnit` issue got fixed within 24 hours after reporting it in the firefox Matrix chat, updating SpiderMonkey to mozilla-central tip See https://bugzilla.mozilla.org/show_bug.cgi?id=1904747 --- mozcentral.version | 2 +- src/modules/pythonmonkey/pythonmonkey.cc | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/mozcentral.version b/mozcentral.version index 7b2cc323..02961814 100644 --- a/mozcentral.version +++ b/mozcentral.version @@ -1 +1 @@ -74b39df74a4a38e44f4b3783a5c4e4e8980ccf6f \ No newline at end of file +d25c9bdacb64ae50779dc91f5919ca0189ad6c36 \ No newline at end of file diff --git a/src/modules/pythonmonkey/pythonmonkey.cc b/src/modules/pythonmonkey/pythonmonkey.cc index 327fc8b5..c7b9455a 100644 --- a/src/modules/pythonmonkey/pythonmonkey.cc +++ b/src/modules/pythonmonkey/pythonmonkey.cc @@ -488,7 +488,6 @@ static PyObject *isCompilableUnit(PyObject *self, PyObject *args) { if (JS_Utf8BufferIsCompilableUnit(GLOBAL_CX, *global, bufferUtf8, strlen(bufferUtf8))) { Py_RETURN_TRUE; } else { - JS_ClearPendingException(GLOBAL_CX); // JS_Utf8BufferIsCompilableUnit would still generate exception for invalid inputs Py_RETURN_FALSE; } } From a7b92e896ff6b077f161b9ae79a9f5e55f4434b5 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Thu, 4 Jul 2024 20:40:32 +0000 Subject: [PATCH 129/428] chore(CI): create a CI action that automatically create pull request when mozilla-central is updated --- .../workflows/update-mozcentral-version.yaml | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 .github/workflows/update-mozcentral-version.yaml diff --git a/.github/workflows/update-mozcentral-version.yaml b/.github/workflows/update-mozcentral-version.yaml new file mode 100644 index 00000000..d869a24e --- /dev/null +++ b/.github/workflows/update-mozcentral-version.yaml @@ -0,0 +1,39 @@ +name: 'Create pull requests to update mozilla-central version to the latest' + +on: + schedule: + - cron: "00 14 * * 1" # run every Monday at 14:00 UTC (10:00 Eastern Daylight Time) + workflow_call: + workflow_dispatch: # or you can run it manually + +defaults: + run: + shell: bash + +jobs: + update: + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v4 + - name: Check Version + # Check the latest changes on mozilla-central via the Mercurial pushlog HTTP API + # See https://mozilla-version-control-tools.readthedocs.io/en/latest/hgmo/pushlog.html#hgweb-commands + run: | + COMMIT_HASH=$( + curl -s "https://hg.mozilla.org/mozilla-central/json-pushes?tipsonly=1&version=2" |\ + jq --join-output '(.lastpushid | tostring) as $pushid | empty, .pushes[$pushid].changesets[0]' + ) + echo "MOZCENTRAL_VERSION=$COMMIT_HASH" >> $GITHUB_ENV + - name: Update `mozcentral.version` File + run: echo $MOZCENTRAL_VERSION > mozcentral.version + - name: Create Pull Request + uses: peter-evans/create-pull-request@v6 + with: + add-paths: mozcentral.version + commit-message: | + chore(deps): upgrade SpiderMonkey to `${{ env.MOZCENTRAL_VERSION }}` + branch: chore/upgrade-spidermonkey-to-${{ env.MOZCENTRAL_VERSION }} + title: Upgrade SpiderMonkey to mozilla-central commit `${{ env.MOZCENTRAL_VERSION }}` + body: | + Changeset: https://hg.mozilla.org/mozilla-central/rev/${{ env.MOZCENTRAL_VERSION }} + labels: dependencies From 9cfb8247c96ff927bf0ae4d4b97d7216712dfd90 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 9 Jul 2024 06:07:51 +0000 Subject: [PATCH 130/428] feat(XHR): print debug logs with a unique connection id to identify each XHR connection --- .../XMLHttpRequest-internal.d.ts | 3 ++ .../XMLHttpRequest-internal.py | 3 +- .../builtin_modules/XMLHttpRequest.js | 42 +++++++++++++------ 3 files changed, 34 insertions(+), 14 deletions(-) diff --git a/python/pythonmonkey/builtin_modules/XMLHttpRequest-internal.d.ts b/python/pythonmonkey/builtin_modules/XMLHttpRequest-internal.d.ts index bdb159b0..2d8c4495 100644 --- a/python/pythonmonkey/builtin_modules/XMLHttpRequest-internal.d.ts +++ b/python/pythonmonkey/builtin_modules/XMLHttpRequest-internal.d.ts @@ -46,6 +46,9 @@ export declare function request( // callbacks for known exceptions onTimeoutError: (err: Error) => void, onNetworkError: (err: Error) => void, + // the debug logging function + /** See `pm.bootstrap.require("debug")` */ + debug: (selector: string) => ((...args: string[]) => void), ): Promise; /** diff --git a/python/pythonmonkey/builtin_modules/XMLHttpRequest-internal.py b/python/pythonmonkey/builtin_modules/XMLHttpRequest-internal.py index e3ea1824..ca716d88 100644 --- a/python/pythonmonkey/builtin_modules/XMLHttpRequest-internal.py +++ b/python/pythonmonkey/builtin_modules/XMLHttpRequest-internal.py @@ -44,9 +44,10 @@ async def request( # callbacks for known exceptions onTimeoutError: Callable[[asyncio.TimeoutError], None], onNetworkError: Callable[[aiohttp.ClientError], None], + # the debug logging function, see `pm.bootstrap.require("debug")` + debug: Callable[[str], Callable[..., None]], / ): - debug = pm.bootstrap.require("debug") # to support HTTP-Keep-Alive global keepAliveConnector diff --git a/python/pythonmonkey/builtin_modules/XMLHttpRequest.js b/python/pythonmonkey/builtin_modules/XMLHttpRequest.js index 6db9bc04..a3cdf133 100644 --- a/python/pythonmonkey/builtin_modules/XMLHttpRequest.js +++ b/python/pythonmonkey/builtin_modules/XMLHttpRequest.js @@ -20,7 +20,7 @@ const debug = globalThis.python.eval('__import__("pythonmonkey").bootstrap.requi * @param {any} what The thing to truncate; must have a slice method and index property. * Works with string, array, typedarray, etc. * @param {number} maxlen The maximum length for truncation - * @param {boolean} coerce Not false = coerce to printable character codes + * @param {boolean=} coerce Not false = coerce to printable character codes * @returns {string} */ function trunc(what, maxlen, coerce) @@ -104,6 +104,21 @@ class XMLHttpRequest extends XMLHttpRequestEventTarget /** @type {EventListenerFn} */ onreadystatechange = null; + // + // debugging + // + /** The unique connection id to identify each XHR connection when debugging */ + #connectionId = Math.random().toString(16).slice(2, 9); // random 7-character hex string + + /** + * Wrapper to print debug logs with connection id information + * @param {string} selector + */ + #debug(selector) + { + return (...args) => debug(selector)(`Conn<${this.#connectionId}>:`, ...args); + } + // // states // @@ -142,7 +157,7 @@ class XMLHttpRequest extends XMLHttpRequestEventTarget */ open(method, url, async = true, username = null, password = null) { - debug('xhr:open')('open start, method=' + method); + this.#debug('xhr:open')('open start, method=' + method); // Normalize the method. // @ts-expect-error method = method.toString().toUpperCase(); @@ -156,7 +171,7 @@ class XMLHttpRequest extends XMLHttpRequestEventTarget parsedURL.username = username; if (password) parsedURL.password = password; - debug('xhr:open')('url is ' + parsedURL.href); + this.#debug('xhr:open')('url is ' + parsedURL.href); // step 11 this.#sendFlag = false; @@ -176,7 +191,7 @@ class XMLHttpRequest extends XMLHttpRequestEventTarget this.#state = XMLHttpRequest.OPENED; this.dispatchEvent(new Event('readystatechange')); } - debug('xhr:open')('finished open, state is ' + this.#state); + this.#debug('xhr:open')('finished open, state is ' + this.#state); } /** @@ -186,7 +201,7 @@ class XMLHttpRequest extends XMLHttpRequestEventTarget */ setRequestHeader(name, value) { - debug('xhr:headers')(`set header ${name}=${value}`); + this.#debug('xhr:headers')(`set header ${name}=${value}`); if (this.#state !== XMLHttpRequest.OPENED) throw new DOMException('setRequestHeader can only be called when state is OPEN', 'InvalidStateError'); if (this.#sendFlag) @@ -252,7 +267,7 @@ class XMLHttpRequest extends XMLHttpRequestEventTarget */ send(body = null) { - debug('xhr:send')(`sending; body length=${body?.length}`); + this.#debug('xhr:send')(`sending; body length=${body?.length}`); if (this.#state !== XMLHttpRequest.OPENED) // step 1 throw new DOMException('connection must be opened before send() is called', 'InvalidStateError'); if (this.#sendFlag) // step 2 @@ -285,7 +300,7 @@ class XMLHttpRequest extends XMLHttpRequestEventTarget if (!originalAuthorContentType && extractedContentType) this.#requestHeaders['content-type'] = extractedContentType; } - debug('xhr:send')(`content-type=${this.#requestHeaders['content-type']}`); + this.#debug('xhr:send')(`content-type=${this.#requestHeaders['content-type']}`); // step 5 if (this.#uploadObject._hasAnyListeners()) @@ -310,7 +325,7 @@ class XMLHttpRequest extends XMLHttpRequestEventTarget */ #sendAsync() { - debug('xhr:send')('sending in async mode'); + this.#debug('xhr:send')('sending in async mode'); this.dispatchEvent(new ProgressEvent('loadstart', { loaded:0, total:0 })); // step 11.1 let requestBodyTransmitted = 0; // step 11.2 @@ -343,7 +358,7 @@ class XMLHttpRequest extends XMLHttpRequestEventTarget let responseLength = 0; const processResponse = (response) => { - debug('xhr:response')(`response headers ----\n${response.getAllResponseHeaders()}`); + this.#debug('xhr:response')(`response headers ----\n${response.getAllResponseHeaders()}`); this.#response = response; // step 11.9.1 this.#state = XMLHttpRequest.HEADERS_RECEIVED; // step 11.9.4 this.dispatchEvent(new Event('readystatechange')); // step 11.9.5 @@ -354,7 +369,7 @@ class XMLHttpRequest extends XMLHttpRequestEventTarget const processBodyChunk = (/** @type {Uint8Array} */ bytes) => { - debug('xhr:response')(`recv chunk, ${bytes.length} bytes (${trunc(bytes, 100)})`); + this.#debug('xhr:response')(`recv chunk, ${bytes.length} bytes (${trunc(bytes, 100)})`); this.#receivedBytes.push(bytes); if (this.#state === XMLHttpRequest.HEADERS_RECEIVED) this.#state = XMLHttpRequest.LOADING; @@ -367,7 +382,7 @@ class XMLHttpRequest extends XMLHttpRequestEventTarget */ const processEndOfBody = () => { - debug('xhr:response')(`end of body, received ${this.#receivedLength} bytes`); + this.#debug('xhr:response')(`end of body, received ${this.#receivedLength} bytes`); const transmitted = this.#receivedLength; // step 3 const length = responseLength || 0; // step 4 @@ -380,8 +395,8 @@ class XMLHttpRequest extends XMLHttpRequestEventTarget this.dispatchEvent(new ProgressEvent(eventType, { loaded:transmitted, total:length })); }; - debug('xhr:send')(`${this.#requestMethod} ${this.#requestURL.href}`); - debug('xhr:headers')('headers=' + Object.entries(this.#requestHeaders)); + this.#debug('xhr:send')(`${this.#requestMethod} ${this.#requestURL.href}`); + this.#debug('xhr:headers')('headers=' + Object.entries(this.#requestHeaders)); // send() step 6 request( @@ -397,6 +412,7 @@ class XMLHttpRequest extends XMLHttpRequestEventTarget processEndOfBody, () => (this.#timedOutFlag = true), // onTimeoutError () => (this.#response = null /* network error */), // onNetworkError + this.#debug.bind(this), ).catch((e) => this.#handleErrors(e)); } From d6639cd8927a4bf19ef1081401e305b9191b10ca Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 9 Jul 2024 06:45:58 +0000 Subject: [PATCH 131/428] feat(XHR): print the request body contents in debug logs --- python/pythonmonkey/builtin_modules/XMLHttpRequest.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/pythonmonkey/builtin_modules/XMLHttpRequest.js b/python/pythonmonkey/builtin_modules/XMLHttpRequest.js index a3cdf133..26de00c1 100644 --- a/python/pythonmonkey/builtin_modules/XMLHttpRequest.js +++ b/python/pythonmonkey/builtin_modules/XMLHttpRequest.js @@ -267,7 +267,7 @@ class XMLHttpRequest extends XMLHttpRequestEventTarget */ send(body = null) { - this.#debug('xhr:send')(`sending; body length=${body?.length}`); + this.#debug('xhr:send')(`sending; body length=${body?.length} «${body ? trunc(body, 100) : ''}»`); if (this.#state !== XMLHttpRequest.OPENED) // step 1 throw new DOMException('connection must be opened before send() is called', 'InvalidStateError'); if (this.#sendFlag) // step 2 @@ -369,7 +369,7 @@ class XMLHttpRequest extends XMLHttpRequestEventTarget const processBodyChunk = (/** @type {Uint8Array} */ bytes) => { - this.#debug('xhr:response')(`recv chunk, ${bytes.length} bytes (${trunc(bytes, 100)})`); + this.#debug('xhr:response')(`recv chunk, ${bytes.length} bytes «${trunc(bytes, 100)}»`); this.#receivedBytes.push(bytes); if (this.#state === XMLHttpRequest.HEADERS_RECEIVED) this.#state = XMLHttpRequest.LOADING; From 1c09b2b964be779cb1992930f9ff70639a9aac0a Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 9 Jul 2024 08:10:51 +0000 Subject: [PATCH 132/428] feat(XHR): add `_requestMetadata` accessor to allow others to inspect the internal properties --- .../pythonmonkey/builtin_modules/XMLHttpRequest.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/python/pythonmonkey/builtin_modules/XMLHttpRequest.js b/python/pythonmonkey/builtin_modules/XMLHttpRequest.js index 26de00c1..3cbacfc1 100644 --- a/python/pythonmonkey/builtin_modules/XMLHttpRequest.js +++ b/python/pythonmonkey/builtin_modules/XMLHttpRequest.js @@ -119,6 +119,19 @@ class XMLHttpRequest extends XMLHttpRequestEventTarget return (...args) => debug(selector)(`Conn<${this.#connectionId}>:`, ...args); } + /** + * Allowing others to inspect the internal properties + */ + get _requestMetadata() + { + return { + method: this.#requestMethod, + url: this.#requestURL.toString(), + headers: this.#requestHeaders, + body: this.#requestBody, + }; + } + // // states // From 69ed8c0a1a094d25cdf7a0cc2a43702bc682fe46 Mon Sep 17 00:00:00 2001 From: philippedistributive <151072087+philippedistributive@users.noreply.github.com> Date: Tue, 9 Jul 2024 10:51:54 -0400 Subject: [PATCH 133/428] Update include/JobQueue.hh --- include/JobQueue.hh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/JobQueue.hh b/include/JobQueue.hh index fba3c782..36a6d810 100644 --- a/include/JobQueue.hh +++ b/include/JobQueue.hh @@ -79,7 +79,7 @@ void runJobs(JSContext *cx) override; bool empty() const override; /** - * @return true if the job queue stops draining, which results in `empty()` being false after `runJobs()`. + * @return true if the job queue stopped draining, which results in `empty()` being false after `runJobs()`. */ bool isDrainingStopped() const override; From 76cccdffe41fa8823e22b222f05b451ae7d76a65 Mon Sep 17 00:00:00 2001 From: philippedistributive <151072087+philippedistributive@users.noreply.github.com> Date: Tue, 9 Jul 2024 10:54:28 -0400 Subject: [PATCH 134/428] Update setup.sh --- setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.sh b/setup.sh index a4cb7292..f647ee84 100755 --- a/setup.sh +++ b/setup.sh @@ -88,7 +88,7 @@ sed -i'' -e 's/"install-name-tool"/"install_name_tool"/' ./moz.configure # `inst sed -i'' -e 's/bool Unbox/JS_PUBLIC_API bool Unbox/g' ./js/public/Class.h # need to manually add JS_PUBLIC_API to js::Unbox until it gets fixed in Spidermonkey sed -i'' -e 's/bool js::Unbox/JS_PUBLIC_API bool js::Unbox/g' ./js/src/vm/JSObject.cpp # same here sed -i'' -e 's/shared_lib = self._pretty_path(libdef.output_path, backend_file)/shared_lib = libdef.lib_name/' ./python/mozbuild/mozbuild/backend/recursivemake.py -sed -i'' -e 's/if version < Version(mac_sdk_min_version())/if False/' ./build/moz.configure/toolchain.configure # do not verify the macOS SDK version as the reqiuired version is not available on Github Actions runner +sed -i'' -e 's/if version < Version(mac_sdk_min_version())/if False/' ./build/moz.configure/toolchain.configure # do not verify the macOS SDK version as the required version is not available on Github Actions runner sed -i'' -e 's/return JS::GetWeakRefsEnabled() == JS::WeakRefSpecifier::Disabled/return false/' ./js/src/vm/GlobalObject.cpp # forcibly enable FinalizationRegistry sed -i'' -e 's/return !IsIteratorHelpersEnabled()/return false/' ./js/src/vm/GlobalObject.cpp # forcibly enable iterator helpers sed -i'' -e '/MOZ_CRASH_UNSAFE_PRINTF/,/__PRETTY_FUNCTION__);/d' ./mfbt/LinkedList.h # would crash in Debug Build: in `~LinkedList()` it should have removed all this list's elements before the list's destruction From 7a398bfb8881b8bc05282ca8b4cb26680af11e61 Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Tue, 9 Jul 2024 13:50:00 -0400 Subject: [PATCH 135/428] python3-distutils is not needed and a problem on ubuntu-24_04 --- setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.sh b/setup.sh index 6e316a11..98887e99 100755 --- a/setup.sh +++ b/setup.sh @@ -19,7 +19,7 @@ if [[ "$OSTYPE" == "linux-gnu"* ]]; then # Linux fi $SUDO apt-get update --yes $SUDO apt-get install --yes cmake graphviz llvm clang pkg-config m4 \ - wget curl python3-distutils python3-dev + wget curl python3-dev # Install Doxygen # the newest version in Ubuntu 20.04 repository is 1.8.17, but we need Doxygen 1.9 series wget -c -q https://www.doxygen.nl/files/doxygen-1.9.7.linux.bin.tar.gz From eebcb6782315c8cb2e5e1777fce09fac24aac996 Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Tue, 9 Jul 2024 14:10:35 -0400 Subject: [PATCH 136/428] added ubuntu-24.04 to CI --- .github/workflows/test-and-publish.yaml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 99383de8..ffda6cd2 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -16,6 +16,7 @@ on: options: - '' - 'ubuntu-20.04' + - 'ubuntu-24.04' - 'macos-12' - 'macos-14' - 'windows-2019' @@ -60,7 +61,7 @@ jobs: fail-fast: false matrix: # Use Ubuntu 20.04 / macOS 13 x86_64 / macOS 14 arm64 + Python 3.10 to build SpiderMonkey - os: [ 'ubuntu-20.04', 'macos-13', 'macos-14' ] # macOS 14 runner exclusively runs on M1 hardwares + os: [ 'ubuntu-20.04','ubuntu-24.04','macos-13', 'macos-14' ] # macOS 14 runner exclusively runs on M1 hardwares # see https://github.blog/changelog/2024-01-30-github-actions-macos-14-sonoma-is-now-available python_version: [ '3.10' ] runs-on: ${{ matrix.os }} @@ -123,7 +124,7 @@ jobs: fail-fast: false matrix: # The lowest supported version is Ubuntu 20.04 + Python 3.8 or macOS 12 + Python 3.9 - os: [ 'ubuntu-20.04', 'macos-12', 'macos-14', 'windows-2019' ] + os: [ 'ubuntu-20.04', 'ubuntu-24.04', 'macos-12', 'macos-14', 'windows-2019' ] python_version: [ '3.8', '3.9', '3.10', '3.11', '3.12' ] exclude: # actions/setup-python: The version '3.8'/'3.9' with architecture 'arm64' was not found for macOS. @@ -162,7 +163,7 @@ jobs: poetry install --no-root --only=dev echo "Installed Dependencies" - name: Build Docs # only build docs once - if: ${{ matrix.os == 'ubuntu-20.04' && matrix.python_version == '3.11' }} + if: ${{ (matrix.os == 'ubuntu-20.04' || matrix.os == 'ubuntu-24.04') && matrix.python_version == '3.11' }} run: | sudo apt-get install -y graphviz # the newest version in Ubuntu 20.04 repository is 1.8.17, but we need Doxygen 1.9 series @@ -172,7 +173,7 @@ jobs: rm -rf doxygen-1.9.7 doxygen-1.9.7.linux.bin.tar.gz BUILD_DOCS=1 BUILD_TYPE=None poetry install - name: Upload Doxygen-generated docs as CI artifacts - if: ${{ matrix.os == 'ubuntu-20.04' && matrix.python_version == '3.11' }} + if: ${{ (matrix.os == 'ubuntu-20.04' || matrix.os == 'ubuntu-24.04') && matrix.python_version == '3.11' }} uses: actions/upload-artifact@v3 with: name: docs-${{ github.run_id }}-${{ github.sha }} @@ -244,7 +245,7 @@ jobs: name: cores-${{ matrix.os }}-${{ matrix.python_version }} path: /cores sdist: - runs-on: ubuntu-20.04 + runs-on: [ubuntu-20.04,ubuntu-24.04] steps: - uses: actions/checkout@v4 with: @@ -268,7 +269,7 @@ jobs: path: ./dist/ publish: needs: [build-and-test, sdist] - runs-on: ubuntu-20.04 + runs-on: [ubuntu-20.04,ubuntu-24.04] if: ${{ success() && github.event_name == 'push' && contains(github.ref, 'refs/tags/') }} steps: # no need to checkout @@ -291,7 +292,7 @@ jobs: # Implement a very basic Python package repository (https://peps.python.org/pep-0503/) # and deploy the static files to GitHub Pages needs: [build-and-test, sdist] - runs-on: ubuntu-20.04 + runs-on: [ubuntu-20.04,ubuntu-24.04] if: ${{ (success() || failure()) && github.ref_name == 'main' }} # publish nightly builds regardless of tests failure permissions: # grant GITHUB_TOKEN the permissions required to make a Pages deployment pages: write From a62c1c7ac22bf107cf21b5989f65673756803143 Mon Sep 17 00:00:00 2001 From: Xmader <16057139+Xmader@users.noreply.github.com> Date: Wed, 10 Jul 2024 19:25:56 +0000 Subject: [PATCH 137/428] chore(deps): upgrade SpiderMonkey to `bc4609b7aa7a3dff961f43d527bc66c5c85f6f4b` --- mozcentral.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mozcentral.version b/mozcentral.version index 02961814..3147fd26 100644 --- a/mozcentral.version +++ b/mozcentral.version @@ -1 +1 @@ -d25c9bdacb64ae50779dc91f5919ca0189ad6c36 \ No newline at end of file +bc4609b7aa7a3dff961f43d527bc66c5c85f6f4b From 92b95c36f6dac168b8b494b5ee45bf797ac1fa3e Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 10 Jul 2024 19:54:50 +0000 Subject: [PATCH 138/428] chore: there shouldn't be a trailing newline in `mozcentral.version` file --- .github/workflows/update-mozcentral-version.yaml | 2 +- mozcentral.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/update-mozcentral-version.yaml b/.github/workflows/update-mozcentral-version.yaml index d869a24e..d7de9f93 100644 --- a/.github/workflows/update-mozcentral-version.yaml +++ b/.github/workflows/update-mozcentral-version.yaml @@ -25,7 +25,7 @@ jobs: ) echo "MOZCENTRAL_VERSION=$COMMIT_HASH" >> $GITHUB_ENV - name: Update `mozcentral.version` File - run: echo $MOZCENTRAL_VERSION > mozcentral.version + run: echo -n $MOZCENTRAL_VERSION > mozcentral.version - name: Create Pull Request uses: peter-evans/create-pull-request@v6 with: diff --git a/mozcentral.version b/mozcentral.version index 3147fd26..758c56ec 100644 --- a/mozcentral.version +++ b/mozcentral.version @@ -1 +1 @@ -bc4609b7aa7a3dff961f43d527bc66c5c85f6f4b +bc4609b7aa7a3dff961f43d527bc66c5c85f6f4b \ No newline at end of file From 4713f028d18bd313227dcd202417d61416ffc6c9 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 10 Jul 2024 20:22:06 +0000 Subject: [PATCH 139/428] chore(CI): make the CI-created branch name shorter --- .github/workflows/update-mozcentral-version.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/update-mozcentral-version.yaml b/.github/workflows/update-mozcentral-version.yaml index d7de9f93..8f95895f 100644 --- a/.github/workflows/update-mozcentral-version.yaml +++ b/.github/workflows/update-mozcentral-version.yaml @@ -24,6 +24,7 @@ jobs: jq --join-output '(.lastpushid | tostring) as $pushid | empty, .pushes[$pushid].changesets[0]' ) echo "MOZCENTRAL_VERSION=$COMMIT_HASH" >> $GITHUB_ENV + echo "MOZCENTRAL_VERSION_SHORT=${COMMIT_HASH:0:7}" >> $GITHUB_ENV - name: Update `mozcentral.version` File run: echo -n $MOZCENTRAL_VERSION > mozcentral.version - name: Create Pull Request @@ -32,7 +33,7 @@ jobs: add-paths: mozcentral.version commit-message: | chore(deps): upgrade SpiderMonkey to `${{ env.MOZCENTRAL_VERSION }}` - branch: chore/upgrade-spidermonkey-to-${{ env.MOZCENTRAL_VERSION }} + branch: chore/upgrade-spidermonkey-to-${{ env.MOZCENTRAL_VERSION_SHORT }} title: Upgrade SpiderMonkey to mozilla-central commit `${{ env.MOZCENTRAL_VERSION }}` body: | Changeset: https://hg.mozilla.org/mozilla-central/rev/${{ env.MOZCENTRAL_VERSION }} From efc161e1b3cf8adc0ded555e1d2dd6df00f96b59 Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Thu, 11 Jul 2024 09:18:41 -0400 Subject: [PATCH 140/428] only use one version of ubuntu for CI, the latest one --- .github/workflows/test-and-publish.yaml | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 865850b7..8a90e710 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -15,7 +15,6 @@ on: required: false options: - '' - - 'ubuntu-20.04' - 'ubuntu-24.04' - 'macos-12' - 'macos-14' @@ -60,8 +59,8 @@ jobs: strategy: fail-fast: false matrix: - # Use Ubuntu 20.04 / macOS 13 x86_64 / macOS 14 arm64 + Python 3.10 to build SpiderMonkey - os: [ 'ubuntu-20.04','ubuntu-24.04','macos-13', 'macos-14' ] # macOS 14 runner exclusively runs on M1 hardwares + # Use Ubuntu 24.04 / macOS 13 x86_64 / macOS 14 arm64 + Python 3.10 to build SpiderMonkey + os: [ 'ubuntu-24.04','macos-13', 'macos-14' ] # macOS 14 runner exclusively runs on M1 hardwares # see https://github.blog/changelog/2024-01-30-github-actions-macos-14-sonoma-is-now-available python_version: [ '3.10' ] runs-on: ${{ matrix.os }} @@ -82,8 +81,6 @@ jobs: lookup-only: true # skip download - name: Setup XCode if: ${{ (matrix.os == 'macos-13' || matrix.os == 'macos-14') && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} - # SpiderMonkey 115 ESR requires XCode SDK version at least 13.3 - # https://github.com/actions/runner-images/blob/main/images/macos/macos-13-Readme.md#installed-sdks run: sudo xcode-select -switch /Applications/Xcode_14.3.app - name: Build spidermonkey if: ${{ steps.cache-spidermonkey.outputs.cache-hit != 'true' }} @@ -129,8 +126,7 @@ jobs: strategy: fail-fast: false matrix: - # The lowest supported version is Ubuntu 20.04 + Python 3.8 or macOS 12 + Python 3.9 - os: [ 'ubuntu-20.04', 'ubuntu-24.04', 'macos-12', 'macos-14', 'windows-2022' ] + os: [ 'ubuntu-24.04', 'macos-12', 'macos-14', 'windows-2022' ] python_version: [ '3.8', '3.9', '3.10', '3.11', '3.12' ] exclude: # actions/setup-python: The version '3.8'/'3.9' with architecture 'arm64' was not found for macOS. @@ -169,17 +165,16 @@ jobs: poetry install --no-root --only=dev echo "Installed Dependencies" - name: Build Docs # only build docs once - if: ${{ (matrix.os == 'ubuntu-20.04' || matrix.os == 'ubuntu-24.04') && matrix.python_version == '3.11' }} + if: ${{ matrix.os == 'ubuntu-24.04' && matrix.python_version == '3.11' }} run: | sudo apt-get install -y graphviz - # the newest version in Ubuntu 20.04 repository is 1.8.17, but we need Doxygen 1.9 series wget -c -q https://www.doxygen.nl/files/doxygen-1.9.7.linux.bin.tar.gz tar xf doxygen-1.9.7.linux.bin.tar.gz cd doxygen-1.9.7 && sudo make install && cd - rm -rf doxygen-1.9.7 doxygen-1.9.7.linux.bin.tar.gz BUILD_DOCS=1 BUILD_TYPE=None poetry install - name: Upload Doxygen-generated docs as CI artifacts - if: ${{ (matrix.os == 'ubuntu-20.04' || matrix.os == 'ubuntu-24.04') && matrix.python_version == '3.11' }} + if: ${{ matrix.os == 'ubuntu-24.04' && matrix.python_version == '3.11' }} uses: actions/upload-artifact@v3 with: name: docs-${{ github.run_id }}-${{ github.sha }} @@ -253,7 +248,7 @@ jobs: name: cores-${{ matrix.os }}-${{ matrix.python_version }} path: /cores sdist: - runs-on: [ubuntu-20.04,ubuntu-24.04] + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 with: @@ -277,7 +272,7 @@ jobs: path: ./dist/ publish: needs: [build-and-test, sdist] - runs-on: [ubuntu-20.04,ubuntu-24.04] + runs-on: ubuntu-24.04 if: ${{ success() && github.event_name == 'push' && contains(github.ref, 'refs/tags/') }} steps: # no need to checkout @@ -300,7 +295,7 @@ jobs: # Implement a very basic Python package repository (https://peps.python.org/pep-0503/) # and deploy the static files to GitHub Pages needs: [build-and-test, sdist] - runs-on: [ubuntu-20.04,ubuntu-24.04] + runs-on: ubuntu-24.04 if: ${{ (success() || failure()) && github.ref_name == 'main' }} # publish nightly builds regardless of tests failure permissions: # grant GITHUB_TOKEN the permissions required to make a Pages deployment pages: write From 7f67f6e2ddfd26d76e8d6eae416573dac62c52ea Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Thu, 11 Jul 2024 12:42:51 -0400 Subject: [PATCH 141/428] still need ubuntu 20.04 after all as lowest common denominator --- .github/workflows/test-and-publish.yaml | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 8a90e710..d49a7e38 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -15,6 +15,7 @@ on: required: false options: - '' + - 'ubuntu-20.04' - 'ubuntu-24.04' - 'macos-12' - 'macos-14' @@ -59,8 +60,8 @@ jobs: strategy: fail-fast: false matrix: - # Use Ubuntu 24.04 / macOS 13 x86_64 / macOS 14 arm64 + Python 3.10 to build SpiderMonkey - os: [ 'ubuntu-24.04','macos-13', 'macos-14' ] # macOS 14 runner exclusively runs on M1 hardwares + # Use Ubuntu 20.04 and 24.04 / macOS 13 x86_64 / macOS 14 arm64 + Python 3.10 to build SpiderMonkey + os: [ 'ubuntu-20.04', 'ubuntu-24.04', 'macos-13', 'macos-14' ] # macOS 14 runner exclusively runs on M1 hardwares # see https://github.blog/changelog/2024-01-30-github-actions-macos-14-sonoma-is-now-available python_version: [ '3.10' ] runs-on: ${{ matrix.os }} @@ -81,6 +82,7 @@ jobs: lookup-only: true # skip download - name: Setup XCode if: ${{ (matrix.os == 'macos-13' || matrix.os == 'macos-14') && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} + # SpiderMonkey requires XCode SDK version at least 13.3 run: sudo xcode-select -switch /Applications/Xcode_14.3.app - name: Build spidermonkey if: ${{ steps.cache-spidermonkey.outputs.cache-hit != 'true' }} @@ -126,7 +128,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ 'ubuntu-24.04', 'macos-12', 'macos-14', 'windows-2022' ] + os: [ 'ubuntu-20.04', 'ubuntu-24.04', 'macos-12', 'macos-14', 'windows-2022' ] python_version: [ '3.8', '3.9', '3.10', '3.11', '3.12' ] exclude: # actions/setup-python: The version '3.8'/'3.9' with architecture 'arm64' was not found for macOS. @@ -165,16 +167,17 @@ jobs: poetry install --no-root --only=dev echo "Installed Dependencies" - name: Build Docs # only build docs once - if: ${{ matrix.os == 'ubuntu-24.04' && matrix.python_version == '3.11' }} + if: ${{ (matrix.os == 'ubuntu-20.04' || matrix.os == 'ubuntu-24.04') && matrix.python_version == '3.11' }} run: | sudo apt-get install -y graphviz + # We need Doxygen 1.9 series wget -c -q https://www.doxygen.nl/files/doxygen-1.9.7.linux.bin.tar.gz tar xf doxygen-1.9.7.linux.bin.tar.gz cd doxygen-1.9.7 && sudo make install && cd - rm -rf doxygen-1.9.7 doxygen-1.9.7.linux.bin.tar.gz BUILD_DOCS=1 BUILD_TYPE=None poetry install - name: Upload Doxygen-generated docs as CI artifacts - if: ${{ matrix.os == 'ubuntu-24.04' && matrix.python_version == '3.11' }} + if: ${{ (matrix.os == 'ubuntu-20.04' || matrix.os == 'ubuntu-24.04') && matrix.python_version == '3.11' }} uses: actions/upload-artifact@v3 with: name: docs-${{ github.run_id }}-${{ github.sha }} @@ -248,7 +251,7 @@ jobs: name: cores-${{ matrix.os }}-${{ matrix.python_version }} path: /cores sdist: - runs-on: ubuntu-24.04 + runs-on: [ubuntu-20.04,ubuntu-24.04] steps: - uses: actions/checkout@v4 with: @@ -272,7 +275,7 @@ jobs: path: ./dist/ publish: needs: [build-and-test, sdist] - runs-on: ubuntu-24.04 + runs-on: [ubuntu-20.04,ubuntu-24.04] if: ${{ success() && github.event_name == 'push' && contains(github.ref, 'refs/tags/') }} steps: # no need to checkout @@ -295,7 +298,7 @@ jobs: # Implement a very basic Python package repository (https://peps.python.org/pep-0503/) # and deploy the static files to GitHub Pages needs: [build-and-test, sdist] - runs-on: ubuntu-24.04 + runs-on: [ubuntu-20.04,ubuntu-24.04] if: ${{ (success() || failure()) && github.ref_name == 'main' }} # publish nightly builds regardless of tests failure permissions: # grant GITHUB_TOKEN the permissions required to make a Pages deployment pages: write From 412eebcb0b87d3b1e021c49b46fcb0f7511bddcf Mon Sep 17 00:00:00 2001 From: philippedistributive Date: Thu, 11 Jul 2024 14:36:19 -0400 Subject: [PATCH 142/428] implement copy protocol for string proxies --- include/JSStringProxy.hh | 29 ++++++++++++++++++++++++ include/StrType.hh | 2 ++ src/JSStringProxy.cc | 14 +++++++++++- src/StrType.cc | 2 +- src/modules/pythonmonkey/pythonmonkey.cc | 3 ++- tests/python/test_strings.py | 19 ++++++++++++++++ 6 files changed, 66 insertions(+), 3 deletions(-) diff --git a/include/JSStringProxy.hh b/include/JSStringProxy.hh index 955f2830..fb376cc0 100644 --- a/include/JSStringProxy.hh +++ b/include/JSStringProxy.hh @@ -36,6 +36,35 @@ public: * @param self - The JSStringProxy to be free'd */ static void JSStringProxy_dealloc(JSStringProxy *self); + + /** + * @brief copy protocol method for both copy and deepcopy + * + * @param self - The JSObjectProxy + * @return a copy of the string + */ + static PyObject *JSStringProxy_copy_method(JSStringProxy *self); +}; + +// docs for methods, copied from cpython +PyDoc_STRVAR(stringproxy_deepcopy__doc__, + "__deepcopy__($self, memo, /)\n" +"--\n" +"\n"); + +PyDoc_STRVAR(stringproxy_copy__doc__, +"__copy__($self, /)\n" +"--\n" +"\n"); + +/** + * @brief Struct for the other methods + * + */ +static PyMethodDef JSStringProxy_methods[] = { + {"__deepcopy__", (PyCFunction)JSStringProxyMethodDefinitions::JSStringProxy_copy_method, METH_O, stringproxy_deepcopy__doc__}, // ignores any memo argument + {"__copy__", (PyCFunction)JSStringProxyMethodDefinitions::JSStringProxy_copy_method, METH_NOARGS, stringproxy_copy__doc__}, + {NULL, NULL} /* sentinel */ }; /** diff --git a/include/StrType.hh b/include/StrType.hh index 927d0195..91f86558 100644 --- a/include/StrType.hh +++ b/include/StrType.hh @@ -37,6 +37,8 @@ public: static PyObject *getPyObject(JSContext *cx, JS::HandleValue str); static const char *getValue(JSContext *cx, JS::HandleValue str); + + static PyObject *processString(JSContext *cx, JS::HandleValue str); }; #endif \ No newline at end of file diff --git a/src/JSStringProxy.cc b/src/JSStringProxy.cc index 01c1ad7d..bc6e7784 100644 --- a/src/JSStringProxy.cc +++ b/src/JSStringProxy.cc @@ -1,6 +1,6 @@ /** * @file JSStringProxy.cc - * @author Caleb Aikens (caleb@distributive.network) + * @author Caleb Aikens (caleb@distributive.network) and Philippe Laporte (plaporte@distributive.network) * @brief JSStringProxy is a custom C-implemented python type that derives from str. It acts as a proxy for JSStrings from Spidermonkey, and behaves like a str would. * @date 2024-05-15 * @@ -10,7 +10,19 @@ #include "include/JSStringProxy.hh" +#include "include/StrType.hh" + + +extern JSContext *GLOBAL_CX; + + void JSStringProxyMethodDefinitions::JSStringProxy_dealloc(JSStringProxy *self) { delete self->jsString; +} + +PyObject *JSStringProxyMethodDefinitions::JSStringProxy_copy_method(JSStringProxy *self) { + JS::RootedString selfString(GLOBAL_CX, ((JSStringProxy *)self)->jsString->toString()); + JS::RootedValue selfStringValue(GLOBAL_CX, JS::StringValue(selfString)); + return StrType::processString(GLOBAL_CX, selfStringValue); } \ No newline at end of file diff --git a/src/StrType.cc b/src/StrType.cc index c5c7ae7e..6459a6b1 100644 --- a/src/StrType.cc +++ b/src/StrType.cc @@ -95,7 +95,7 @@ static PyObject *asUCS4(PyObject *pyString) { return ret; } -static PyObject *processString(JSContext *cx, JS::HandleValue strVal) { +PyObject *StrType::processString(JSContext *cx, JS::HandleValue strVal) { JS::RootedString str(cx, strVal.toString()); JSLinearString *lstr = JS_EnsureLinearString(cx, str); JS::AutoCheckCannotGC nogc; diff --git a/src/modules/pythonmonkey/pythonmonkey.cc b/src/modules/pythonmonkey/pythonmonkey.cc index c7b9455a..e49b6f81 100644 --- a/src/modules/pythonmonkey/pythonmonkey.cc +++ b/src/modules/pythonmonkey/pythonmonkey.cc @@ -130,7 +130,8 @@ PyTypeObject JSStringProxyType = { .tp_basicsize = sizeof(JSStringProxy), .tp_dealloc = (destructor)JSStringProxyMethodDefinitions::JSStringProxy_dealloc, .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_UNICODE_SUBCLASS, - .tp_doc = PyDoc_STR("Javascript String value"), + .tp_doc = PyDoc_STR("Javascript String proxy"), + .tp_methods = JSStringProxy_methods, .tp_base = &PyUnicode_Type }; diff --git a/tests/python/test_strings.py b/tests/python/test_strings.py index cb3d37ae..01a22b97 100644 --- a/tests/python/test_strings.py +++ b/tests/python/test_strings.py @@ -1,6 +1,7 @@ import pythonmonkey as pm import gc import random +import copy def test_identity(): @@ -271,3 +272,21 @@ def test_eval_boxed_ucs4_string_fuzztest(): string1 = string2 assert INITIAL_STRING == string1 # strings should still match after a bunch of iterations through JS + + +def test_string_proxy_copy(): + world = pm.eval('(function() {return "World"})') + say = pm.eval('(function(who) { return `Hello ${who}`})') + who = world() + hello_world = say(copy.copy(who)) + assert hello_world == "Hello World" + assert hello_world is not who + +def test_string_proxy_deepcopy(): + world = pm.eval('(function() {return "World"})') + say = pm.eval('(function(who) { return `Hello ${who}`})') + who = world() + hello_world = say(copy.deepcopy(who)) + assert hello_world == "Hello World" + assert hello_world is not who + \ No newline at end of file From 9a6325bbaa763133b103acb257dde299b6afa3fe Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Thu, 11 Jul 2024 15:55:52 -0400 Subject: [PATCH 143/428] restrict actions for ubuntu 24.04 to build and test --- .github/workflows/test-and-publish.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index d49a7e38..0b90fc30 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -251,7 +251,7 @@ jobs: name: cores-${{ matrix.os }}-${{ matrix.python_version }} path: /cores sdist: - runs-on: [ubuntu-20.04,ubuntu-24.04] + runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v4 with: @@ -275,7 +275,7 @@ jobs: path: ./dist/ publish: needs: [build-and-test, sdist] - runs-on: [ubuntu-20.04,ubuntu-24.04] + runs-on: ubuntu-20.04 if: ${{ success() && github.event_name == 'push' && contains(github.ref, 'refs/tags/') }} steps: # no need to checkout @@ -298,7 +298,7 @@ jobs: # Implement a very basic Python package repository (https://peps.python.org/pep-0503/) # and deploy the static files to GitHub Pages needs: [build-and-test, sdist] - runs-on: [ubuntu-20.04,ubuntu-24.04] + runs-on: ubuntu-20.04 if: ${{ (success() || failure()) && github.ref_name == 'main' }} # publish nightly builds regardless of tests failure permissions: # grant GITHUB_TOKEN the permissions required to make a Pages deployment pages: write From 66f0078c9ea4e7cea550ef81ccb51c688d3ecf44 Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Fri, 12 Jul 2024 09:54:43 -0400 Subject: [PATCH 144/428] more CI for Ubuntu 24.04 --- .github/workflows/test-and-publish.yaml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 0b90fc30..63f93360 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -16,7 +16,6 @@ on: options: - '' - 'ubuntu-20.04' - - 'ubuntu-24.04' - 'macos-12' - 'macos-14' - 'windows-2022' @@ -60,7 +59,7 @@ jobs: strategy: fail-fast: false matrix: - # Use Ubuntu 20.04 and 24.04 / macOS 13 x86_64 / macOS 14 arm64 + Python 3.10 to build SpiderMonkey + # Use Ubuntu 20.04 / Ubuntu 24.04 / macOS 13 x86_64 / macOS 14 arm64 + Python 3.10 to build SpiderMonkey os: [ 'ubuntu-20.04', 'ubuntu-24.04', 'macos-13', 'macos-14' ] # macOS 14 runner exclusively runs on M1 hardwares # see https://github.blog/changelog/2024-01-30-github-actions-macos-14-sonoma-is-now-available python_version: [ '3.10' ] @@ -251,7 +250,7 @@ jobs: name: cores-${{ matrix.os }}-${{ matrix.python_version }} path: /cores sdist: - runs-on: ubuntu-20.04 + runs-on: [ubuntu-20.04, ubuntu-24.04] steps: - uses: actions/checkout@v4 with: From ab254593c2a34536e0ba3bf2a0ee1941e84453c3 Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Fri, 12 Jul 2024 10:01:13 -0400 Subject: [PATCH 145/428] improved naming --- include/StrType.hh | 2 +- src/JSStringProxy.cc | 2 +- src/StrType.cc | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/StrType.hh b/include/StrType.hh index 91f86558..a22fd6e0 100644 --- a/include/StrType.hh +++ b/include/StrType.hh @@ -38,7 +38,7 @@ public: static const char *getValue(JSContext *cx, JS::HandleValue str); - static PyObject *processString(JSContext *cx, JS::HandleValue str); + static PyObject *proxyfiString(JSContext *cx, JS::HandleValue str); }; #endif \ No newline at end of file diff --git a/src/JSStringProxy.cc b/src/JSStringProxy.cc index bc6e7784..d74f1c7a 100644 --- a/src/JSStringProxy.cc +++ b/src/JSStringProxy.cc @@ -24,5 +24,5 @@ void JSStringProxyMethodDefinitions::JSStringProxy_dealloc(JSStringProxy *self) PyObject *JSStringProxyMethodDefinitions::JSStringProxy_copy_method(JSStringProxy *self) { JS::RootedString selfString(GLOBAL_CX, ((JSStringProxy *)self)->jsString->toString()); JS::RootedValue selfStringValue(GLOBAL_CX, JS::StringValue(selfString)); - return StrType::processString(GLOBAL_CX, selfStringValue); + return StrType::proxyfiString(GLOBAL_CX, selfStringValue); } \ No newline at end of file diff --git a/src/StrType.cc b/src/StrType.cc index 6459a6b1..2fc63262 100644 --- a/src/StrType.cc +++ b/src/StrType.cc @@ -95,7 +95,7 @@ static PyObject *asUCS4(PyObject *pyString) { return ret; } -PyObject *StrType::processString(JSContext *cx, JS::HandleValue strVal) { +PyObject *StrType::proxyfiString(JSContext *cx, JS::HandleValue strVal) { JS::RootedString str(cx, strVal.toString()); JSLinearString *lstr = JS_EnsureLinearString(cx, str); JS::AutoCheckCannotGC nogc; @@ -189,11 +189,11 @@ PyObject *StrType::getPyObject(JSContext *cx, JS::HandleValue str) { } } - return processString(cx, str); + return proxyfiString(cx, str); } const char *StrType::getValue(JSContext *cx, JS::HandleValue str) { - PyObject *pyString = processString(cx, str); + PyObject *pyString = proxyfiString(cx, str); const char *value = PyUnicode_AsUTF8(pyString); Py_DECREF(pyString); return value; From 24d7896b97a15efe75bc09ce1942595ba2af4f67 Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Mon, 15 Jul 2024 14:31:36 -0400 Subject: [PATCH 146/428] handle NULL coming from pyTypeFactory and take into account jsObject address when detecting cycles --- src/JSObjectProxy.cc | 43 +++++++++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/src/JSObjectProxy.cc b/src/JSObjectProxy.cc index 83546f37..5116fe46 100644 --- a/src/JSObjectProxy.cc +++ b/src/JSObjectProxy.cc @@ -338,7 +338,14 @@ PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_iter_next(JSObjectProxy } PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_repr(JSObjectProxy *self) { - Py_ssize_t i = Py_ReprEnter((PyObject *)self); + // Detect cyclic objects + PyObject *objPtr = PyLong_FromVoidPtr(self->jsObject->get()); + // For `Py_ReprEnter`, we must get a same PyObject when visiting the same JSObject. + // We cannot simply use the object returned by `PyLong_FromVoidPtr` because it won't reuse the PyLongObjects for ints not between -5 and 256. + // Instead, we store this PyLongObject in a global dict, using itself as the hashable key, effectively interning the PyLongObject. + PyObject *tsDict = PyThreadState_GetDict(); + PyObject *cyclicKey = PyDict_SetDefault(tsDict, /*key*/ objPtr, /*value*/ objPtr); // cyclicKey = (tsDict[objPtr] ??= objPtr) + int i = Py_ReprEnter(cyclicKey); if (i != 0) { return i > 0 ? PyUnicode_FromString("{...}") : NULL; } @@ -346,7 +353,8 @@ PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_repr(JSObjectProxy *self Py_ssize_t selfLength = JSObjectProxy_length(self); if (selfLength == 0) { - Py_ReprLeave((PyObject *)self); + Py_ReprLeave(cyclicKey); + PyDict_DelItem(tsDict, cyclicKey); return PyUnicode_FromString("{}"); } @@ -417,15 +425,24 @@ PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_repr(JSObjectProxy *self value = pyTypeFactory(GLOBAL_CX, elementVal); } - s = PyObject_Repr(value); - if (s == NULL) { - goto error; - } + if (value != NULL) { + s = PyObject_Repr(value); + if (s == NULL) { + goto error; + } - res = _PyUnicodeWriter_WriteStr(&writer, s); - Py_DECREF(s); - if (res < 0) { - goto error; + res = _PyUnicodeWriter_WriteStr(&writer, s); + Py_DECREF(s); + if (res < 0) { + goto error; + } + } else { + // clear exception that was just set + PyErr_Clear(); + + if (_PyUnicodeWriter_WriteASCIIString(&writer, "", 19) < 0) { + goto error; + } } Py_CLEAR(key); @@ -437,11 +454,13 @@ PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_repr(JSObjectProxy *self goto error; } - Py_ReprLeave((PyObject *)self); + Py_ReprLeave(cyclicKey); + PyDict_DelItem(tsDict, cyclicKey); return _PyUnicodeWriter_Finish(&writer); error: - Py_ReprLeave((PyObject *)self); + Py_ReprLeave(cyclicKey); + PyDict_DelItem(tsDict, cyclicKey); _PyUnicodeWriter_Dealloc(&writer); Py_XDECREF(key); Py_XDECREF(value); From 07128594210086c6501591ab4e8af583b1316974 Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Mon, 15 Jul 2024 14:34:37 -0400 Subject: [PATCH 147/428] improved comment --- src/JSObjectProxy.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/JSObjectProxy.cc b/src/JSObjectProxy.cc index 5116fe46..a3fe2e1f 100644 --- a/src/JSObjectProxy.cc +++ b/src/JSObjectProxy.cc @@ -437,7 +437,7 @@ PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_repr(JSObjectProxy *self goto error; } } else { - // clear exception that was just set + // clear any exception that was just set PyErr_Clear(); if (_PyUnicodeWriter_WriteASCIIString(&writer, "", 19) < 0) { From dc1162563813d791d2d0a6fac198d72a01c3727b Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Mon, 15 Jul 2024 16:41:45 -0400 Subject: [PATCH 148/428] detect cycles in JS Arrays as well --- src/JSArrayProxy.cc | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/JSArrayProxy.cc b/src/JSArrayProxy.cc index 6fbdf465..00f085d5 100644 --- a/src/JSArrayProxy.cc +++ b/src/JSArrayProxy.cc @@ -511,17 +511,26 @@ PyObject *JSArrayProxyMethodDefinitions::JSArrayProxy_richcompare(JSArrayProxy * } PyObject *JSArrayProxyMethodDefinitions::JSArrayProxy_repr(JSArrayProxy *self) { + // Detect cyclic objects + PyObject *objPtr = PyLong_FromVoidPtr(self->jsArray->get()); + // For `Py_ReprEnter`, we must get a same PyObject when visiting the same JSObject. + // We cannot simply use the object returned by `PyLong_FromVoidPtr` because it won't reuse the PyLongObjects for ints not between -5 and 256. + // Instead, we store this PyLongObject in a global dict, using itself as the hashable key, effectively interning the PyLongObject. + PyObject *tsDict = PyThreadState_GetDict(); + PyObject *cyclicKey = PyDict_SetDefault(tsDict, /*key*/ objPtr, /*value*/ objPtr); // cyclicKey = (tsDict[objPtr] ??= objPtr) + int i = Py_ReprEnter(cyclicKey); + if (i != 0) { + return i > 0 ? PyUnicode_FromString("[...]") : NULL; + } + Py_ssize_t selfLength = JSArrayProxy_length(self); if (selfLength == 0) { + Py_ReprLeave(cyclicKey); + PyDict_DelItem(tsDict, cyclicKey); return PyUnicode_FromString("[]"); } - Py_ssize_t i = Py_ReprEnter((PyObject *)self); - if (i != 0) { - return i > 0 ? PyUnicode_FromString("[...]") : NULL; - } - _PyUnicodeWriter writer; _PyUnicodeWriter_Init(&writer); @@ -569,12 +578,14 @@ PyObject *JSArrayProxyMethodDefinitions::JSArrayProxy_repr(JSArrayProxy *self) { goto error; } - Py_ReprLeave((PyObject *)self); + Py_ReprLeave(cyclicKey); + PyDict_DelItem(tsDict, cyclicKey); return _PyUnicodeWriter_Finish(&writer); error: _PyUnicodeWriter_Dealloc(&writer); - Py_ReprLeave((PyObject *)self); + Py_ReprLeave(cyclicKey); + PyDict_DelItem(tsDict, cyclicKey); return NULL; } From 09c92add6576b9869fbbb55e7b8d650be0365084 Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Mon, 15 Jul 2024 16:49:27 -0400 Subject: [PATCH 149/428] Revert "detect cycles in JS Arrays as well" This reverts commit dc1162563813d791d2d0a6fac198d72a01c3727b. --- src/JSArrayProxy.cc | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/src/JSArrayProxy.cc b/src/JSArrayProxy.cc index 00f085d5..6fbdf465 100644 --- a/src/JSArrayProxy.cc +++ b/src/JSArrayProxy.cc @@ -511,26 +511,17 @@ PyObject *JSArrayProxyMethodDefinitions::JSArrayProxy_richcompare(JSArrayProxy * } PyObject *JSArrayProxyMethodDefinitions::JSArrayProxy_repr(JSArrayProxy *self) { - // Detect cyclic objects - PyObject *objPtr = PyLong_FromVoidPtr(self->jsArray->get()); - // For `Py_ReprEnter`, we must get a same PyObject when visiting the same JSObject. - // We cannot simply use the object returned by `PyLong_FromVoidPtr` because it won't reuse the PyLongObjects for ints not between -5 and 256. - // Instead, we store this PyLongObject in a global dict, using itself as the hashable key, effectively interning the PyLongObject. - PyObject *tsDict = PyThreadState_GetDict(); - PyObject *cyclicKey = PyDict_SetDefault(tsDict, /*key*/ objPtr, /*value*/ objPtr); // cyclicKey = (tsDict[objPtr] ??= objPtr) - int i = Py_ReprEnter(cyclicKey); - if (i != 0) { - return i > 0 ? PyUnicode_FromString("[...]") : NULL; - } - Py_ssize_t selfLength = JSArrayProxy_length(self); if (selfLength == 0) { - Py_ReprLeave(cyclicKey); - PyDict_DelItem(tsDict, cyclicKey); return PyUnicode_FromString("[]"); } + Py_ssize_t i = Py_ReprEnter((PyObject *)self); + if (i != 0) { + return i > 0 ? PyUnicode_FromString("[...]") : NULL; + } + _PyUnicodeWriter writer; _PyUnicodeWriter_Init(&writer); @@ -578,14 +569,12 @@ PyObject *JSArrayProxyMethodDefinitions::JSArrayProxy_repr(JSArrayProxy *self) { goto error; } - Py_ReprLeave(cyclicKey); - PyDict_DelItem(tsDict, cyclicKey); + Py_ReprLeave((PyObject *)self); return _PyUnicodeWriter_Finish(&writer); error: _PyUnicodeWriter_Dealloc(&writer); - Py_ReprLeave(cyclicKey); - PyDict_DelItem(tsDict, cyclicKey); + Py_ReprLeave((PyObject *)self); return NULL; } From f888be43c2e4f0a1a0e1b239eeeef8779fd9268d Mon Sep 17 00:00:00 2001 From: Caleb Aikens Date: Tue, 16 Jul 2024 10:04:20 -0400 Subject: [PATCH 150/428] fix(setup.sh): only perform dev configurations if in a repo --- setup.sh | 65 +++++++++++++++++++++++++++++++------------------------- 1 file changed, 36 insertions(+), 29 deletions(-) diff --git a/setup.sh b/setup.sh index de25b914..eab31081 100755 --- a/setup.sh +++ b/setup.sh @@ -2,11 +2,6 @@ set -euo pipefail IFS=$'\n\t' -# set git hooks -ln -s -f ../../githooks/pre-commit .git/hooks/pre-commit -# set blame ignore file -git config blame.ignorerevsfile .git-blame-ignore-revs - # Get number of CPU cores CPUS=$(getconf _NPROCESSORS_ONLN 2>/dev/null || getconf NPROCESSORS_ONLN 2>/dev/null || echo 1) @@ -17,11 +12,12 @@ if [[ "$OSTYPE" == "linux-gnu"* ]]; then # Linux # sudo is present on the system, so use it SUDO='sudo' fi - $SUDO apt-get update --yes + echo "Installing apt packages" $SUDO apt-get install --yes cmake graphviz llvm clang pkg-config m4 unzip \ wget curl python3-dev # Install Doxygen # the newest version in Ubuntu 20.04 repository is 1.8.17, but we need Doxygen 1.9 series + echo "Installing doxygen" wget -c -q https://www.doxygen.nl/files/doxygen-1.9.7.linux.bin.tar.gz tar xf doxygen-1.9.7.linux.bin.tar.gz cd doxygen-1.9.7 && $SUDO make install && cd - @@ -36,9 +32,11 @@ else exit 1 fi # Install rust compiler +echo "Installing rust compiler" curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.76 cargo install cbindgen # Setup Poetry +echo "Installing poetry" curl -sSL https://install.python-poetry.org | python3 - --version "1.7.1" if [[ "$OSTYPE" == "msys"* ]]; then # Windows POETRY_BIN="$APPDATA/Python/Scripts/poetry" @@ -46,31 +44,8 @@ else POETRY_BIN=`echo ~/.local/bin/poetry` # expand tilde fi $POETRY_BIN self add 'poetry-dynamic-versioning[plugin]' -$POETRY_BIN run pip install autopep8 echo "Done installing dependencies" -echo "Downloading uncrustify source code" -wget -c -q https://github.com/uncrustify/uncrustify/archive/refs/tags/uncrustify-0.78.1.tar.gz -mkdir -p uncrustify-source -tar -xzf uncrustify-0.78.1.tar.gz -C uncrustify-source --strip-components=1 # strip the root folder -echo "Done downloading uncrustify source code" - -echo "Building uncrustify" -cd uncrustify-source -mkdir -p build -cd build -if [[ "$OSTYPE" == "msys"* ]]; then # Windows - cmake ../ - cmake --build . -j$CPUS --config Release - cp Release/uncrustify.exe ../../uncrustify.exe -else - cmake ../ - make -j$CPUS - cp uncrustify ../../uncrustify -fi -cd ../.. -echo "Done building uncrustify" - echo "Downloading spidermonkey source code" # Read the commit hash for mozilla-central from the `mozcentral.version` file MOZCENTRAL_VERSION=$(cat mozcentral.version) @@ -118,3 +93,35 @@ if [[ "$OSTYPE" == "darwin"* ]]; then # macOS install_name_tool -id @rpath/$(basename ./libmozjs*) ./libmozjs* # making it work for whatever name the libmozjs dylib is called fi echo "Done installing spidermonkey" + +# if this is being ran in the root directory of the PythonMonkey repo, then include dev configurations +if test -f .git/hooks/pre-commit; then + # set git hooks + ln -s -f ../../githooks/pre-commit .git/hooks/pre-commit + # set blame ignore file + git config blame.ignorerevsfile .git-blame-ignore-revs + # install autopep8 + $POETRY_BIN run pip install autopep8 + # install uncrustify + echo "Downloading uncrustify source code" + wget -c -q https://github.com/uncrustify/uncrustify/archive/refs/tags/uncrustify-0.78.1.tar.gz + mkdir -p uncrustify-source + tar -xzf uncrustify-0.78.1.tar.gz -C uncrustify-source --strip-components=1 # strip the root folder + echo "Done downloading uncrustify source code" + + echo "Building uncrustify" + cd uncrustify-source + mkdir -p build + cd build + if [[ "$OSTYPE" == "msys"* ]]; then # Windows + cmake ../ + cmake --build . -j$CPUS --config Release + cp Release/uncrustify.exe ../../uncrustify.exe + else + cmake ../ + make -j$CPUS + cp uncrustify ../../uncrustify + fi + cd ../.. + echo "Done building uncrustify" +fi \ No newline at end of file From daeb2661f4a6ed680f84af84dea4cbab9ad0c6d7 Mon Sep 17 00:00:00 2001 From: Caleb Aikens Date: Tue, 16 Jul 2024 10:05:22 -0400 Subject: [PATCH 151/428] meta(CI): include a test of sdist installation in CI --- .github/workflows/test-and-publish.yaml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 63f93360..8902fc81 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -272,6 +272,19 @@ jobs: with: name: wheel-${{ github.run_id }}-${{ github.sha }} path: ./dist/ + check-install-from-sdist: + needs: [build-and-test, sdist] + runs-on: [ubuntu-24.04] + steps: + - uses: actions/setup-python@v5 + with: + python-version: '3.10' + - name: Download wheels built + uses: actions/download-artifact@v3 + with: + name: wheel-${{ github.run_id }}-${{ github.sha }} + path: ./dist/ + - run: pip install ./dist/pythonmonkey-*.tar.gz publish: needs: [build-and-test, sdist] runs-on: ubuntu-20.04 From 310ccf181640b93b90c8252d763654a8af888169 Mon Sep 17 00:00:00 2001 From: philippedistributive <151072087+philippedistributive@users.noreply.github.com> Date: Tue, 16 Jul 2024 11:31:51 -0400 Subject: [PATCH 152/428] Update .github/workflows/test-and-publish.yaml Co-authored-by: Caleb Aikens --- .github/workflows/test-and-publish.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 8902fc81..2acb3ddd 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -166,7 +166,7 @@ jobs: poetry install --no-root --only=dev echo "Installed Dependencies" - name: Build Docs # only build docs once - if: ${{ (matrix.os == 'ubuntu-20.04' || matrix.os == 'ubuntu-24.04') && matrix.python_version == '3.11' }} + if: ${{ matrix.os == 'ubuntu-20.04' && matrix.python_version == '3.11' }} run: | sudo apt-get install -y graphviz # We need Doxygen 1.9 series From f854430258ae0690700a071e2e723284f1fd404d Mon Sep 17 00:00:00 2001 From: philippedistributive <151072087+philippedistributive@users.noreply.github.com> Date: Tue, 16 Jul 2024 11:32:32 -0400 Subject: [PATCH 153/428] Update .github/workflows/test-and-publish.yaml Co-authored-by: Caleb Aikens --- .github/workflows/test-and-publish.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 2acb3ddd..f84ba795 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -169,7 +169,7 @@ jobs: if: ${{ matrix.os == 'ubuntu-20.04' && matrix.python_version == '3.11' }} run: | sudo apt-get install -y graphviz - # We need Doxygen 1.9 series + # the newest version in Ubuntu 20.04 repository is 1.8.17, but we need Doxygen 1.9 series wget -c -q https://www.doxygen.nl/files/doxygen-1.9.7.linux.bin.tar.gz tar xf doxygen-1.9.7.linux.bin.tar.gz cd doxygen-1.9.7 && sudo make install && cd - From 1d776f6ca8a2498fad4f8811b79f3970b1f80c32 Mon Sep 17 00:00:00 2001 From: philippedistributive <151072087+philippedistributive@users.noreply.github.com> Date: Tue, 16 Jul 2024 11:36:22 -0400 Subject: [PATCH 154/428] Update .github/workflows/test-and-publish.yaml Co-authored-by: Caleb Aikens --- .github/workflows/test-and-publish.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index f84ba795..e63dd576 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -176,7 +176,7 @@ jobs: rm -rf doxygen-1.9.7 doxygen-1.9.7.linux.bin.tar.gz BUILD_DOCS=1 BUILD_TYPE=None poetry install - name: Upload Doxygen-generated docs as CI artifacts - if: ${{ (matrix.os == 'ubuntu-20.04' || matrix.os == 'ubuntu-24.04') && matrix.python_version == '3.11' }} + if: ${{ matrix.os == 'ubuntu-20.04' && matrix.python_version == '3.11' }} uses: actions/upload-artifact@v3 with: name: docs-${{ github.run_id }}-${{ github.sha }} From b319ae62008acaddc621d29bee68fd9dd608ec06 Mon Sep 17 00:00:00 2001 From: philippedistributive <151072087+philippedistributive@users.noreply.github.com> Date: Tue, 16 Jul 2024 11:37:07 -0400 Subject: [PATCH 155/428] Update .github/workflows/test-and-publish.yaml Co-authored-by: Caleb Aikens --- .github/workflows/test-and-publish.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index e63dd576..8d1b1651 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -250,7 +250,7 @@ jobs: name: cores-${{ matrix.os }}-${{ matrix.python_version }} path: /cores sdist: - runs-on: [ubuntu-20.04, ubuntu-24.04] + runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v4 with: From 4ef34d2d4b41fc65dd01f59b6be0c8b8a0c5234d Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Tue, 16 Jul 2024 11:45:07 -0400 Subject: [PATCH 156/428] fixup --- .github/workflows/test-and-publish.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 8d1b1651..718ff493 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -274,7 +274,7 @@ jobs: path: ./dist/ check-install-from-sdist: needs: [build-and-test, sdist] - runs-on: [ubuntu-24.04] + runs-on: ubuntu-24.04 steps: - uses: actions/setup-python@v5 with: From ec65cd18a327e062aa3a28398919fe2b9d6fd385 Mon Sep 17 00:00:00 2001 From: philippedistributive <151072087+philippedistributive@users.noreply.github.com> Date: Tue, 16 Jul 2024 12:26:55 -0400 Subject: [PATCH 157/428] renaming Co-authored-by: Caleb Aikens --- include/StrType.hh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/StrType.hh b/include/StrType.hh index a22fd6e0..5e1954c1 100644 --- a/include/StrType.hh +++ b/include/StrType.hh @@ -38,7 +38,7 @@ public: static const char *getValue(JSContext *cx, JS::HandleValue str); - static PyObject *proxyfiString(JSContext *cx, JS::HandleValue str); + static PyObject *proxifyString(JSContext *cx, JS::HandleValue str); }; #endif \ No newline at end of file From 90b54b65f1fbbc02b535a674e6dadcf5c7c371aa Mon Sep 17 00:00:00 2001 From: philippedistributive <151072087+philippedistributive@users.noreply.github.com> Date: Tue, 16 Jul 2024 12:27:03 -0400 Subject: [PATCH 158/428] renaming Co-authored-by: Caleb Aikens --- src/StrType.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/StrType.cc b/src/StrType.cc index 2fc63262..71e19003 100644 --- a/src/StrType.cc +++ b/src/StrType.cc @@ -95,7 +95,7 @@ static PyObject *asUCS4(PyObject *pyString) { return ret; } -PyObject *StrType::proxyfiString(JSContext *cx, JS::HandleValue strVal) { +PyObject *StrType::proxifyString(JSContext *cx, JS::HandleValue strVal) { JS::RootedString str(cx, strVal.toString()); JSLinearString *lstr = JS_EnsureLinearString(cx, str); JS::AutoCheckCannotGC nogc; From 0aa7f4e988da35579ff41f20cdf7886e8beb7eaf Mon Sep 17 00:00:00 2001 From: philippedistributive <151072087+philippedistributive@users.noreply.github.com> Date: Tue, 16 Jul 2024 12:27:13 -0400 Subject: [PATCH 159/428] renaming Co-authored-by: Caleb Aikens --- src/JSStringProxy.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/JSStringProxy.cc b/src/JSStringProxy.cc index d74f1c7a..90ae9d5a 100644 --- a/src/JSStringProxy.cc +++ b/src/JSStringProxy.cc @@ -24,5 +24,5 @@ void JSStringProxyMethodDefinitions::JSStringProxy_dealloc(JSStringProxy *self) PyObject *JSStringProxyMethodDefinitions::JSStringProxy_copy_method(JSStringProxy *self) { JS::RootedString selfString(GLOBAL_CX, ((JSStringProxy *)self)->jsString->toString()); JS::RootedValue selfStringValue(GLOBAL_CX, JS::StringValue(selfString)); - return StrType::proxyfiString(GLOBAL_CX, selfStringValue); + return StrType::proxifyString(GLOBAL_CX, selfStringValue); } \ No newline at end of file From b310b6f19372dcaf52d128c3451eff3e6e88847d Mon Sep 17 00:00:00 2001 From: philippedistributive <151072087+philippedistributive@users.noreply.github.com> Date: Tue, 16 Jul 2024 12:27:22 -0400 Subject: [PATCH 160/428] renaming Co-authored-by: Caleb Aikens --- src/StrType.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/StrType.cc b/src/StrType.cc index 71e19003..8cf8c547 100644 --- a/src/StrType.cc +++ b/src/StrType.cc @@ -193,7 +193,7 @@ PyObject *StrType::getPyObject(JSContext *cx, JS::HandleValue str) { } const char *StrType::getValue(JSContext *cx, JS::HandleValue str) { - PyObject *pyString = proxyfiString(cx, str); + PyObject *pyString = proxifyString(cx, str); const char *value = PyUnicode_AsUTF8(pyString); Py_DECREF(pyString); return value; From 1ad2784b27eae91422d7c7c0fcf74d096e463826 Mon Sep 17 00:00:00 2001 From: philippedistributive <151072087+philippedistributive@users.noreply.github.com> Date: Tue, 16 Jul 2024 12:27:30 -0400 Subject: [PATCH 161/428] renaming Co-authored-by: Caleb Aikens --- src/StrType.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/StrType.cc b/src/StrType.cc index 8cf8c547..f01ce1ac 100644 --- a/src/StrType.cc +++ b/src/StrType.cc @@ -189,7 +189,7 @@ PyObject *StrType::getPyObject(JSContext *cx, JS::HandleValue str) { } } - return proxyfiString(cx, str); + return proxifyString(cx, str); } const char *StrType::getValue(JSContext *cx, JS::HandleValue str) { From 2633b5a77fa5b641883ae7d30e18ebdac58c5d89 Mon Sep 17 00:00:00 2001 From: Caleb Aikens Date: Tue, 16 Jul 2024 13:05:06 -0400 Subject: [PATCH 162/428] meta(CI): check-install-from-sdist step doesn't require build-and-test --- .github/workflows/test-and-publish.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 718ff493..296b66af 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -273,7 +273,7 @@ jobs: name: wheel-${{ github.run_id }}-${{ github.sha }} path: ./dist/ check-install-from-sdist: - needs: [build-and-test, sdist] + needs: sdist runs-on: ubuntu-24.04 steps: - uses: actions/setup-python@v5 From a14a70d8c93d9e10b76d6f0e5c0d9d1c99f29f20 Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Tue, 16 Jul 2024 16:57:56 -0400 Subject: [PATCH 163/428] check if exception was set before clearing it --- src/JSObjectProxy.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/JSObjectProxy.cc b/src/JSObjectProxy.cc index a3fe2e1f..675219bf 100644 --- a/src/JSObjectProxy.cc +++ b/src/JSObjectProxy.cc @@ -438,7 +438,9 @@ PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_repr(JSObjectProxy *self } } else { // clear any exception that was just set - PyErr_Clear(); + if (PyErr_Occurred()) { + PyErr_Clear(); + } if (_PyUnicodeWriter_WriteASCIIString(&writer, "", 19) < 0) { goto error; From e91d38f023fd925a9778895ee37e910c11bc61ea Mon Sep 17 00:00:00 2001 From: Caleb Aikens Date: Wed, 17 Jul 2024 09:46:25 -0400 Subject: [PATCH 164/428] fix(setup): configure the current shell to include cargo before using it in setup.sh --- setup.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.sh b/setup.sh index eab31081..ca7ab7c9 100755 --- a/setup.sh +++ b/setup.sh @@ -34,6 +34,7 @@ fi # Install rust compiler echo "Installing rust compiler" curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.76 +. $HOME/.cargo/env cargo install cbindgen # Setup Poetry echo "Installing poetry" From 73129bae2f8d8093317a5665c2ec45b80d230f47 Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Thu, 18 Jul 2024 12:12:15 -0400 Subject: [PATCH 165/428] support console printing of iterable proxy --- src/PyIterableProxyHandler.cc | 84 ++++++++++++++++++++++++++++++++++- src/PyObjectProxyHandler.cc | 28 +++++++----- 2 files changed, 100 insertions(+), 12 deletions(-) diff --git a/src/PyIterableProxyHandler.cc b/src/PyIterableProxyHandler.cc index 178dbde4..4c6920f0 100644 --- a/src/PyIterableProxyHandler.cc +++ b/src/PyIterableProxyHandler.cc @@ -66,8 +66,48 @@ static bool iterable_next(JSContext *cx, unsigned argc, JS::Value *vp) { return iter_next(cx, args, it); } +static bool toPrimitive(JSContext *cx, unsigned argc, JS::Value *vp) { + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); + + JS::RootedObject proxy(cx, JS::ToObject(cx, args.thisv())); + if (!proxy) { + return false; + } + + PyObject *self = JS::GetMaybePtrFromReservedSlot(proxy, PyObjectSlot); + + _PyUnicodeWriter writer; + + _PyUnicodeWriter_Init(&writer); + + PyObject *s = PyObject_Repr(self); + + if (s == nullptr) { + args.rval().setString(JS_NewStringCopyZ(cx, "")); + return true; + } + + int res = _PyUnicodeWriter_WriteStr(&writer, s); + Py_DECREF(s); + + if (res < 0) { + args.rval().setString(JS_NewStringCopyZ(cx, "")); + return true; + } + + PyObject* repr = _PyUnicodeWriter_Finish(&writer); + + args.rval().set(jsTypeFactory(cx, repr)); + return true; +} + +static bool iterable_valueOf(JSContext *cx, unsigned argc, JS::Value *vp) { + return toPrimitive(cx, argc, vp); +} + JSMethodDef PyIterableProxyHandler::iterable_methods[] = { {"next", iterable_next, 0}, + {"valueOf", iterable_valueOf, 0}, {NULL, NULL, 0} }; @@ -172,7 +212,7 @@ bool PyIterableProxyHandler::getOwnPropertyDescriptor( JSContext *cx, JS::HandleObject proxy, JS::HandleId id, JS::MutableHandle> desc ) const { - + // see if we're calling a function if (id.isString()) { for (size_t index = 0;; index++) { @@ -196,11 +236,39 @@ bool PyIterableProxyHandler::getOwnPropertyDescriptor( } } + // "constructor" property + bool isConstructorProperty; + if (id.isString() && JS_StringEqualsLiteral(cx, id.toString(), "constructor", &isConstructorProperty) && isConstructorProperty) { + //printf("PyIterableProxyHandler::handleGetOwnPropertyDescriptor constructor\n"); + JS::RootedObject global(cx, JS::GetNonCCWObjectGlobal(proxy)); + + JS::RootedObject rootedObjectPrototype(cx); + if (!JS_GetClassPrototype(cx, JSProto_Object, &rootedObjectPrototype)) { + return false; + } + + JS::RootedValue Object_Prototype_Constructor(cx); + if (!JS_GetProperty(cx, rootedObjectPrototype, "constructor", &Object_Prototype_Constructor)) { + return false; + } + + JS::RootedObject rootedObjectPrototypeConstructor(cx, Object_Prototype_Constructor.toObjectOrNull()); + + desc.set(mozilla::Some( + JS::PropertyDescriptor::Data( + JS::ObjectValue(*rootedObjectPrototypeConstructor), + {JS::PropertyAttribute::Enumerable} + ) + )); + return true; + } + // symbol property if (id.isSymbol()) { JS::RootedSymbol rootedSymbol(cx, id.toSymbol()); + JS::SymbolCode symbolCode = JS::GetSymbolCode(rootedSymbol); - if (JS::GetSymbolCode(rootedSymbol) == JS::SymbolCode::iterator) { + if (symbolCode == JS::SymbolCode::iterator) { JSFunction *newFunction = JS_NewFunction(cx, iterable_values, 0, 0, NULL); if (!newFunction) return false; JS::RootedObject funObj(cx, JS_GetFunctionObject(newFunction)); @@ -211,6 +279,18 @@ bool PyIterableProxyHandler::getOwnPropertyDescriptor( ) )); return true; + } + else if (symbolCode == JS::SymbolCode::toPrimitive) { + JSFunction *newFunction = JS_NewFunction(cx, toPrimitive, 0, 0, nullptr); + if (!newFunction) return false; + JS::RootedObject funObj(cx, JS_GetFunctionObject(newFunction)); + desc.set(mozilla::Some( + JS::PropertyDescriptor::Data( + JS::ObjectValue(*funObj), + {JS::PropertyAttribute::Enumerable} + ) + )); + return true; } } diff --git a/src/PyObjectProxyHandler.cc b/src/PyObjectProxyHandler.cc index 12bfef78..270f6124 100644 --- a/src/PyObjectProxyHandler.cc +++ b/src/PyObjectProxyHandler.cc @@ -123,19 +123,27 @@ void PyObjectProxyHandler::finalize(JS::GCContext *gcx, JSObject *proxy) const { bool PyObjectProxyHandler::ownPropertyKeys(JSContext *cx, JS::HandleObject proxy, JS::MutableHandleIdVector props) const { PyObject *self = JS::GetMaybePtrFromReservedSlot(proxy, PyObjectSlot); PyObject *keys = PyObject_Dir(self); - size_t keysLength = PyList_Size(keys); - PyObject *nonDunderKeys = PyList_New(0); - for (size_t i = 0; i < keysLength; i++) { - PyObject *key = PyList_GetItem(keys, i); - if (PyObject_CallMethod(key, "startswith", "(s)", "__") == Py_False) { // if key starts with "__", ignore it - PyList_Append(nonDunderKeys, key); - } - } + if (keys != nullptr) { + size_t keysLength = PyList_Size(keys); - size_t length = PyList_Size(nonDunderKeys); + PyObject *nonDunderKeys = PyList_New(0); + for (size_t i = 0; i < keysLength; i++) { + PyObject *key = PyList_GetItem(keys, i); + if (PyObject_CallMethod(key, "startswith", "(s)", "__") == Py_False) { // if key starts with "__", ignore it + PyList_Append(nonDunderKeys, key); + } + } - return handleOwnPropertyKeys(cx, nonDunderKeys, length, props); + return handleOwnPropertyKeys(cx, nonDunderKeys, PyList_Size(nonDunderKeys), props); + } + else { + if (PyErr_Occurred()) { + PyErr_Clear(); + } + + return handleOwnPropertyKeys(cx, PyList_New(0), 0, props); + } } bool PyObjectProxyHandler::delete_(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, From b90bf37ae2e5ffd3818b6ab459394c88f51bf32f Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Thu, 18 Jul 2024 12:14:48 -0400 Subject: [PATCH 166/428] cleanup --- src/PyIterableProxyHandler.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/PyIterableProxyHandler.cc b/src/PyIterableProxyHandler.cc index 4c6920f0..e56c3b85 100644 --- a/src/PyIterableProxyHandler.cc +++ b/src/PyIterableProxyHandler.cc @@ -212,7 +212,6 @@ bool PyIterableProxyHandler::getOwnPropertyDescriptor( JSContext *cx, JS::HandleObject proxy, JS::HandleId id, JS::MutableHandle> desc ) const { - // see if we're calling a function if (id.isString()) { for (size_t index = 0;; index++) { @@ -239,7 +238,6 @@ bool PyIterableProxyHandler::getOwnPropertyDescriptor( // "constructor" property bool isConstructorProperty; if (id.isString() && JS_StringEqualsLiteral(cx, id.toString(), "constructor", &isConstructorProperty) && isConstructorProperty) { - //printf("PyIterableProxyHandler::handleGetOwnPropertyDescriptor constructor\n"); JS::RootedObject global(cx, JS::GetNonCCWObjectGlobal(proxy)); JS::RootedObject rootedObjectPrototype(cx); From d036526ce6d3a303411a60f8be31476fff7dfcec Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Thu, 18 Jul 2024 12:23:50 -0400 Subject: [PATCH 167/428] added tests for iterable proxy constructor and Symbol.toPrimitive properties --- tests/python/test_objects.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/python/test_objects.py b/tests/python/test_objects.py index a56ba529..dada0e39 100644 --- a/tests/python/test_objects.py +++ b/tests/python/test_objects.py @@ -148,3 +148,15 @@ def __init__(self): o = MyClass() assert '[object Object]' == pm.eval("(obj) => { return obj.toLocaleString(); }")(o) + + +def test_toPrimitive_iterable(): + iterable = iter([1,2]) + toPrimitive = pm.eval("(obj) => { return obj[Symbol.toPrimitive]; }")(iterable) + assert repr(toPrimitive).__contains__(" { return obj.constructor; }")(iterable) + assert repr(toPrimitive).__contains__(" Date: Thu, 18 Jul 2024 12:41:11 -0400 Subject: [PATCH 168/428] more tests for toPrimitive and constructor property --- tests/python/test_objects.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/tests/python/test_objects.py b/tests/python/test_objects.py index dada0e39..96935344 100644 --- a/tests/python/test_objects.py +++ b/tests/python/test_objects.py @@ -1,4 +1,5 @@ import pythonmonkey as pm +import sys def test_eval_pyobjects(): @@ -158,5 +159,15 @@ def test_toPrimitive_iterable(): def test_constructor_iterable(): iterable = iter([1,2]) - toPrimitive = pm.eval("(obj) => { return obj.constructor; }")(iterable) - assert repr(toPrimitive).__contains__(" { return obj.constructor; }")(iterable) + assert repr(constructor).__contains__(" { return obj[Symbol.toPrimitive]; }")(sys.stdin) + assert repr(toPrimitive).__contains__(" { return obj.constructor; }")(sys.stdin) + assert repr(constructor).__contains__(" Date: Fri, 19 Jul 2024 17:17:45 -0400 Subject: [PATCH 169/428] Need to get PyObject 's attribute which is not necessarily a dict --- src/PyIterableProxyHandler.cc | 2 +- tests/python/test_objects.py | 13 ++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/PyIterableProxyHandler.cc b/src/PyIterableProxyHandler.cc index e56c3b85..f60c747b 100644 --- a/src/PyIterableProxyHandler.cc +++ b/src/PyIterableProxyHandler.cc @@ -294,7 +294,7 @@ bool PyIterableProxyHandler::getOwnPropertyDescriptor( PyObject *attrName = idToKey(cx, id); PyObject *self = JS::GetMaybePtrFromReservedSlot(proxy, PyObjectSlot); - PyObject *item = PyDict_GetItemWithError(self, attrName); + PyObject *item = PyObject_GetAttr(self, attrName); return handleGetOwnPropertyDescriptor(cx, id, desc, item); } \ No newline at end of file diff --git a/tests/python/test_objects.py b/tests/python/test_objects.py index 96935344..4ae77c9c 100644 --- a/tests/python/test_objects.py +++ b/tests/python/test_objects.py @@ -1,5 +1,6 @@ import pythonmonkey as pm import sys +from io import StringIO def test_eval_pyobjects(): @@ -170,4 +171,14 @@ def test_toPrimitive_stdin(): def test_constructor_stdin(): constructor = pm.eval("(obj) => { return obj.constructor; }")(sys.stdin) - assert repr(constructor).__contains__(" Date: Fri, 19 Jul 2024 17:36:50 -0400 Subject: [PATCH 170/428] improved test --- tests/python/test_objects.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/python/test_objects.py b/tests/python/test_objects.py index 4ae77c9c..0f2346da 100644 --- a/tests/python/test_objects.py +++ b/tests/python/test_objects.py @@ -174,11 +174,12 @@ def test_constructor_stdin(): assert repr(constructor).__contains__(" Date: Fri, 19 Jul 2024 17:37:48 -0400 Subject: [PATCH 171/428] improved test naming --- tests/python/test_objects.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/python/test_objects.py b/tests/python/test_objects.py index 0f2346da..23d3ef2a 100644 --- a/tests/python/test_objects.py +++ b/tests/python/test_objects.py @@ -174,7 +174,7 @@ def test_constructor_stdin(): assert repr(constructor).__contains__(" Date: Fri, 19 Jul 2024 17:39:20 -0400 Subject: [PATCH 172/428] best place for test --- tests/python/test_objects.py | 14 +------------- tests/python/test_pythonmonkey_eval.py | 11 +++++++++++ 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/tests/python/test_objects.py b/tests/python/test_objects.py index 23d3ef2a..96935344 100644 --- a/tests/python/test_objects.py +++ b/tests/python/test_objects.py @@ -1,6 +1,5 @@ import pythonmonkey as pm import sys -from io import StringIO def test_eval_pyobjects(): @@ -171,15 +170,4 @@ def test_toPrimitive_stdin(): def test_constructor_stdin(): constructor = pm.eval("(obj) => { return obj.constructor; }")(sys.stdin) - assert repr(constructor).__contains__(" Date: Thu, 25 Jul 2024 12:54:58 -0400 Subject: [PATCH 173/428] Introducing proxy for python bytes --- include/PyBaseProxyHandler.hh | 2 +- include/PyBytesProxyHandler.hh | 45 +++++ src/BufferType.cc | 118 ++++++++----- src/PyBytesProxyHandler.cc | 215 ++++++++++++++++++++++++ src/pyTypeFactory.cc | 4 +- tests/python/test_buffer_typed_array.py | 66 ++++++-- 6 files changed, 394 insertions(+), 56 deletions(-) create mode 100644 include/PyBytesProxyHandler.hh create mode 100644 src/PyBytesProxyHandler.cc diff --git a/include/PyBaseProxyHandler.hh b/include/PyBaseProxyHandler.hh index 0634728a..637a0300 100644 --- a/include/PyBaseProxyHandler.hh +++ b/include/PyBaseProxyHandler.hh @@ -30,7 +30,7 @@ public: bool isExtensible(JSContext *cx, JS::HandleObject proxy, bool *extensible) const override final; }; -enum ProxySlots {PyObjectSlot}; +enum ProxySlots {PyObjectSlot, OtherSlot}; typedef struct { const char *name; /* The name of the method */ diff --git a/include/PyBytesProxyHandler.hh b/include/PyBytesProxyHandler.hh new file mode 100644 index 00000000..b29227e6 --- /dev/null +++ b/include/PyBytesProxyHandler.hh @@ -0,0 +1,45 @@ +/** + * @file PyBytesProxyHandler.hh + * @author Philippe Laporte (philippe@distributive.network) + * @brief Struct for creating JS proxy objects for immutable bytes objects + * @date 2024-07-23 + * + * @copyright Copyright (c) 2024 Distributive Corp. + * + */ + +#ifndef PythonMonkey_PyBytesProxy_ +#define PythonMonkey_PyBytesProxy_ + + +#include "include/PyObjectProxyHandler.hh" + + +/** + * @brief This struct is the ProxyHandler for JS Proxy Iterable pythonmonkey creates to handle coercion from python iterables to JS Objects + * + */ +struct PyBytesProxyHandler : public PyObjectProxyHandler { +public: + PyBytesProxyHandler() : PyObjectProxyHandler(&family) {}; + static const char family; + + bool set(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, + JS::HandleValue v, JS::HandleValue receiver, + JS::ObjectOpResult &result) const override; + + bool getOwnPropertyDescriptor( + JSContext *cx, JS::HandleObject proxy, JS::HandleId id, + JS::MutableHandle> desc + ) const override; + + void finalize(JS::GCContext *gcx, JSObject *proxy) const override; + + /** + * @brief An array of method definitions for bytes prototype methods + * + */ + static JSMethodDef bytes_methods[]; +}; + +#endif \ No newline at end of file diff --git a/src/BufferType.cc b/src/BufferType.cc index 0ee2ec63..8fd6fa81 100644 --- a/src/BufferType.cc +++ b/src/BufferType.cc @@ -9,7 +9,7 @@ */ #include "include/BufferType.hh" - +#include "include/PyBytesProxyHandler.hh" #include #include @@ -17,6 +17,45 @@ #include +// JS to Python + +/* static */ +const char *BufferType::_toPyBufferFormatCode(JS::Scalar::Type subtype) { + // floating point types + if (subtype == JS::Scalar::Float32) { + return "f"; + } else if (subtype == JS::Scalar::Float64) { + return "d"; + } + + // integer types + bool isSigned = JS::Scalar::isSignedIntType(subtype); + uint8_t byteSize = JS::Scalar::byteSize(subtype); + // Python `array` type codes are strictly mapped to basic C types (e.g., `int`), widths may vary on different architectures, + // but JS TypedArray uses fixed-width integer types (e.g., `uint32_t`) + switch (byteSize) { + case sizeof(char): + return isSigned ? "b" : "B"; + case sizeof(short): + return isSigned ? "h" : "H"; + case sizeof(int): + return isSigned ? "i" : "I"; + // case sizeof(long): // compile error: duplicate case value + // // And this is usually where the bit widths on 32/64-bit systems don't agree, + // // see https://en.wikipedia.org/wiki/64-bit_computing#64-bit_data_models + // return isSigned ? "l" : "L"; + case sizeof(long long): + return isSigned ? "q" : "Q"; + default: // invalid + return "x"; // type code for pad bytes, no value + } +} + +/* static */ +bool BufferType::isSupportedJsTypes(JSObject *obj) { + return JS::IsArrayBufferObject(obj) || JS_IsTypedArrayObject(obj); +} + PyObject *BufferType::getPyObject(JSContext *cx, JS::HandleObject bufObj) { PyObject *pyObject; if (JS_IsTypedArrayObject(bufObj)) { @@ -32,11 +71,6 @@ PyObject *BufferType::getPyObject(JSContext *cx, JS::HandleObject bufObj) { return pyObject; } -/* static */ -bool BufferType::isSupportedJsTypes(JSObject *obj) { - return JS::IsArrayBufferObject(obj) || JS_IsTypedArrayObject(obj); -} - /* static */ PyObject *BufferType::fromJsTypedArray(JSContext *cx, JS::HandleObject typedArray) { JS::Scalar::Type subtype = JS_GetArrayBufferViewType(typedArray); @@ -90,16 +124,31 @@ PyObject *BufferType::fromJsArrayBuffer(JSContext *cx, JS::HandleObject arrayBuf return PyMemoryView_FromBuffer(&bufInfo); } + +// Python to JS + +static PyBytesProxyHandler pyBytesProxyHandler; + + JSObject *BufferType::toJsTypedArray(JSContext *cx, PyObject *pyObject) { - Py_INCREF(pyObject); + Py_INCREF(pyObject); // TODO remove // Get the pyObject's underlying buffer pointer and size Py_buffer *view = new Py_buffer{}; + bool immutable = false; if (PyObject_GetBuffer(pyObject, view, PyBUF_ND | PyBUF_WRITABLE /* C-contiguous and writable */ | PyBUF_FORMAT) < 0) { + // the buffer is immutable (e.g., Python `bytes` type is read-only) - return nullptr; // raises a PyExc_BufferError + PyErr_Clear(); // a PyExc_BufferError was raised + + if (PyObject_GetBuffer(pyObject, view, PyBUF_ND /* C-contiguous and writable */ | PyBUF_FORMAT) < 0) { + return nullptr; // and a PyExc_BufferError was raised again + } + + immutable = true; } - if (view->ndim != 1) { + + if (view->ndim != 1 && !immutable) { PyErr_SetString(PyExc_BufferError, "multidimensional arrays are not allowed"); BufferType::_releasePyBuffer(view); return nullptr; @@ -108,7 +157,7 @@ JSObject *BufferType::toJsTypedArray(JSContext *cx, PyObject *pyObject) { // Determine the TypedArray's subtype (Uint8Array, Float64Array, ...) JS::Scalar::Type subtype = _getPyBufferType(view); - JSObject *arrayBuffer = nullptr; + JSObject *arrayBuffer; if (view->len > 0) { // Create a new ExternalArrayBuffer object // Note: data will be copied instead of transferring the ownership when this external ArrayBuffer is "transferred" to a worker thread. @@ -117,6 +166,7 @@ JSObject *BufferType::toJsTypedArray(JSContext *cx, PyObject *pyObject) { view->buf /* data pointer */, {BufferType::_releasePyBuffer, view /* the `bufView` argument to `_releasePyBuffer` */} ); + arrayBuffer = JS::NewExternalArrayBuffer(cx, view->len /* byteLength */, std::move(dataPtr) ); @@ -124,9 +174,21 @@ JSObject *BufferType::toJsTypedArray(JSContext *cx, PyObject *pyObject) { arrayBuffer = JS::NewArrayBuffer(cx, 0); BufferType::_releasePyBuffer(view); // the buffer is no longer needed since we are creating a brand new empty ArrayBuffer } - JS::RootedObject arrayBufferRooted(cx, arrayBuffer); - return _newTypedArrayWithBuffer(cx, subtype, arrayBufferRooted); + if (!immutable) { + JS::RootedObject arrayBufferRooted(cx, arrayBuffer); + return _newTypedArrayWithBuffer(cx, subtype, arrayBufferRooted); + } else { + JS::RootedValue v(cx); + JS::RootedObject uint8ArrayPrototype(cx); + JS_GetClassPrototype(cx, JSProto_Uint8Array, &uint8ArrayPrototype); // so that instanceof will work, not that prototype methods will TEST THIS + JSObject *proxy = js::NewProxyObject(cx, &pyBytesProxyHandler, v, uint8ArrayPrototype.get()); + JS::SetReservedSlot(proxy, PyObjectSlot, JS::PrivateValue(pyObject)); + JS::PersistentRootedObject *arrayBufferPointer = new JS::PersistentRootedObject(cx); + arrayBufferPointer->set(arrayBuffer); + JS::SetReservedSlot(proxy, OtherSlot, JS::PrivateValue(arrayBufferPointer)); + return proxy; + } } /* static */ @@ -178,38 +240,6 @@ JS::Scalar::Type BufferType::_getPyBufferType(Py_buffer *bufView) { } } -/* static */ -const char *BufferType::_toPyBufferFormatCode(JS::Scalar::Type subtype) { - // floating point types - if (subtype == JS::Scalar::Float32) { - return "f"; - } else if (subtype == JS::Scalar::Float64) { - return "d"; - } - - // integer types - bool isSigned = JS::Scalar::isSignedIntType(subtype); - uint8_t byteSize = JS::Scalar::byteSize(subtype); - // Python `array` type codes are strictly mapped to basic C types (e.g., `int`), widths may vary on different architectures, - // but JS TypedArray uses fixed-width integer types (e.g., `uint32_t`) - switch (byteSize) { - case sizeof(char): - return isSigned ? "b" : "B"; - case sizeof(short): - return isSigned ? "h" : "H"; - case sizeof(int): - return isSigned ? "i" : "I"; - // case sizeof(long): // compile error: duplicate case value - // // And this is usually where the bit widths on 32/64-bit systems don't agree, - // // see https://en.wikipedia.org/wiki/64-bit_computing#64-bit_data_models - // return isSigned ? "l" : "L"; - case sizeof(long long): - return isSigned ? "q" : "Q"; - default: // invalid - return "x"; // type code for pad bytes, no value - } -} - JSObject *BufferType::_newTypedArrayWithBuffer(JSContext *cx, JS::Scalar::Type subtype, JS::HandleObject arrayBuffer) { switch (subtype) { #define NEW_TYPED_ARRAY_WITH_BUFFER(ExternalType, NativeType, Name) \ diff --git a/src/PyBytesProxyHandler.cc b/src/PyBytesProxyHandler.cc new file mode 100644 index 00000000..d731ad85 --- /dev/null +++ b/src/PyBytesProxyHandler.cc @@ -0,0 +1,215 @@ +/** + * @file PyBytesProxyHandler.cc + * @author Philippe Laporte (philippe@distributive.network) + * @brief Struct for creating JS proxy objects for immutable bytes objects + * @date 2024-07-23 + * + * @copyright Copyright (c) 2024 Distributive Corp. + * + */ + + +#include "include/PyBytesProxyHandler.hh" + +#include +#include + +#include + + +const char PyBytesProxyHandler::family = 0; + + +static bool bytes_valueOf(JSContext *cx, unsigned argc, JS::Value *vp) { + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); + + JS::RootedObject proxy(cx, JS::ToObject(cx, args.thisv())); + if (!proxy) { + return false; + } + + JS::PersistentRootedObject* arrayBuffer = JS::GetMaybePtrFromReservedSlot(proxy, OtherSlot); + JS::RootedObject rootedArrayBuffer(cx, arrayBuffer->get()); + + auto byteLength = JS::GetArrayBufferByteLength(rootedArrayBuffer); + + bool isSharedMemory; + JS::AutoCheckCannotGC autoNoGC(cx); + uint8_t *data = JS::GetArrayBufferData(rootedArrayBuffer, &isSharedMemory, autoNoGC); + + std::string valueOfString; + + for (Py_ssize_t index = 0; index < byteLength; index++) { + if (index > 0) { + valueOfString += ","; + } + valueOfString += data[index]; + } + + args.rval().setString(JS_NewStringCopyZ(cx, valueOfString.c_str())); + return true; +} + +JSMethodDef PyBytesProxyHandler::bytes_methods[] = { + {"valueOf", bytes_valueOf, 0}, + {NULL, NULL, 0} +}; + + +bool PyBytesProxyHandler::set(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, + JS::HandleValue v, JS::HandleValue receiver, + JS::ObjectOpResult &result) const { + + // block all modifications + + PyObject *self = JS::GetMaybePtrFromReservedSlot(proxy, PyObjectSlot); + + PyErr_Format(PyExc_TypeError, + "'%.100s' object has only read-only attributes", + Py_TYPE(self)->tp_name); + + return result.failReadOnly(); +} + +bool PyBytesProxyHandler::getOwnPropertyDescriptor( + JSContext *cx, JS::HandleObject proxy, JS::HandleId id, + JS::MutableHandle> desc +) const { + // see if we're calling a function + if (id.isString()) { + for (size_t index = 0;; index++) { + bool isThatFunction; + const char *methodName = bytes_methods[index].name; + if (methodName == NULL) { + break; + } + else if (JS_StringEqualsAscii(cx, id.toString(), methodName, &isThatFunction) && isThatFunction) { + JSFunction *newFunction = JS_NewFunction(cx, bytes_methods[index].call, bytes_methods[index].nargs, 0, NULL); + if (!newFunction) return false; + JS::RootedObject funObj(cx, JS_GetFunctionObject(newFunction)); + desc.set(mozilla::Some( + JS::PropertyDescriptor::Data( + JS::ObjectValue(*funObj), + {JS::PropertyAttribute::Enumerable} + ) + )); + return true; + } + } + } + + if (id.isString()) { + bool isProperty; + + // "length" and byteLength properties have the same value + if (((JS_StringEqualsLiteral(cx, id.toString(), "length", &isProperty) && isProperty) || (JS_StringEqualsLiteral(cx, id.toString(), "byteLength", &isProperty) && isProperty))) { + JS::PersistentRootedObject* arrayBuffer = JS::GetMaybePtrFromReservedSlot(proxy, OtherSlot); + + JS::RootedObject rootedArrayBuffer(cx, arrayBuffer->get()); + + auto byteLength = JS::GetArrayBufferByteLength(rootedArrayBuffer); + + desc.set(mozilla::Some( + JS::PropertyDescriptor::Data( + JS::Int32Value(byteLength) + ) + )); + return true; + } + + // buffer property + if (JS_StringEqualsLiteral(cx, id.toString(), "buffer", &isProperty) && isProperty) { + JS::PersistentRootedObject* arrayBuffer = JS::GetMaybePtrFromReservedSlot(proxy, OtherSlot); + + desc.set(mozilla::Some( + JS::PropertyDescriptor::Data( + JS::ObjectValue(*(arrayBuffer->get())) + ) + )); + return true; + } + + // BYTES_PER_ELEMENT property + if (JS_StringEqualsLiteral(cx, id.toString(), "BYTES_PER_ELEMENT", &isProperty) && isProperty) { + desc.set(mozilla::Some( + JS::PropertyDescriptor::Data( + JS::Int32Value(1) + ) + )); + return true; + } + + // byteOffset property + if (JS_StringEqualsLiteral(cx, id.toString(), "byteOffset", &isProperty) && isProperty) { + desc.set(mozilla::Some( + JS::PropertyDescriptor::Data( + JS::Int32Value(0) + ) + )); + return true; + } + } + + // "constructor" property + bool isConstructorProperty; + if (id.isString() && JS_StringEqualsLiteral(cx, id.toString(), "constructor", &isConstructorProperty) && isConstructorProperty) { + JS::RootedObject global(cx, JS::GetNonCCWObjectGlobal(proxy)); + + JS::RootedObject uint8ArrayPrototype(cx); + if (!JS_GetClassPrototype(cx, JSProto_Uint8Array, &uint8ArrayPrototype)) { + return false; + } + + JS::RootedValue Uint8Array_Prototype_Constructor(cx); + if (!JS_GetProperty(cx, uint8ArrayPrototype, "constructor", &Uint8Array_Prototype_Constructor)) { + return false; + } + + JS::RootedObject rootedUint8ArrayPrototypeConstructor(cx, Uint8Array_Prototype_Constructor.toObjectOrNull()); + + desc.set(mozilla::Some( + JS::PropertyDescriptor::Data( + JS::ObjectValue(*rootedUint8ArrayPrototypeConstructor), + {JS::PropertyAttribute::Enumerable} + ) + )); + + return true; + } + + if (id.isSymbol()) { + return true; // needed for console.log + } + + // item + Py_ssize_t index; + if (idToIndex(cx, id, &index)) { + JS::PersistentRootedObject* arrayBuffer = JS::GetMaybePtrFromReservedSlot(proxy, OtherSlot); + JS::RootedObject rootedArrayBuffer(cx, arrayBuffer->get()); + + bool isSharedMemory; + JS::AutoCheckCannotGC autoNoGC(cx); + uint8_t *data = JS::GetArrayBufferData(rootedArrayBuffer, &isSharedMemory, autoNoGC); + + desc.set(mozilla::Some( + JS::PropertyDescriptor::Data( + JS::Int32Value(data[index]) + ) + )); + + return true; + } + + PyObject *attrName = idToKey(cx, id); + PyObject *self = JS::GetMaybePtrFromReservedSlot(proxy, PyObjectSlot); + PyObject *item = PyObject_GetAttr(self, attrName); + + return handleGetOwnPropertyDescriptor(cx, id, desc, item); +} + +void PyBytesProxyHandler::finalize(JS::GCContext *gcx, JSObject *proxy) const { + PyObjectProxyHandler::finalize(gcx, proxy); + + JS::PersistentRootedObject *arrayBuffer = JS::GetMaybePtrFromReservedSlot(proxy, OtherSlot); + delete arrayBuffer; +} \ No newline at end of file diff --git a/src/pyTypeFactory.cc b/src/pyTypeFactory.cc index 62212ee4..c11f0c1f 100644 --- a/src/pyTypeFactory.cc +++ b/src/pyTypeFactory.cc @@ -27,6 +27,7 @@ #include "include/PyListProxyHandler.hh" #include "include/PyObjectProxyHandler.hh" #include "include/PyIterableProxyHandler.hh" +#include "include/PyBytesProxyHandler.hh" #include "include/setSpiderMonkeyException.hh" #include "include/StrType.hh" #include "include/modules/pythonmonkey/pythonmonkey.hh" @@ -68,7 +69,8 @@ PyObject *pyTypeFactory(JSContext *cx, JS::HandleValue rval) { if (js::GetProxyHandler(obj)->family() == &PyDictProxyHandler::family || // this is one of our proxies for python dicts js::GetProxyHandler(obj)->family() == &PyListProxyHandler::family || // this is one of our proxies for python lists js::GetProxyHandler(obj)->family() == &PyIterableProxyHandler::family || // this is one of our proxies for python iterables - js::GetProxyHandler(obj)->family() == &PyObjectProxyHandler::family) { // this is one of our proxies for python objects + js::GetProxyHandler(obj)->family() == &PyObjectProxyHandler::family || // this is one of our proxies for python iterables + js::GetProxyHandler(obj)->family() == &PyBytesProxyHandler::family) { // this is one of our proxies for python bytes objects PyObject *pyObject = JS::GetMaybePtrFromReservedSlot(obj, PyObjectSlot); Py_INCREF(pyObject); diff --git a/tests/python/test_buffer_typed_array.py b/tests/python/test_buffer_typed_array.py index dabc8c61..caf13cb1 100644 --- a/tests/python/test_buffer_typed_array.py +++ b/tests/python/test_buffer_typed_array.py @@ -4,6 +4,8 @@ import numpy import array import struct +from io import StringIO +import sys def test_py_buffer_to_js_typed_array(): @@ -189,16 +191,6 @@ def assert_empty_arraybuffer(buf): # TODO (Tom Tang): error for detached ArrayBuffer, or should it be considered as empty? - # should error on immutable Python buffers - # Note: Python `bytes` type must be converted to a (mutable) `bytearray` - # because there's no such a concept of read-only ArrayBuffer in JS - with pytest.raises(BufferError, match="Object is not writable."): - pm.eval("(typedArray) => {}")(b'') - immutable_numpy_array = numpy.arange(10) - immutable_numpy_array.setflags(write=False) - with pytest.raises(ValueError, match="buffer source array is read-only"): - pm.eval("(typedArray) => {}")(immutable_numpy_array) - # buffer should be in C order (row major) # 1-D array is always considered C-contiguous because it doesn't matter if it's row or column major in 1-D fortran_order_arr = numpy.array([[1, 2], [3, 4]], order="F") @@ -209,3 +201,57 @@ def assert_empty_arraybuffer(buf): numpy_2d_array = numpy.array([[1, 2], [3, 4]], order="C") with pytest.raises(BufferError, match="multidimensional arrays are not allowed"): pm.eval("(typedArray) => {}")(numpy_2d_array) + + + +def test_bytes_proxy_write(): + with pytest.raises(TypeError, match="'bytes' object has only read-only attributes"): + pm.eval('(bytes) => bytes[0] = 5')(bytes("hello world", "ascii")) + + +def test_bytes_get_index_python(): + b = pm.eval('(bytes) => bytes')(bytes("hello world", "ascii")) + assert b[0] == 104 + + +def test_bytes_get_index_js(): + b = pm.eval('(bytes) => bytes[1]')(bytes("hello world", "ascii")) + assert b == 101.0 + + +def test_bytes_bytes_per_element(): + b = pm.eval('(bytes) => bytes.BYTES_PER_ELEMENT')(bytes("hello world", "ascii")) + assert b == 1.0 + + +def test_bytes_buffer(): + b = pm.eval('(bytes) => bytes.buffer')(bytes("hello world", "ascii")) + assert repr(b).__contains__("memory at") + assert b[2] == 108 + + +def test_bytes_length(): + b = pm.eval('(bytes) => bytes.length')(bytes("hello world", "ascii")) + assert b == 11.0 + +def test_bytes_bytelength(): + b = pm.eval('(bytes) => bytes.byteLength')(bytes("hello world", "ascii")) + assert b == 11.0 + + +def test_bytes_byteoffset(): + b = pm.eval('(bytes) => bytes.byteOffset')(bytes("hello world", "ascii")) + assert b == 0.0 + + +def test_bytes_instanceof(): + result = [None] + pm.eval("(result, obj) => {result[0] = obj instanceof Uint8Array}")(result, bytes("hello world", "ascii")) + assert result[0] + + +def test_bytes_console(): + temp_out = StringIO() + sys.stdout = temp_out + pm.eval('console.log')(bytes("hello world", "ascii")) + assert temp_out.getvalue().startswith("{ [String: 'h,e,l,l,o, ,w,o,r,l,d']") \ No newline at end of file From 1330fe03d0070a3da22eaca18d25eb4e8de6d0e8 Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Thu, 25 Jul 2024 12:57:56 -0400 Subject: [PATCH 174/428] cleanup --- src/BufferType.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/BufferType.cc b/src/BufferType.cc index 8fd6fa81..333c0e6c 100644 --- a/src/BufferType.cc +++ b/src/BufferType.cc @@ -131,8 +131,6 @@ static PyBytesProxyHandler pyBytesProxyHandler; JSObject *BufferType::toJsTypedArray(JSContext *cx, PyObject *pyObject) { - Py_INCREF(pyObject); // TODO remove - // Get the pyObject's underlying buffer pointer and size Py_buffer *view = new Py_buffer{}; bool immutable = false; From 3a8a2e3b26b942826f4ea50c5559d7ebf1bf7b70 Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Thu, 25 Jul 2024 12:59:24 -0400 Subject: [PATCH 175/428] proper cleanup --- src/BufferType.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/BufferType.cc b/src/BufferType.cc index 333c0e6c..9bdd69de 100644 --- a/src/BufferType.cc +++ b/src/BufferType.cc @@ -131,6 +131,8 @@ static PyBytesProxyHandler pyBytesProxyHandler; JSObject *BufferType::toJsTypedArray(JSContext *cx, PyObject *pyObject) { + Py_INCREF(pyObject); + // Get the pyObject's underlying buffer pointer and size Py_buffer *view = new Py_buffer{}; bool immutable = false; From 6e80c3121e228d5972184324b8d5647e4e6051ba Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Thu, 25 Jul 2024 13:01:13 -0400 Subject: [PATCH 176/428] improved comments --- src/BufferType.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/BufferType.cc b/src/BufferType.cc index 9bdd69de..66b8f9de 100644 --- a/src/BufferType.cc +++ b/src/BufferType.cc @@ -137,12 +137,11 @@ JSObject *BufferType::toJsTypedArray(JSContext *cx, PyObject *pyObject) { Py_buffer *view = new Py_buffer{}; bool immutable = false; if (PyObject_GetBuffer(pyObject, view, PyBUF_ND | PyBUF_WRITABLE /* C-contiguous and writable */ | PyBUF_FORMAT) < 0) { - // the buffer is immutable (e.g., Python `bytes` type is read-only) PyErr_Clear(); // a PyExc_BufferError was raised if (PyObject_GetBuffer(pyObject, view, PyBUF_ND /* C-contiguous and writable */ | PyBUF_FORMAT) < 0) { - return nullptr; // and a PyExc_BufferError was raised again + return nullptr; // a PyExc_BufferError was raised again } immutable = true; From bf2465105ed13f14dc480046eb4a58c46183c2d6 Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Thu, 25 Jul 2024 13:04:28 -0400 Subject: [PATCH 177/428] logic improvement --- src/PyBytesProxyHandler.cc | 41 +++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/src/PyBytesProxyHandler.cc b/src/PyBytesProxyHandler.cc index d731ad85..c161e570 100644 --- a/src/PyBytesProxyHandler.cc +++ b/src/PyBytesProxyHandler.cc @@ -148,33 +148,32 @@ bool PyBytesProxyHandler::getOwnPropertyDescriptor( )); return true; } - } - // "constructor" property - bool isConstructorProperty; - if (id.isString() && JS_StringEqualsLiteral(cx, id.toString(), "constructor", &isConstructorProperty) && isConstructorProperty) { - JS::RootedObject global(cx, JS::GetNonCCWObjectGlobal(proxy)); + // "constructor" property + if (JS_StringEqualsLiteral(cx, id.toString(), "constructor", &isProperty) && isProperty) { + JS::RootedObject global(cx, JS::GetNonCCWObjectGlobal(proxy)); - JS::RootedObject uint8ArrayPrototype(cx); - if (!JS_GetClassPrototype(cx, JSProto_Uint8Array, &uint8ArrayPrototype)) { - return false; - } + JS::RootedObject uint8ArrayPrototype(cx); + if (!JS_GetClassPrototype(cx, JSProto_Uint8Array, &uint8ArrayPrototype)) { + return false; + } - JS::RootedValue Uint8Array_Prototype_Constructor(cx); - if (!JS_GetProperty(cx, uint8ArrayPrototype, "constructor", &Uint8Array_Prototype_Constructor)) { - return false; - } + JS::RootedValue Uint8Array_Prototype_Constructor(cx); + if (!JS_GetProperty(cx, uint8ArrayPrototype, "constructor", &Uint8Array_Prototype_Constructor)) { + return false; + } - JS::RootedObject rootedUint8ArrayPrototypeConstructor(cx, Uint8Array_Prototype_Constructor.toObjectOrNull()); + JS::RootedObject rootedUint8ArrayPrototypeConstructor(cx, Uint8Array_Prototype_Constructor.toObjectOrNull()); - desc.set(mozilla::Some( - JS::PropertyDescriptor::Data( - JS::ObjectValue(*rootedUint8ArrayPrototypeConstructor), - {JS::PropertyAttribute::Enumerable} - ) - )); + desc.set(mozilla::Some( + JS::PropertyDescriptor::Data( + JS::ObjectValue(*rootedUint8ArrayPrototypeConstructor), + {JS::PropertyAttribute::Enumerable} + ) + )); - return true; + return true; + } } if (id.isSymbol()) { From 38e94ed9236caf77a28004943cd8ad9d1d879cf0 Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Thu, 25 Jul 2024 14:14:47 -0400 Subject: [PATCH 178/428] added toString support --- src/PyBytesProxyHandler.cc | 5 +++++ src/PyObjectProxyHandler.cc | 1 + tests/python/test_buffer_typed_array.py | 12 +++++++++++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/PyBytesProxyHandler.cc b/src/PyBytesProxyHandler.cc index c161e570..0148f157 100644 --- a/src/PyBytesProxyHandler.cc +++ b/src/PyBytesProxyHandler.cc @@ -50,7 +50,12 @@ static bool bytes_valueOf(JSContext *cx, unsigned argc, JS::Value *vp) { return true; } +static bool bytes_toString(JSContext *cx, unsigned argc, JS::Value *vp) { + return bytes_valueOf(cx, argc, vp); +} + JSMethodDef PyBytesProxyHandler::bytes_methods[] = { + {"toString", bytes_toString, 0}, {"valueOf", bytes_valueOf, 0}, {NULL, NULL, 0} }; diff --git a/src/PyObjectProxyHandler.cc b/src/PyObjectProxyHandler.cc index 270f6124..4c27c3fb 100644 --- a/src/PyObjectProxyHandler.cc +++ b/src/PyObjectProxyHandler.cc @@ -72,6 +72,7 @@ bool PyObjectProxyHandler::handleOwnPropertyKeys(JSContext *cx, PyObject *keys, return true; } +// TODO need to let subclasses call superclass methods bool PyObjectProxyHandler::handleGetOwnPropertyDescriptor(JSContext *cx, JS::HandleId id, JS::MutableHandle> desc, PyObject *item) { // see if we're calling a function diff --git a/tests/python/test_buffer_typed_array.py b/tests/python/test_buffer_typed_array.py index caf13cb1..16f93c84 100644 --- a/tests/python/test_buffer_typed_array.py +++ b/tests/python/test_buffer_typed_array.py @@ -246,10 +246,20 @@ def test_bytes_byteoffset(): def test_bytes_instanceof(): result = [None] - pm.eval("(result, obj) => {result[0] = obj instanceof Uint8Array}")(result, bytes("hello world", "ascii")) + pm.eval("(result, bytes) => {result[0] = bytes instanceof Uint8Array}")(result, bytes("hello world", "ascii")) assert result[0] +def test_bytes_valueOf(): + a = pm.eval('(bytes) => bytes.valueOf()')(bytes("hello world", "ascii")) + assert a == "h,e,l,l,o, ,w,o,r,l,d" + + +def test_bytes_toString(): + a = pm.eval('(bytes) => bytes.toString()')(bytes("hello world", "ascii")) + assert a == "h,e,l,l,o, ,w,o,r,l,d" + + def test_bytes_console(): temp_out = StringIO() sys.stdout = temp_out From 02e85662a7bf4376e36809ebf09dd519001e1fe3 Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Thu, 25 Jul 2024 15:09:03 -0400 Subject: [PATCH 179/428] implement iteration on bytes object --- include/PyBytesProxyHandler.hh | 4 +- src/PyBytesProxyHandler.cc | 213 +++++++++++++++++++++++- tests/python/test_buffer_typed_array.py | 132 ++++++++++++++- 3 files changed, 337 insertions(+), 12 deletions(-) diff --git a/include/PyBytesProxyHandler.hh b/include/PyBytesProxyHandler.hh index b29227e6..bd9dd83c 100644 --- a/include/PyBytesProxyHandler.hh +++ b/include/PyBytesProxyHandler.hh @@ -1,7 +1,7 @@ /** * @file PyBytesProxyHandler.hh * @author Philippe Laporte (philippe@distributive.network) - * @brief Struct for creating JS proxy objects for immutable bytes objects + * @brief Struct for creating JS Uint8Array-like proxy objects for immutable bytes objects * @date 2024-07-23 * * @copyright Copyright (c) 2024 Distributive Corp. @@ -39,7 +39,7 @@ public: * @brief An array of method definitions for bytes prototype methods * */ - static JSMethodDef bytes_methods[]; + static JSMethodDef array_methods[]; }; #endif \ No newline at end of file diff --git a/src/PyBytesProxyHandler.cc b/src/PyBytesProxyHandler.cc index 0148f157..014ee606 100644 --- a/src/PyBytesProxyHandler.cc +++ b/src/PyBytesProxyHandler.cc @@ -1,7 +1,7 @@ /** * @file PyBytesProxyHandler.cc * @author Philippe Laporte (philippe@distributive.network) - * @brief Struct for creating JS proxy objects for immutable bytes objects + * @brief Struct for creating JS Uint8Array-like proxy objects for immutable bytes objects * @date 2024-07-23 * * @copyright Copyright (c) 2024 Distributive Corp. @@ -20,7 +20,7 @@ const char PyBytesProxyHandler::family = 0; -static bool bytes_valueOf(JSContext *cx, unsigned argc, JS::Value *vp) { +static bool array_valueOf(JSContext *cx, unsigned argc, JS::Value *vp) { JS::CallArgs args = JS::CallArgsFromVp(argc, vp); JS::RootedObject proxy(cx, JS::ToObject(cx, args.thisv())); @@ -50,13 +50,193 @@ static bool bytes_valueOf(JSContext *cx, unsigned argc, JS::Value *vp) { return true; } -static bool bytes_toString(JSContext *cx, unsigned argc, JS::Value *vp) { - return bytes_valueOf(cx, argc, vp); +static bool array_toString(JSContext *cx, unsigned argc, JS::Value *vp) { + return array_valueOf(cx, argc, vp); } -JSMethodDef PyBytesProxyHandler::bytes_methods[] = { - {"toString", bytes_toString, 0}, - {"valueOf", bytes_valueOf, 0}, + +// BytesIterator + + +#define ITEM_KIND_KEY 0 +#define ITEM_KIND_VALUE 1 +#define ITEM_KIND_KEY_AND_VALUE 2 + +enum { + BytesIteratorSlotIteratedObject, + BytesIteratorSlotNextIndex, + BytesIteratorSlotItemKind, + BytesIteratorSlotCount +}; + +static JSClass bytesIteratorClass = {"BytesIterator", JSCLASS_HAS_RESERVED_SLOTS(BytesIteratorSlotCount)}; + +static bool iterator_next(JSContext *cx, unsigned argc, JS::Value *vp) { + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); + JS::RootedObject thisObj(cx); + if (!args.computeThis(cx, &thisObj)) return false; + + JS::PersistentRootedObject* arrayBuffer = JS::GetMaybePtrFromReservedSlot(thisObj, BytesIteratorSlotIteratedObject); + JS::RootedObject rootedArrayBuffer(cx, arrayBuffer->get()); + + JS::RootedValue rootedNextIndex(cx, JS::GetReservedSlot(thisObj, BytesIteratorSlotNextIndex)); + JS::RootedValue rootedItemKind(cx, JS::GetReservedSlot(thisObj, BytesIteratorSlotItemKind)); + + int32_t nextIndex; + int32_t itemKind; + if (!JS::ToInt32(cx, rootedNextIndex, &nextIndex) || !JS::ToInt32(cx, rootedItemKind, &itemKind)) return false; + + JS::RootedObject result(cx, JS_NewPlainObject(cx)); + + Py_ssize_t len = JS::GetArrayBufferByteLength(rootedArrayBuffer); + + if (nextIndex >= len) { + // UnsafeSetReservedSlot(obj, ITERATOR_SLOT_TARGET, null); // TODO lose ref + JS::RootedValue done(cx, JS::BooleanValue(true)); + if (!JS_SetProperty(cx, result, "done", done)) return false; + args.rval().setObject(*result); + return result; + } + + JS::SetReservedSlot(thisObj, BytesIteratorSlotNextIndex, JS::Int32Value(nextIndex + 1)); + + JS::RootedValue done(cx, JS::BooleanValue(false)); + if (!JS_SetProperty(cx, result, "done", done)) return false; + + if (itemKind == ITEM_KIND_VALUE) { + bool isSharedMemory; + JS::AutoCheckCannotGC autoNoGC(cx); + uint8_t *data = JS::GetArrayBufferData(rootedArrayBuffer, &isSharedMemory, autoNoGC); + + JS::RootedValue value(cx, JS::Int32Value(data[nextIndex])); + if (!JS_SetProperty(cx, result, "value", value)) return false; + } + else if (itemKind == ITEM_KIND_KEY_AND_VALUE) { + JS::Rooted> items(cx); + + JS::RootedValue rootedNextIndex(cx, JS::Int32Value(nextIndex)); + items[0].set(rootedNextIndex); + + bool isSharedMemory; + JS::AutoCheckCannotGC autoNoGC(cx); + uint8_t *data = JS::GetArrayBufferData(rootedArrayBuffer, &isSharedMemory, autoNoGC); + + JS::RootedValue value(cx, JS::Int32Value(data[nextIndex])); + items[1].set(value); + + JS::RootedValue pair(cx); + JSObject *array = JS::NewArrayObject(cx, items); + pair.setObject(*array); + if (!JS_SetProperty(cx, result, "value", pair)) return false; + } + else { // itemKind == ITEM_KIND_KEY + JS::RootedValue value(cx, JS::Int32Value(nextIndex)); + if (!JS_SetProperty(cx, result, "value", value)) return false; + } + + args.rval().setObject(*result); + return true; +} + +static JSFunctionSpec bytes_iterator_methods[] = { + JS_FN("next", iterator_next, 0, JSPROP_ENUMERATE), + JS_FS_END +}; + +static bool BytesIteratorConstructor(JSContext *cx, unsigned argc, JS::Value *vp) { + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); + + if (!args.isConstructing()) { + JS_ReportErrorASCII(cx, "You must call this constructor with 'new'"); + return false; + } + + JS::RootedObject thisObj(cx, JS_NewObjectForConstructor(cx, &bytesIteratorClass, args)); + if (!thisObj) { + return false; + } + + args.rval().setObject(*thisObj); + return true; +} + +static bool DefineBytesIterator(JSContext *cx, JS::HandleObject global) { + JS::RootedObject iteratorPrototype(cx); + if (!JS_GetClassPrototype(cx, JSProto_Iterator, &iteratorPrototype)) { + return false; + } + + JS::RootedObject protoObj(cx, + JS_InitClass(cx, global, + nullptr, iteratorPrototype, + "BytesIterator", + BytesIteratorConstructor, 0, + nullptr, bytes_iterator_methods, + nullptr, nullptr) + ); + + return protoObj; // != nullptr +} + +/// private util +static bool array_iterator_func(JSContext *cx, unsigned argc, JS::Value *vp, int itemKind) { + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); + + JS::RootedObject proxy(cx, JS::ToObject(cx, args.thisv())); + if (!proxy) { + return false; + } + + JS::RootedObject global(cx, JS::GetNonCCWObjectGlobal(proxy)); + + JS::RootedValue constructor_val(cx); + if (!JS_GetProperty(cx, global, "BytesIterator", &constructor_val)) return false; + if (!constructor_val.isObject()) { + if (!DefineBytesIterator(cx, global)) { + return false; + } + + if (!JS_GetProperty(cx, global, "BytesIterator", &constructor_val)) return false; + if (!constructor_val.isObject()) { + JS_ReportErrorASCII(cx, "BytesIterator is not a constructor"); + return false; + } + } + JS::RootedObject constructor(cx, &constructor_val.toObject()); + + JS::RootedObject obj(cx); + if (!JS::Construct(cx, constructor_val, JS::HandleValueArray::empty(), &obj)) return false; + if (!obj) return false; + + JS::PersistentRootedObject* arrayBuffer = JS::GetMaybePtrFromReservedSlot(proxy, OtherSlot); + + JS::SetReservedSlot(obj, BytesIteratorSlotIteratedObject, JS::PrivateValue(arrayBuffer)); + JS::SetReservedSlot(obj, BytesIteratorSlotNextIndex, JS::Int32Value(0)); + JS::SetReservedSlot(obj, BytesIteratorSlotItemKind, JS::Int32Value(itemKind)); + + args.rval().setObject(*obj); + return true; +} + +static bool array_entries(JSContext *cx, unsigned argc, JS::Value *vp) { + return array_iterator_func(cx, argc, vp, ITEM_KIND_KEY_AND_VALUE); +} + +static bool array_keys(JSContext *cx, unsigned argc, JS::Value *vp) { + return array_iterator_func(cx, argc, vp, ITEM_KIND_KEY); +} + +static bool array_values(JSContext *cx, unsigned argc, JS::Value *vp) { + return array_iterator_func(cx, argc, vp, ITEM_KIND_VALUE); +} + + +JSMethodDef PyBytesProxyHandler::array_methods[] = { + {"toString", array_toString, 0}, + {"valueOf", array_valueOf, 0}, + {"entries", array_entries, 0}, + {"keys", array_keys, 0}, + {"values", array_values, 0}, {NULL, NULL, 0} }; @@ -84,12 +264,12 @@ bool PyBytesProxyHandler::getOwnPropertyDescriptor( if (id.isString()) { for (size_t index = 0;; index++) { bool isThatFunction; - const char *methodName = bytes_methods[index].name; + const char *methodName = array_methods[index].name; if (methodName == NULL) { break; } else if (JS_StringEqualsAscii(cx, id.toString(), methodName, &isThatFunction) && isThatFunction) { - JSFunction *newFunction = JS_NewFunction(cx, bytes_methods[index].call, bytes_methods[index].nargs, 0, NULL); + JSFunction *newFunction = JS_NewFunction(cx, array_methods[index].call, array_methods[index].nargs, 0, NULL); if (!newFunction) return false; JS::RootedObject funObj(cx, JS_GetFunctionObject(newFunction)); desc.set(mozilla::Some( @@ -182,6 +362,21 @@ bool PyBytesProxyHandler::getOwnPropertyDescriptor( } if (id.isSymbol()) { + JS::RootedSymbol rootedSymbol(cx, id.toSymbol()); + + if (JS::GetSymbolCode(rootedSymbol) == JS::SymbolCode::iterator) { + JSFunction *newFunction = JS_NewFunction(cx, array_values, 0, 0, NULL); + if (!newFunction) return false; + JS::RootedObject funObj(cx, JS_GetFunctionObject(newFunction)); + desc.set(mozilla::Some( + JS::PropertyDescriptor::Data( + JS::ObjectValue(*funObj), + {JS::PropertyAttribute::Enumerable} + ) + )); + return true; + } + return true; // needed for console.log } diff --git a/tests/python/test_buffer_typed_array.py b/tests/python/test_buffer_typed_array.py index 16f93c84..33633761 100644 --- a/tests/python/test_buffer_typed_array.py +++ b/tests/python/test_buffer_typed_array.py @@ -250,6 +250,13 @@ def test_bytes_instanceof(): assert result[0] +def test_constructor_creates_typedarray(): + items = bytes("hello world", "ascii") + result = [0] + pm.eval("(result, arr) => { result[0] = arr.constructor; result[0] = new result[0]; result[0] = result[0] instanceof Uint8Array}")(result, items) + assert result[0] == True + + def test_bytes_valueOf(): a = pm.eval('(bytes) => bytes.valueOf()')(bytes("hello world", "ascii")) assert a == "h,e,l,l,o, ,w,o,r,l,d" @@ -264,4 +271,127 @@ def test_bytes_console(): temp_out = StringIO() sys.stdout = temp_out pm.eval('console.log')(bytes("hello world", "ascii")) - assert temp_out.getvalue().startswith("{ [String: 'h,e,l,l,o, ,w,o,r,l,d']") \ No newline at end of file + assert temp_out.getvalue().startswith("{ [String: 'h,e,l,l,o, ,w,o,r,l,d']") + + +# iterator symbol property + +def test_iterator_type_function(): + items = bytes("hello world", "ascii") + result = [0] + pm.eval("(result, arr) => { result[0] = typeof arr[Symbol.iterator]}")(result, items) + assert result[0] == 'function' + + +def test_iterator_first_next(): + items = bytes("hello world", "ascii") + result = [0] + pm.eval("(result, arr) => { result[0] = arr[Symbol.iterator]().next()}")(result, items) + assert result[0].value == 104.0 + assert not result[0].done + + +def test_iterator_second_next(): + items = bytes("hello world", "ascii") + result = [0] + pm.eval("(result, arr) => { let iterator = arr[Symbol.iterator](); iterator.next(); result[0] = iterator.next()}")( + result, items) + assert result[0].value == 101.0 + assert not result[0].done + + +def test_iterator_last_next(): + items = bytes("hello world", "ascii") + result = [0] + pm.eval(""" + (result, arr) => { + let iterator = arr[Symbol.iterator](); + iterator.next(); + iterator.next(); + iterator.next(); + iterator.next(); + iterator.next(); + iterator.next(); + iterator.next(); + iterator.next(); + iterator.next(); + iterator.next(); + iterator.next(); + result[0] = iterator.next(); + } + """)(result, items) + assert result[0].value is None + assert result[0].done + + +def test_iterator_iterator(): + items = bytes("hell", "ascii") + result = [0] + pm.eval("(result, arr) => {let iter = arr[Symbol.iterator](); let head = iter.next().value; result[0] = [...iter] }")( + result, items) + assert result[0] == [101.0, 108.0, 108.0] + + +# entries + +def test_entries_next(): + items = bytes("abc", "ascii") + result = [0] + pm.eval("(result, arr) => {result[0] = arr.entries(); result[0] = result[0].next().value}")(result, items) + assert items == bytes("abc", "ascii") + assert result[0] == [0, 97.0] + + +def test_entries_next_next(): + items = bytes("abc", "ascii") + result = [0] + pm.eval("(result, arr) => {result[0] = arr.entries(); result[0].next(); result[0] = result[0].next().value}")( + result, items) + assert result[0] == [1, 98.0] + + +def test_entries_next_next_undefined(): + items = bytes("a", "ascii") + result = [0] + pm.eval("(result, arr) => {result[0] = arr.entries(); result[0].next(); result[0] = result[0].next().value}")( + result, items) + assert result[0] is None + + +# keys + + +def test_keys_iterator(): + items = bytes("abc", "ascii") + result = [7, 8, 9] + pm.eval(""" + (result, arr) => { + index = 0; + iterator = arr.keys(); + for (const key of iterator) { + result[index] = key; + index++; + } + } + """)(result, items) + assert result == [0, 1, 2] + + +# values + + +def test_values_iterator(): + items = bytes("abc", "ascii") + result = [7, 8, 9] + pm.eval(""" + (result, arr) => { + index = 0; + iterator = arr.values(); + for (const value of iterator) { + result[index] = value; + index++; + } + } + """)(result, items) + assert result == [97.0, 98.0, 99.0] + assert result is not items \ No newline at end of file From cef3963074d1a6b803d314f104acbca1a0b0bf6e Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Thu, 25 Jul 2024 15:19:53 -0400 Subject: [PATCH 180/428] improve valueOf to print bytes instead their equivalent chars --- src/PyBytesProxyHandler.cc | 3 ++- tests/python/test_buffer_typed_array.py | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/PyBytesProxyHandler.cc b/src/PyBytesProxyHandler.cc index 014ee606..ef5d8891 100644 --- a/src/PyBytesProxyHandler.cc +++ b/src/PyBytesProxyHandler.cc @@ -43,7 +43,8 @@ static bool array_valueOf(JSContext *cx, unsigned argc, JS::Value *vp) { if (index > 0) { valueOfString += ","; } - valueOfString += data[index]; + + valueOfString += std::to_string(data[index]); } args.rval().setString(JS_NewStringCopyZ(cx, valueOfString.c_str())); diff --git a/tests/python/test_buffer_typed_array.py b/tests/python/test_buffer_typed_array.py index 33633761..f804547b 100644 --- a/tests/python/test_buffer_typed_array.py +++ b/tests/python/test_buffer_typed_array.py @@ -259,19 +259,19 @@ def test_constructor_creates_typedarray(): def test_bytes_valueOf(): a = pm.eval('(bytes) => bytes.valueOf()')(bytes("hello world", "ascii")) - assert a == "h,e,l,l,o, ,w,o,r,l,d" + assert a == "104,101,108,108,111,32,119,111,114,108,100" def test_bytes_toString(): a = pm.eval('(bytes) => bytes.toString()')(bytes("hello world", "ascii")) - assert a == "h,e,l,l,o, ,w,o,r,l,d" + assert a == "104,101,108,108,111,32,119,111,114,108,100" def test_bytes_console(): temp_out = StringIO() sys.stdout = temp_out pm.eval('console.log')(bytes("hello world", "ascii")) - assert temp_out.getvalue().startswith("{ [String: 'h,e,l,l,o, ,w,o,r,l,d']") + assert temp_out.getvalue().startswith("\x1b[32m[String: '104,101,108,108,111,32,119,111,114,108,100'") # iterator symbol property From e1bf931ae9c63cfe5f79e94c9bf3d9ca096bd2fe Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Thu, 25 Jul 2024 15:22:05 -0400 Subject: [PATCH 181/428] improved line spacing --- tests/python/test_buffer_typed_array.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/python/test_buffer_typed_array.py b/tests/python/test_buffer_typed_array.py index f804547b..07ea47d9 100644 --- a/tests/python/test_buffer_typed_array.py +++ b/tests/python/test_buffer_typed_array.py @@ -360,7 +360,6 @@ def test_entries_next_next_undefined(): # keys - def test_keys_iterator(): items = bytes("abc", "ascii") result = [7, 8, 9] @@ -379,7 +378,6 @@ def test_keys_iterator(): # values - def test_values_iterator(): items = bytes("abc", "ascii") result = [7, 8, 9] From 57d64f21dd668c8fd1e4d651099918b7c25dc853 Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Thu, 25 Jul 2024 17:06:48 -0400 Subject: [PATCH 182/428] improved test --- tests/python/test_buffer_typed_array.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/python/test_buffer_typed_array.py b/tests/python/test_buffer_typed_array.py index 07ea47d9..33065105 100644 --- a/tests/python/test_buffer_typed_array.py +++ b/tests/python/test_buffer_typed_array.py @@ -271,7 +271,7 @@ def test_bytes_console(): temp_out = StringIO() sys.stdout = temp_out pm.eval('console.log')(bytes("hello world", "ascii")) - assert temp_out.getvalue().startswith("\x1b[32m[String: '104,101,108,108,111,32,119,111,114,108,100'") + assert temp_out.getvalue().__contains__("104,101,108,108,111,32,119,111,114,108,100") # iterator symbol property From b6cd3830dc4f42fc6487bbb8ebe9095d57f52b50 Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Thu, 25 Jul 2024 17:20:07 -0400 Subject: [PATCH 183/428] other symbols are undefined --- src/PyBytesProxyHandler.cc | 5 +++-- tests/python/test_buffer_typed_array.py | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/PyBytesProxyHandler.cc b/src/PyBytesProxyHandler.cc index ef5d8891..f3724171 100644 --- a/src/PyBytesProxyHandler.cc +++ b/src/PyBytesProxyHandler.cc @@ -375,10 +375,11 @@ bool PyBytesProxyHandler::getOwnPropertyDescriptor( {JS::PropertyAttribute::Enumerable} ) )); - return true; + } else { + desc.set(mozilla::Nothing()); } - return true; // needed for console.log + return true; } // item diff --git a/tests/python/test_buffer_typed_array.py b/tests/python/test_buffer_typed_array.py index 33065105..a475c4f8 100644 --- a/tests/python/test_buffer_typed_array.py +++ b/tests/python/test_buffer_typed_array.py @@ -271,7 +271,7 @@ def test_bytes_console(): temp_out = StringIO() sys.stdout = temp_out pm.eval('console.log')(bytes("hello world", "ascii")) - assert temp_out.getvalue().__contains__("104,101,108,108,111,32,119,111,114,108,100") + assert temp_out.getvalue() == "\x1b[32m[String: '104,101,108,108,111,32,119,111,114,108,100']\x1b[39m\n" # iterator symbol property From 51b401d9511ef58b9921e2fcd5f02a4b60a992e7 Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Thu, 25 Jul 2024 17:25:17 -0400 Subject: [PATCH 184/428] comment removed --- src/PyObjectProxyHandler.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/src/PyObjectProxyHandler.cc b/src/PyObjectProxyHandler.cc index 4c27c3fb..270f6124 100644 --- a/src/PyObjectProxyHandler.cc +++ b/src/PyObjectProxyHandler.cc @@ -72,7 +72,6 @@ bool PyObjectProxyHandler::handleOwnPropertyKeys(JSContext *cx, PyObject *keys, return true; } -// TODO need to let subclasses call superclass methods bool PyObjectProxyHandler::handleGetOwnPropertyDescriptor(JSContext *cx, JS::HandleId id, JS::MutableHandle> desc, PyObject *item) { // see if we're calling a function From 59627a1d4fa7cb88e4820022ed3cb93ebf3bcac1 Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Thu, 25 Jul 2024 17:48:14 -0400 Subject: [PATCH 185/428] cleanup unused var --- src/PyBytesProxyHandler.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/PyBytesProxyHandler.cc b/src/PyBytesProxyHandler.cc index f3724171..e0a6328c 100644 --- a/src/PyBytesProxyHandler.cc +++ b/src/PyBytesProxyHandler.cc @@ -337,8 +337,6 @@ bool PyBytesProxyHandler::getOwnPropertyDescriptor( // "constructor" property if (JS_StringEqualsLiteral(cx, id.toString(), "constructor", &isProperty) && isProperty) { - JS::RootedObject global(cx, JS::GetNonCCWObjectGlobal(proxy)); - JS::RootedObject uint8ArrayPrototype(cx); if (!JS_GetClassPrototype(cx, JSProto_Uint8Array, &uint8ArrayPrototype)) { return false; From b6d3a41eaabec158c1d00143e17c786108398fc8 Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Thu, 25 Jul 2024 17:49:19 -0400 Subject: [PATCH 186/428] fixed test --- tests/python/test_buffer_typed_array.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/python/test_buffer_typed_array.py b/tests/python/test_buffer_typed_array.py index a475c4f8..4d34959e 100644 --- a/tests/python/test_buffer_typed_array.py +++ b/tests/python/test_buffer_typed_array.py @@ -271,7 +271,7 @@ def test_bytes_console(): temp_out = StringIO() sys.stdout = temp_out pm.eval('console.log')(bytes("hello world", "ascii")) - assert temp_out.getvalue() == "\x1b[32m[String: '104,101,108,108,111,32,119,111,114,108,100']\x1b[39m\n" + assert temp_out.getvalue().__contains__('104,101,108,108,111,32,119,111,114,108,100') # iterator symbol property From e4a758eeb58c6e1b3310f105234cdfa69305b5e2 Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Thu, 25 Jul 2024 17:59:07 -0400 Subject: [PATCH 187/428] use prototype method defaults for Objects --- src/PyObjectProxyHandler.cc | 69 +++++++++++------------------------- tests/python/test_objects.py | 17 ++++++++- 2 files changed, 37 insertions(+), 49 deletions(-) diff --git a/src/PyObjectProxyHandler.cc b/src/PyObjectProxyHandler.cc index 270f6124..aae9ad94 100644 --- a/src/PyObjectProxyHandler.cc +++ b/src/PyObjectProxyHandler.cc @@ -24,38 +24,6 @@ const char PyObjectProxyHandler::family = 0; -bool PyObjectProxyHandler::object_toString(JSContext *cx, unsigned argc, JS::Value *vp) { - JS::CallArgs args = JS::CallArgsFromVp(argc, vp); - - args.rval().setString(JS_NewStringCopyZ(cx, "[object Object]")); - return true; -} - -bool PyObjectProxyHandler::object_toLocaleString(JSContext *cx, unsigned argc, JS::Value *vp) { - return object_toString(cx, argc, vp); -} - -bool PyObjectProxyHandler::object_valueOf(JSContext *cx, unsigned argc, JS::Value *vp) { - JS::CallArgs args = JS::CallArgsFromVp(argc, vp); - - JS::RootedObject proxy(cx, JS::ToObject(cx, args.thisv())); - if (!proxy) { - return false; - } - PyObject *self = JS::GetMaybePtrFromReservedSlot(proxy, PyObjectSlot); - - // return ref to self - args.rval().set(jsTypeFactory(cx, self)); - return true; -} - -JSMethodDef PyObjectProxyHandler::object_methods[] = { - {"toString", PyObjectProxyHandler::object_toString, 0}, - {"toLocaleString", PyObjectProxyHandler::object_toLocaleString, 0}, - {"valueOf", PyObjectProxyHandler::object_valueOf, 0}, - {NULL, NULL, 0} -}; - bool PyObjectProxyHandler::handleOwnPropertyKeys(JSContext *cx, PyObject *keys, size_t length, JS::MutableHandleIdVector props) { if (!props.reserve(length)) { return false; // out of memory @@ -76,24 +44,29 @@ bool PyObjectProxyHandler::handleGetOwnPropertyDescriptor(JSContext *cx, JS::Han JS::MutableHandle> desc, PyObject *item) { // see if we're calling a function if (id.isString()) { - for (size_t index = 0;; index++) { - bool isThatFunction; - const char *methodName = object_methods[index].name; - if (methodName == NULL) { - break; + JS::RootedString idString(cx, id.toString()); + const char *methodName = JS_EncodeStringToUTF8(cx, idString).get(); + if (!strcmp(methodName, "toString") || !strcmp(methodName, "toLocaleString") || !strcmp(methodName, "valueOf")) { + JS::RootedObject objectPrototype(cx); + if (!JS_GetClassPrototype(cx, JSProto_Object, &objectPrototype)) { + return false; } - else if (JS_StringEqualsAscii(cx, id.toString(), methodName, &isThatFunction) && isThatFunction) { - JSFunction *newFunction = JS_NewFunction(cx, object_methods[index].call, object_methods[index].nargs, 0, NULL); - if (!newFunction) return false; - JS::RootedObject funObj(cx, JS_GetFunctionObject(newFunction)); - desc.set(mozilla::Some( - JS::PropertyDescriptor::Data( - JS::ObjectValue(*funObj), - {JS::PropertyAttribute::Enumerable} - ) - )); - return true; + + JS::RootedValue Object_Prototype_Method(cx); + if (!JS_GetProperty(cx, objectPrototype, methodName, &Object_Prototype_Method)) { + return false; } + + JS::RootedObject rootedObjectPrototypeConstructor(cx, Object_Prototype_Method.toObjectOrNull()); + + desc.set(mozilla::Some( + JS::PropertyDescriptor::Data( + JS::ObjectValue(*rootedObjectPrototypeConstructor), + {JS::PropertyAttribute::Enumerable} + ) + )); + + return true; } } diff --git a/tests/python/test_objects.py b/tests/python/test_objects.py index 96935344..b40f25b1 100644 --- a/tests/python/test_objects.py +++ b/tests/python/test_objects.py @@ -170,4 +170,19 @@ def test_toPrimitive_stdin(): def test_constructor_stdin(): constructor = pm.eval("(obj) => { return obj.constructor; }")(sys.stdin) - assert repr(constructor).__contains__(" x.toString === Object.prototype.toString") + assert is_to_string_correct({}) + + +def test_toString_is_prototype_toLocaleString(): + is_to_locale_string_correct = pm.eval("x => x.toLocaleString === Object.prototype.toLocaleString") + assert is_to_locale_string_correct({}) + + +def test_valueof_is_prototype_valueof(): + is_valueof_correct = pm.eval("x => x.valueOf === Object.prototype.valueOf") + assert is_valueof_correct({}) \ No newline at end of file From bae0533d139b9120a0575a59a86cdc7d98eb956c Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Thu, 25 Jul 2024 18:05:12 -0400 Subject: [PATCH 188/428] cleanup unsued vars --- src/PyIterableProxyHandler.cc | 2 -- src/PyListProxyHandler.cc | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/PyIterableProxyHandler.cc b/src/PyIterableProxyHandler.cc index f60c747b..5a33f870 100644 --- a/src/PyIterableProxyHandler.cc +++ b/src/PyIterableProxyHandler.cc @@ -238,8 +238,6 @@ bool PyIterableProxyHandler::getOwnPropertyDescriptor( // "constructor" property bool isConstructorProperty; if (id.isString() && JS_StringEqualsLiteral(cx, id.toString(), "constructor", &isConstructorProperty) && isConstructorProperty) { - JS::RootedObject global(cx, JS::GetNonCCWObjectGlobal(proxy)); - JS::RootedObject rootedObjectPrototype(cx); if (!JS_GetClassPrototype(cx, JSProto_Object, &rootedObjectPrototype)) { return false; diff --git a/src/PyListProxyHandler.cc b/src/PyListProxyHandler.cc index 2b6f9573..688cf82d 100644 --- a/src/PyListProxyHandler.cc +++ b/src/PyListProxyHandler.cc @@ -2040,8 +2040,6 @@ bool PyListProxyHandler::getOwnPropertyDescriptor( // "constructor" property bool isConstructorProperty; if (id.isString() && JS_StringEqualsLiteral(cx, id.toString(), "constructor", &isConstructorProperty) && isConstructorProperty) { - JS::RootedObject global(cx, JS::GetNonCCWObjectGlobal(proxy)); - JS::RootedObject rootedArrayPrototype(cx); if (!JS_GetClassPrototype(cx, JSProto_Array, &rootedArrayPrototype)) { return false; From f50e9a1ed1d3ccad812eaba95d7e958356ff356e Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Fri, 26 Jul 2024 11:55:42 -0400 Subject: [PATCH 189/428] comments fixes --- src/PyBytesProxyHandler.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/PyBytesProxyHandler.cc b/src/PyBytesProxyHandler.cc index e0a6328c..92756c3f 100644 --- a/src/PyBytesProxyHandler.cc +++ b/src/PyBytesProxyHandler.cc @@ -287,7 +287,7 @@ bool PyBytesProxyHandler::getOwnPropertyDescriptor( if (id.isString()) { bool isProperty; - // "length" and byteLength properties have the same value + // "length" and "byteLength" properties have the same value if (((JS_StringEqualsLiteral(cx, id.toString(), "length", &isProperty) && isProperty) || (JS_StringEqualsLiteral(cx, id.toString(), "byteLength", &isProperty) && isProperty))) { JS::PersistentRootedObject* arrayBuffer = JS::GetMaybePtrFromReservedSlot(proxy, OtherSlot); @@ -303,7 +303,7 @@ bool PyBytesProxyHandler::getOwnPropertyDescriptor( return true; } - // buffer property + // "buffer" property if (JS_StringEqualsLiteral(cx, id.toString(), "buffer", &isProperty) && isProperty) { JS::PersistentRootedObject* arrayBuffer = JS::GetMaybePtrFromReservedSlot(proxy, OtherSlot); @@ -315,7 +315,7 @@ bool PyBytesProxyHandler::getOwnPropertyDescriptor( return true; } - // BYTES_PER_ELEMENT property + // "BYTES_PER_ELEMENT" property if (JS_StringEqualsLiteral(cx, id.toString(), "BYTES_PER_ELEMENT", &isProperty) && isProperty) { desc.set(mozilla::Some( JS::PropertyDescriptor::Data( @@ -325,7 +325,7 @@ bool PyBytesProxyHandler::getOwnPropertyDescriptor( return true; } - // byteOffset property + // "byteOffset" property if (JS_StringEqualsLiteral(cx, id.toString(), "byteOffset", &isProperty) && isProperty) { desc.set(mozilla::Some( JS::PropertyDescriptor::Data( From 1d112b3616f21295a1a0ae432c910ca6a867c64f Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Fri, 26 Jul 2024 12:04:51 -0400 Subject: [PATCH 190/428] cleanup --- include/PyBytesProxyHandler.hh | 6 ------ src/PyBytesProxyHandler.cc | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/include/PyBytesProxyHandler.hh b/include/PyBytesProxyHandler.hh index bd9dd83c..12bb8b9f 100644 --- a/include/PyBytesProxyHandler.hh +++ b/include/PyBytesProxyHandler.hh @@ -34,12 +34,6 @@ public: ) const override; void finalize(JS::GCContext *gcx, JSObject *proxy) const override; - - /** - * @brief An array of method definitions for bytes prototype methods - * - */ - static JSMethodDef array_methods[]; }; #endif \ No newline at end of file diff --git a/src/PyBytesProxyHandler.cc b/src/PyBytesProxyHandler.cc index 92756c3f..450b05a7 100644 --- a/src/PyBytesProxyHandler.cc +++ b/src/PyBytesProxyHandler.cc @@ -232,7 +232,7 @@ static bool array_values(JSContext *cx, unsigned argc, JS::Value *vp) { } -JSMethodDef PyBytesProxyHandler::array_methods[] = { +static JSMethodDef array_methods[] = { {"toString", array_toString, 0}, {"valueOf", array_valueOf, 0}, {"entries", array_entries, 0}, From 282706a760befdea984680779e4b656fbe580606 Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Fri, 26 Jul 2024 12:07:01 -0400 Subject: [PATCH 191/428] cleanup --- include/PyIterableProxyHandler.hh | 6 ------ include/PyObjectProxyHandler.hh | 6 ------ src/PyIterableProxyHandler.cc | 2 +- 3 files changed, 1 insertion(+), 13 deletions(-) diff --git a/include/PyIterableProxyHandler.hh b/include/PyIterableProxyHandler.hh index ff631b3a..8a11706f 100644 --- a/include/PyIterableProxyHandler.hh +++ b/include/PyIterableProxyHandler.hh @@ -28,12 +28,6 @@ public: JSContext *cx, JS::HandleObject proxy, JS::HandleId id, JS::MutableHandle> desc ) const override; - - /** - * @brief An array of method definitions for Iterable prototype methods - * - */ - static JSMethodDef iterable_methods[]; }; #endif \ No newline at end of file diff --git a/include/PyObjectProxyHandler.hh b/include/PyObjectProxyHandler.hh index 78cf1f37..38f6f970 100644 --- a/include/PyObjectProxyHandler.hh +++ b/include/PyObjectProxyHandler.hh @@ -190,12 +190,6 @@ public: JS::ObjectOpResult &result) const override; bool getBuiltinClass(JSContext *cx, JS::HandleObject proxy, js::ESClass *cls) const override; - - /** - * @brief An array of method definitions for Object prototype methods - * - */ - static JSMethodDef object_methods[]; }; #endif \ No newline at end of file diff --git a/src/PyIterableProxyHandler.cc b/src/PyIterableProxyHandler.cc index 5a33f870..5de9ec3a 100644 --- a/src/PyIterableProxyHandler.cc +++ b/src/PyIterableProxyHandler.cc @@ -105,7 +105,7 @@ static bool iterable_valueOf(JSContext *cx, unsigned argc, JS::Value *vp) { return toPrimitive(cx, argc, vp); } -JSMethodDef PyIterableProxyHandler::iterable_methods[] = { +static JSMethodDef iterable_methods[] = { {"next", iterable_next, 0}, {"valueOf", iterable_valueOf, 0}, {NULL, NULL, 0} From 8883eaf642cb5146259db44eeaaeb85ebebdb5e6 Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Fri, 26 Jul 2024 12:09:49 -0400 Subject: [PATCH 192/428] minor improvement --- src/PyBytesProxyHandler.cc | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/PyBytesProxyHandler.cc b/src/PyBytesProxyHandler.cc index 450b05a7..739f03d4 100644 --- a/src/PyBytesProxyHandler.cc +++ b/src/PyBytesProxyHandler.cc @@ -287,8 +287,10 @@ bool PyBytesProxyHandler::getOwnPropertyDescriptor( if (id.isString()) { bool isProperty; + JSString *idString = id.toString(); + // "length" and "byteLength" properties have the same value - if (((JS_StringEqualsLiteral(cx, id.toString(), "length", &isProperty) && isProperty) || (JS_StringEqualsLiteral(cx, id.toString(), "byteLength", &isProperty) && isProperty))) { + if (((JS_StringEqualsLiteral(cx, idString, "length", &isProperty) && isProperty) || (JS_StringEqualsLiteral(cx, id.toString(), "byteLength", &isProperty) && isProperty))) { JS::PersistentRootedObject* arrayBuffer = JS::GetMaybePtrFromReservedSlot(proxy, OtherSlot); JS::RootedObject rootedArrayBuffer(cx, arrayBuffer->get()); @@ -304,7 +306,7 @@ bool PyBytesProxyHandler::getOwnPropertyDescriptor( } // "buffer" property - if (JS_StringEqualsLiteral(cx, id.toString(), "buffer", &isProperty) && isProperty) { + if (JS_StringEqualsLiteral(cx, idString, "buffer", &isProperty) && isProperty) { JS::PersistentRootedObject* arrayBuffer = JS::GetMaybePtrFromReservedSlot(proxy, OtherSlot); desc.set(mozilla::Some( @@ -316,7 +318,7 @@ bool PyBytesProxyHandler::getOwnPropertyDescriptor( } // "BYTES_PER_ELEMENT" property - if (JS_StringEqualsLiteral(cx, id.toString(), "BYTES_PER_ELEMENT", &isProperty) && isProperty) { + if (JS_StringEqualsLiteral(cx, idString, "BYTES_PER_ELEMENT", &isProperty) && isProperty) { desc.set(mozilla::Some( JS::PropertyDescriptor::Data( JS::Int32Value(1) @@ -326,7 +328,7 @@ bool PyBytesProxyHandler::getOwnPropertyDescriptor( } // "byteOffset" property - if (JS_StringEqualsLiteral(cx, id.toString(), "byteOffset", &isProperty) && isProperty) { + if (JS_StringEqualsLiteral(cx, idString, "byteOffset", &isProperty) && isProperty) { desc.set(mozilla::Some( JS::PropertyDescriptor::Data( JS::Int32Value(0) @@ -336,7 +338,7 @@ bool PyBytesProxyHandler::getOwnPropertyDescriptor( } // "constructor" property - if (JS_StringEqualsLiteral(cx, id.toString(), "constructor", &isProperty) && isProperty) { + if (JS_StringEqualsLiteral(cx, idString, "constructor", &isProperty) && isProperty) { JS::RootedObject uint8ArrayPrototype(cx); if (!JS_GetClassPrototype(cx, JSProto_Uint8Array, &uint8ArrayPrototype)) { return false; From 56389b50cdcd029876f9f39bdcc6da2b4ebc1ea6 Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Fri, 26 Jul 2024 12:29:03 -0400 Subject: [PATCH 193/428] header cleanup --- src/PyBytesProxyHandler.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/PyBytesProxyHandler.cc b/src/PyBytesProxyHandler.cc index 739f03d4..80d18ebd 100644 --- a/src/PyBytesProxyHandler.cc +++ b/src/PyBytesProxyHandler.cc @@ -14,8 +14,6 @@ #include #include -#include - const char PyBytesProxyHandler::family = 0; From 38af5332cde4cf2d5f539b3904947403d9206cec Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Fri, 26 Jul 2024 12:31:07 -0400 Subject: [PATCH 194/428] removed unneeded parenthesis --- src/PyBytesProxyHandler.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PyBytesProxyHandler.cc b/src/PyBytesProxyHandler.cc index 80d18ebd..c8d7dad8 100644 --- a/src/PyBytesProxyHandler.cc +++ b/src/PyBytesProxyHandler.cc @@ -288,7 +288,7 @@ bool PyBytesProxyHandler::getOwnPropertyDescriptor( JSString *idString = id.toString(); // "length" and "byteLength" properties have the same value - if (((JS_StringEqualsLiteral(cx, idString, "length", &isProperty) && isProperty) || (JS_StringEqualsLiteral(cx, id.toString(), "byteLength", &isProperty) && isProperty))) { + if ((JS_StringEqualsLiteral(cx, idString, "length", &isProperty) && isProperty) || (JS_StringEqualsLiteral(cx, id.toString(), "byteLength", &isProperty) && isProperty)) { JS::PersistentRootedObject* arrayBuffer = JS::GetMaybePtrFromReservedSlot(proxy, OtherSlot); JS::RootedObject rootedArrayBuffer(cx, arrayBuffer->get()); From f4e79232a9d942578eba961d169b6b13dd0c04bf Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Fri, 26 Jul 2024 12:46:01 -0400 Subject: [PATCH 195/428] comment cleanup --- src/BufferType.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BufferType.cc b/src/BufferType.cc index 66b8f9de..dde0f09b 100644 --- a/src/BufferType.cc +++ b/src/BufferType.cc @@ -180,7 +180,7 @@ JSObject *BufferType::toJsTypedArray(JSContext *cx, PyObject *pyObject) { } else { JS::RootedValue v(cx); JS::RootedObject uint8ArrayPrototype(cx); - JS_GetClassPrototype(cx, JSProto_Uint8Array, &uint8ArrayPrototype); // so that instanceof will work, not that prototype methods will TEST THIS + JS_GetClassPrototype(cx, JSProto_Uint8Array, &uint8ArrayPrototype); // so that instanceof will work, not that prototype methods will JSObject *proxy = js::NewProxyObject(cx, &pyBytesProxyHandler, v, uint8ArrayPrototype.get()); JS::SetReservedSlot(proxy, PyObjectSlot, JS::PrivateValue(pyObject)); JS::PersistentRootedObject *arrayBufferPointer = new JS::PersistentRootedObject(cx); From 9df5dfdd3a704a55e60320a218ec1d08875151ea Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Fri, 26 Jul 2024 12:52:51 -0400 Subject: [PATCH 196/428] unneeded check --- src/BufferType.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BufferType.cc b/src/BufferType.cc index dde0f09b..97ac7781 100644 --- a/src/BufferType.cc +++ b/src/BufferType.cc @@ -147,7 +147,7 @@ JSObject *BufferType::toJsTypedArray(JSContext *cx, PyObject *pyObject) { immutable = true; } - if (view->ndim != 1 && !immutable) { + if (view->ndim != 1) { PyErr_SetString(PyExc_BufferError, "multidimensional arrays are not allowed"); BufferType::_releasePyBuffer(view); return nullptr; From 105723dc15da5d330ec7377b5f68ddeaf264d301 Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Fri, 26 Jul 2024 12:56:20 -0400 Subject: [PATCH 197/428] comment fix --- src/BufferType.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BufferType.cc b/src/BufferType.cc index 97ac7781..e71eb87a 100644 --- a/src/BufferType.cc +++ b/src/BufferType.cc @@ -140,7 +140,7 @@ JSObject *BufferType::toJsTypedArray(JSContext *cx, PyObject *pyObject) { // the buffer is immutable (e.g., Python `bytes` type is read-only) PyErr_Clear(); // a PyExc_BufferError was raised - if (PyObject_GetBuffer(pyObject, view, PyBUF_ND /* C-contiguous and writable */ | PyBUF_FORMAT) < 0) { + if (PyObject_GetBuffer(pyObject, view, PyBUF_ND /* C-contiguous */ | PyBUF_FORMAT) < 0) { return nullptr; // a PyExc_BufferError was raised again } From f69f80bb9a624540d33b85132d5f72224667aa6f Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Mon, 29 Jul 2024 17:28:25 -0400 Subject: [PATCH 198/428] check for SystemExit before scheduling timer --- src/internalBinding/timers.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/internalBinding/timers.cc b/src/internalBinding/timers.cc index f7adabf5..567df548 100644 --- a/src/internalBinding/timers.cc +++ b/src/internalBinding/timers.cc @@ -23,6 +23,11 @@ using AsyncHandle = PyEventLoop::AsyncHandle; */ static bool enqueueWithDelay(JSContext *cx, unsigned argc, JS::Value *vp) { + if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_SystemExit)) { + // quit, exit or sys.exit was called (and raised SystemExit) + return false; + } + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); JS::HandleValue jobArgVal = args.get(0); double delaySeconds = args.get(1).toNumber(); From 1ad53c27f4feeefdc6e454a104307200f648e513 Mon Sep 17 00:00:00 2001 From: philippedistributive <151072087+philippedistributive@users.noreply.github.com> Date: Tue, 30 Jul 2024 10:14:49 -0400 Subject: [PATCH 199/428] also include limits.h Co-authored-by: Caleb Aikens --- src/BufferType.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/BufferType.cc b/src/BufferType.cc index e71eb87a..d627e753 100644 --- a/src/BufferType.cc +++ b/src/BufferType.cc @@ -16,6 +16,7 @@ #include #include +#include // JS to Python From 1be6a926b5bf6f45c520ec85be8ff48f511c6c3e Mon Sep 17 00:00:00 2001 From: philippedistributive <151072087+philippedistributive@users.noreply.github.com> Date: Tue, 30 Jul 2024 10:18:22 -0400 Subject: [PATCH 200/428] more efficient string processing Co-authored-by: Caleb Aikens --- src/PyBytesProxyHandler.cc | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/PyBytesProxyHandler.cc b/src/PyBytesProxyHandler.cc index c8d7dad8..f2199df5 100644 --- a/src/PyBytesProxyHandler.cc +++ b/src/PyBytesProxyHandler.cc @@ -35,17 +35,17 @@ static bool array_valueOf(JSContext *cx, unsigned argc, JS::Value *vp) { JS::AutoCheckCannotGC autoNoGC(cx); uint8_t *data = JS::GetArrayBufferData(rootedArrayBuffer, &isSharedMemory, autoNoGC); - std::string valueOfString; + const size_t STRING_LENGTH = byteLength*2 - 1; + JS::Latin1Char* buffer = (JS::Latin1Char *)malloc(sizeof(JS::Latin1Char) * STRING_LENGTH); - for (Py_ssize_t index = 0; index < byteLength; index++) { - if (index > 0) { - valueOfString += ","; - } - - valueOfString += std::to_string(data[index]); + buffer[0] = data[0]; + for (Py_ssize_t index = 1; index < byteLength; index++) { + buffer[index*2 - 1] = ','; + buffer[index*2] = data[index]; } - args.rval().setString(JS_NewStringCopyZ(cx, valueOfString.c_str())); + JS::UniqueLatin1Chars str(buffer); + args.rval().setString(JS_NewLatin1String(cx, std::move(str), STRING_LENGTH)); return true; } From bf9ca98868d4e6fff5de49745b1b1800a516ba7f Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Tue, 30 Jul 2024 10:18:41 -0400 Subject: [PATCH 201/428] method documentation --- include/PyBytesProxyHandler.hh | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/include/PyBytesProxyHandler.hh b/include/PyBytesProxyHandler.hh index 12bb8b9f..1c7126f9 100644 --- a/include/PyBytesProxyHandler.hh +++ b/include/PyBytesProxyHandler.hh @@ -24,6 +24,18 @@ public: PyBytesProxyHandler() : PyObjectProxyHandler(&family) {}; static const char family; + /** + * @brief [[Set]] + * + * @param cx pointer to JSContext + * @param proxy The proxy object who's property we wish to set + * @param id Key of the property we wish to set + * @param v Value that we wish to set the property to + * @param receiver The `this` value to use when executing any code + * @param result whether or not the call succeeded + * @return true call succeed + * @return false call failed and an exception has been raised + */ bool set(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, JS::HandleValue v, JS::HandleValue receiver, JS::ObjectOpResult &result) const override; @@ -33,6 +45,12 @@ public: JS::MutableHandle> desc ) const override; + /** + * @brief Handles python object reference count when JS Proxy object is finalized + * + * @param gcx pointer to JS::GCContext + * @param proxy the proxy object being finalized + */ void finalize(JS::GCContext *gcx, JSObject *proxy) const override; }; From e0b6bf59e9d0ca12d266ad076e77dd4ea28d719e Mon Sep 17 00:00:00 2001 From: philippedistributive <151072087+philippedistributive@users.noreply.github.com> Date: Tue, 30 Jul 2024 11:05:47 -0400 Subject: [PATCH 202/428] added missing Float16 supoport Co-authored-by: Caleb Aikens --- src/BufferType.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/BufferType.cc b/src/BufferType.cc index d627e753..2cb0329c 100644 --- a/src/BufferType.cc +++ b/src/BufferType.cc @@ -23,9 +23,12 @@ /* static */ const char *BufferType::_toPyBufferFormatCode(JS::Scalar::Type subtype) { // floating point types - if (subtype == JS::Scalar::Float32) { + switch (subtype) { + case JS::Scalar::Float16: + return "e"; + case JS::Scalar::Float32: return "f"; - } else if (subtype == JS::Scalar::Float64) { + case JS::Scalar::Float64: return "d"; } From 2a5ba78f44959ea59eb286640381a40a09c3abd8 Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Tue, 30 Jul 2024 11:10:33 -0400 Subject: [PATCH 203/428] added more float16 support and tests --- src/BufferType.cc | 3 +++ tests/python/test_buffer_typed_array.py | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/BufferType.cc b/src/BufferType.cc index 2cb0329c..f0726bce 100644 --- a/src/BufferType.cc +++ b/src/BufferType.cc @@ -220,8 +220,11 @@ JS::Scalar::Type BufferType::_getPyBufferType(Py_buffer *bufView) { return JS::Scalar::Float32; } else if (typeCode == 'd') { return JS::Scalar::Float64; + } else if (typeCode == 'e') { + return JS::Scalar::Float16; } + // integer types // We can't rely on the type codes alone since the typecodes are mapped to C types and would have different sizes on different architectures // see https://docs.python.org/3.9/library/array.html#module-array diff --git a/tests/python/test_buffer_typed_array.py b/tests/python/test_buffer_typed_array.py index 4d34959e..0eab66d5 100644 --- a/tests/python/test_buffer_typed_array.py +++ b/tests/python/test_buffer_typed_array.py @@ -50,6 +50,7 @@ def assert_js_to_py_memoryview(buf: memoryview): assert pm.eval("(arr)=>arr instanceof Int16Array")(numpy.array([1], dtype=numpy.int16)) assert pm.eval("(arr)=>arr instanceof Int32Array")(numpy.array([1], dtype=numpy.int32)) assert pm.eval("(arr)=>arr instanceof BigInt64Array")(numpy.array([1], dtype=numpy.int64)) + assert pm.eval("(arr)=>arr instanceof Float16Array")(numpy.array([1], dtype=numpy.float16)) assert pm.eval("(arr)=>arr instanceof Float32Array")(numpy.array([1], dtype=numpy.float32)) assert pm.eval("(arr)=>arr instanceof Float64Array")(numpy.array([1], dtype=numpy.float64)) assert pm.eval("new Uint8Array([1])").format == "B" @@ -60,6 +61,7 @@ def assert_js_to_py_memoryview(buf: memoryview): assert pm.eval("new Int16Array([1])").format == "h" assert pm.eval("new Int32Array([1])").format == "i" assert pm.eval("new BigInt64Array([1n])").format == "q" + assert pm.eval("new Float16Array([1])").format == "e" assert pm.eval("new Float32Array([1])").format == "f" assert pm.eval("new Float64Array([1])").format == "d" From 80eee2041b1c9f0ba70cc7d07e403d5c5bae2f5e Mon Sep 17 00:00:00 2001 From: philippedistributive <151072087+philippedistributive@users.noreply.github.com> Date: Tue, 30 Jul 2024 11:28:10 -0400 Subject: [PATCH 204/428] print numbers instead of chars Co-authored-by: Caleb Aikens --- src/PyBytesProxyHandler.cc | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/PyBytesProxyHandler.cc b/src/PyBytesProxyHandler.cc index f2199df5..68f9a402 100644 --- a/src/PyBytesProxyHandler.cc +++ b/src/PyBytesProxyHandler.cc @@ -34,18 +34,25 @@ static bool array_valueOf(JSContext *cx, unsigned argc, JS::Value *vp) { bool isSharedMemory; JS::AutoCheckCannotGC autoNoGC(cx); uint8_t *data = JS::GetArrayBufferData(rootedArrayBuffer, &isSharedMemory, autoNoGC); - - const size_t STRING_LENGTH = byteLength*2 - 1; + size_t numberOfDigits = 0; + for (size_t i = 0; i < byteLength; i++) { + numberOfDigits += data[i] < 10 ? 1 : data[i] < 100 ? 2 : 3; + } + const size_t STRING_LENGTH = byteLength + numberOfDigits; JS::Latin1Char* buffer = (JS::Latin1Char *)malloc(sizeof(JS::Latin1Char) * STRING_LENGTH); - - buffer[0] = data[0]; - for (Py_ssize_t index = 1; index < byteLength; index++) { - buffer[index*2 - 1] = ','; - buffer[index*2] = data[index]; + + size_t charIndex = 0; + sprintf((char*)&buffer[charIndex], "%d", data[0]); + charIndex += data[0] < 10 ? 1 : data[0] < 100 ? 2 : 3; + for (size_t dataIndex = 1; dataIndex < byteLength; dataIndex++) { + buffer[charIndex] = ','; + charIndex++; + sprintf((char*)&buffer[charIndex], "%d", data[dataIndex]); + charIndex += data[dataIndex] < 10 ? 1 : data[dataIndex] < 100 ? 2 : 3; } JS::UniqueLatin1Chars str(buffer); - args.rval().setString(JS_NewLatin1String(cx, std::move(str), STRING_LENGTH)); + args.rval().setString(JS_NewLatin1String(cx, std::move(str), STRING_LENGTH - 1)); // don't include null byte return true; } From 88973b767707ef0cd30180d9d9801edf46d66f53 Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Tue, 30 Jul 2024 11:29:15 -0400 Subject: [PATCH 205/428] added line spacings --- src/PyBytesProxyHandler.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/PyBytesProxyHandler.cc b/src/PyBytesProxyHandler.cc index 68f9a402..753e67e5 100644 --- a/src/PyBytesProxyHandler.cc +++ b/src/PyBytesProxyHandler.cc @@ -34,6 +34,7 @@ static bool array_valueOf(JSContext *cx, unsigned argc, JS::Value *vp) { bool isSharedMemory; JS::AutoCheckCannotGC autoNoGC(cx); uint8_t *data = JS::GetArrayBufferData(rootedArrayBuffer, &isSharedMemory, autoNoGC); + size_t numberOfDigits = 0; for (size_t i = 0; i < byteLength; i++) { numberOfDigits += data[i] < 10 ? 1 : data[i] < 100 ? 2 : 3; @@ -44,6 +45,7 @@ static bool array_valueOf(JSContext *cx, unsigned argc, JS::Value *vp) { size_t charIndex = 0; sprintf((char*)&buffer[charIndex], "%d", data[0]); charIndex += data[0] < 10 ? 1 : data[0] < 100 ? 2 : 3; + for (size_t dataIndex = 1; dataIndex < byteLength; dataIndex++) { buffer[charIndex] = ','; charIndex++; From 292382812dab7296aa1686bd515e745dbef5ca5a Mon Sep 17 00:00:00 2001 From: Ciarands <74070993+Ciarands@users.noreply.github.com> Date: Fri, 9 Aug 2024 03:10:33 +0100 Subject: [PATCH 206/428] fix: base64.py 'Incorrect padding' error Update python implementation of 'atob' to properly reflect behaviour of JS 'atob'. --- python/pythonmonkey/builtin_modules/base64.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python/pythonmonkey/builtin_modules/base64.py b/python/pythonmonkey/builtin_modules/base64.py index 12ca25a0..da18fedc 100644 --- a/python/pythonmonkey/builtin_modules/base64.py +++ b/python/pythonmonkey/builtin_modules/base64.py @@ -8,7 +8,10 @@ def atob(b64): - return str(base64.standard_b64decode(b64), 'latin1') + # Workaround for pythons 'Incorrect padding' error when base64 decoding, see: + # https://stackoverflow.com/questions/2941995/python-ignore-incorrect-padding-error-when-base64-decoding + append = b"==" if isinstance(b64, bytes) else "==" + return str(base64.standard_b64decode(b64 + append), 'latin1') def btoa(data): From baca7095bec0aaeff05b39adb0b20ee48761fadb Mon Sep 17 00:00:00 2001 From: philippedistributive <151072087+philippedistributive@users.noreply.github.com> Date: Mon, 12 Aug 2024 14:00:54 +0000 Subject: [PATCH 207/428] chore(deps): upgrade SpiderMonkey to `2d25134707f3710ac52e3b25ccb0eb710e2c5d3b` --- mozcentral.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mozcentral.version b/mozcentral.version index 758c56ec..f0511752 100644 --- a/mozcentral.version +++ b/mozcentral.version @@ -1 +1 @@ -bc4609b7aa7a3dff961f43d527bc66c5c85f6f4b \ No newline at end of file +2d25134707f3710ac52e3b25ccb0eb710e2c5d3b \ No newline at end of file From c55099cdd6d61a9907cd9a3235bcc45eae1c620f Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 14 Aug 2024 18:36:32 +0000 Subject: [PATCH 208/428] chore(CI): add arm64 build Building on our in-house Raspberry Pi runner. --- .github/workflows/test-and-publish.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 296b66af..edd54105 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -60,7 +60,7 @@ jobs: fail-fast: false matrix: # Use Ubuntu 20.04 / Ubuntu 24.04 / macOS 13 x86_64 / macOS 14 arm64 + Python 3.10 to build SpiderMonkey - os: [ 'ubuntu-20.04', 'ubuntu-24.04', 'macos-13', 'macos-14' ] # macOS 14 runner exclusively runs on M1 hardwares + os: [ 'ubuntu-20.04', 'ubuntu-24.04', 'macos-13', 'macos-14', 'pi' ] # macOS 14 runner exclusively runs on M1 hardwares # see https://github.blog/changelog/2024-01-30-github-actions-macos-14-sonoma-is-now-available python_version: [ '3.10' ] runs-on: ${{ matrix.os }} @@ -127,7 +127,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ 'ubuntu-20.04', 'ubuntu-24.04', 'macos-12', 'macos-14', 'windows-2022' ] + os: [ 'ubuntu-20.04', 'ubuntu-24.04', 'macos-12', 'macos-14', 'windows-2022', 'pi' ] python_version: [ '3.8', '3.9', '3.10', '3.11', '3.12' ] exclude: # actions/setup-python: The version '3.8'/'3.9' with architecture 'arm64' was not found for macOS. From 8e7c55934e2abea9f482e0c6b4748b8fa95c31f5 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 14 Aug 2024 18:38:35 +0000 Subject: [PATCH 209/428] fix(CI): temporarily fix Windows build --- setup.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/setup.sh b/setup.sh index ca7ab7c9..9cab6c6d 100755 --- a/setup.sh +++ b/setup.sh @@ -34,7 +34,9 @@ fi # Install rust compiler echo "Installing rust compiler" curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.76 -. $HOME/.cargo/env +if [[ "$OSTYPE" != "msys"* ]]; then # not Windows + . $HOME/.cargo/env +fi cargo install cbindgen # Setup Poetry echo "Installing poetry" From 723c301dc9ee048793ec3b3c82a2d9013bf0852f Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 14 Aug 2024 23:09:13 +0000 Subject: [PATCH 210/428] fix(CI): use the correct Python version for poetry --- .github/workflows/test-and-publish.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index edd54105..ad913aeb 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -162,9 +162,11 @@ jobs: fi echo "Installing python deps" poetry self add "poetry-dynamic-versioning[plugin]" - poetry env use python3 # use the correct Python version we've set up + poetry env use python$PYTHON_VERSION # use the correct Python version we've set up poetry install --no-root --only=dev echo "Installed Dependencies" + env: + PYTHON_VERSION: ${{ matrix.python_version }} - name: Build Docs # only build docs once if: ${{ matrix.os == 'ubuntu-20.04' && matrix.python_version == '3.11' }} run: | From 228467f54a55aa22ee3214176d544f04657d31ca Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Thu, 15 Aug 2024 14:53:57 +0000 Subject: [PATCH 211/428] Revert "fix(CI): use the correct Python version for poetry" This reverts commit 723c301dc9ee048793ec3b3c82a2d9013bf0852f. --- .github/workflows/test-and-publish.yaml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index ad913aeb..edd54105 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -162,11 +162,9 @@ jobs: fi echo "Installing python deps" poetry self add "poetry-dynamic-versioning[plugin]" - poetry env use python$PYTHON_VERSION # use the correct Python version we've set up + poetry env use python3 # use the correct Python version we've set up poetry install --no-root --only=dev echo "Installed Dependencies" - env: - PYTHON_VERSION: ${{ matrix.python_version }} - name: Build Docs # only build docs once if: ${{ matrix.os == 'ubuntu-20.04' && matrix.python_version == '3.11' }} run: | From 08c1dafd94231423e116adc7a8ed7eb0345489d9 Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Thu, 15 Aug 2024 10:56:24 -0400 Subject: [PATCH 212/428] refresh status assessment --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8f6a9550..899a0090 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ 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 product is in an advanced stage, approximately 95% to MVP as of March 2024. It is under active development by [Distributive](https://distributive.network/). +This product is in an advanced stage, approximately 98% to MVP as of August 2024. It is under active development by [Distributive](https://distributive.network/). External contributions and feedback are welcome and encouraged. From 76140aff2bd173f4616f7878c9d0a14e94a1ac54 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Thu, 15 Aug 2024 15:14:29 +0000 Subject: [PATCH 213/428] fix(CI): use the correct Python version for poetry --- .github/workflows/test-and-publish.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index edd54105..240dda3c 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -162,9 +162,11 @@ jobs: fi echo "Installing python deps" poetry self add "poetry-dynamic-versioning[plugin]" - poetry env use python3 # use the correct Python version we've set up + poetry env use python$PYTHON_VERSION || poetry env use python3 # use the correct Python version we've set up poetry install --no-root --only=dev echo "Installed Dependencies" + env: + PYTHON_VERSION: ${{ matrix.python_version }} - name: Build Docs # only build docs once if: ${{ matrix.os == 'ubuntu-20.04' && matrix.python_version == '3.11' }} run: | From be2f4b232110f929607079ade5e201f49db8885c Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Sat, 17 Aug 2024 21:16:32 +0000 Subject: [PATCH 214/428] fix(CI): remove old virtual environments for poetry --- .github/workflows/test-and-publish.yaml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 240dda3c..a3de645e 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -162,11 +162,10 @@ jobs: fi echo "Installing python deps" poetry self add "poetry-dynamic-versioning[plugin]" - poetry env use python$PYTHON_VERSION || poetry env use python3 # use the correct Python version we've set up + poetry env remove --all + poetry env use python3 # use the correct Python version we've set up poetry install --no-root --only=dev echo "Installed Dependencies" - env: - PYTHON_VERSION: ${{ matrix.python_version }} - name: Build Docs # only build docs once if: ${{ matrix.os == 'ubuntu-20.04' && matrix.python_version == '3.11' }} run: | From 2535988261924b32eb4cccd52d67fc7644bf13e6 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Sat, 17 Aug 2024 21:24:31 +0000 Subject: [PATCH 215/428] fix(CI): use the correct Python version for poetry --- .github/workflows/test-and-publish.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index a3de645e..1382d995 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -162,10 +162,12 @@ jobs: fi echo "Installing python deps" poetry self add "poetry-dynamic-versioning[plugin]" - poetry env remove --all - poetry env use python3 # use the correct Python version we've set up + poetry env remove --all -v + poetry env use python$PYTHON_VERSION || poetry env use python3 # use the correct Python version we've set up poetry install --no-root --only=dev echo "Installed Dependencies" + env: + PYTHON_VERSION: ${{ matrix.python_version }} - name: Build Docs # only build docs once if: ${{ matrix.os == 'ubuntu-20.04' && matrix.python_version == '3.11' }} run: | From 99a9f27da6529947e10bbfb2c642abb9a1dc9ecc Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Sat, 17 Aug 2024 21:32:47 +0000 Subject: [PATCH 216/428] fix(CI): remove old poetry cache --- .github/workflows/test-and-publish.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 1382d995..afcadfc9 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -146,6 +146,9 @@ jobs: - uses: actions/setup-python@v5 with: python-version: ${{ matrix.python_version }} + - name: Remove old poetry cache + run: rm -rf ~/.cache/pypoetry + if: ${{ matrix.os == 'pi' }} - name: Setup Poetry uses: snok/install-poetry@v1 with: @@ -162,7 +165,6 @@ jobs: fi echo "Installing python deps" poetry self add "poetry-dynamic-versioning[plugin]" - poetry env remove --all -v poetry env use python$PYTHON_VERSION || poetry env use python3 # use the correct Python version we've set up poetry install --no-root --only=dev echo "Installed Dependencies" From 3d02051cecaf6bfc3483938eda698aa2244a63af Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Sun, 18 Aug 2024 04:34:08 +0000 Subject: [PATCH 217/428] fix: compilation error in `JSObjectProxy.cc` error: cannot initialize return object of type 'bool' with an rvalue of type 'std::nullptr_t' --- src/JSObjectProxy.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/JSObjectProxy.cc b/src/JSObjectProxy.cc index 675219bf..13b3e609 100644 --- a/src/JSObjectProxy.cc +++ b/src/JSObjectProxy.cc @@ -245,7 +245,7 @@ bool JSObjectProxyMethodDefinitions::JSObjectProxy_richcompare_helper(JSObjectPr if (!js::GetPropertyKeys(GLOBAL_CX, *(self->jsObject), JSITER_OWNONLY, &props)) { PyErr_Format(PyExc_SystemError, "%s JSAPI call failed", JSObjectProxyType.tp_name); - return NULL; + return false; } // iterate recursively through members of self and check for equality @@ -442,7 +442,7 @@ PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_repr(JSObjectProxy *self PyErr_Clear(); } - if (_PyUnicodeWriter_WriteASCIIString(&writer, "", 19) < 0) { + if (_PyUnicodeWriter_WriteASCIIString(&writer, "", 19) < 0) { goto error; } } From d0d8bff57696b414c60c1c71b1adeb0ddb615c54 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Sun, 18 Aug 2024 04:41:31 +0000 Subject: [PATCH 218/428] fix(setup.sh): forcibly compile SpiderMonkey to `clang`'s (cross-)compilation target setup If the target triple is different even by the `vendor` parameter, it be treated differently, and fatal error: 'type_traits' file not found #include See https://clang.llvm.org/docs/CrossCompilation.html#target-triple --- setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.sh b/setup.sh index 9cab6c6d..30d1b7ab 100755 --- a/setup.sh +++ b/setup.sh @@ -75,7 +75,7 @@ cd js/src mkdir -p _build cd _build mkdir -p ../../../../_spidermonkey_install/ -../configure \ +../configure --target=$(clang --print-target-triple) \ --prefix=$(realpath $PWD/../../../../_spidermonkey_install) \ --with-intl-api \ $(if [[ "$OSTYPE" != "msys"* ]]; then echo "--without-system-zlib"; fi) \ From 0bb14cf13bce976bdc0274f8bc9cb464efdf63cf Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Sun, 18 Aug 2024 04:49:56 +0000 Subject: [PATCH 219/428] Revert "fix(CI): temporarily fix Windows build" This reverts commit 8e7c55934e2abea9f482e0c6b4748b8fa95c31f5. --- setup.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/setup.sh b/setup.sh index 30d1b7ab..e8467798 100755 --- a/setup.sh +++ b/setup.sh @@ -34,9 +34,7 @@ fi # Install rust compiler echo "Installing rust compiler" curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.76 -if [[ "$OSTYPE" != "msys"* ]]; then # not Windows - . $HOME/.cargo/env -fi +. $HOME/.cargo/env cargo install cbindgen # Setup Poetry echo "Installing poetry" From d5eca269569a8c001b84e7bd58bfd13d68ecce11 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Sun, 18 Aug 2024 04:57:01 +0000 Subject: [PATCH 220/428] fix(CI): fix Windows build for finding the `cargo` executable --- setup.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/setup.sh b/setup.sh index e8467798..ed938c74 100755 --- a/setup.sh +++ b/setup.sh @@ -34,15 +34,15 @@ fi # Install rust compiler echo "Installing rust compiler" curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.76 -. $HOME/.cargo/env -cargo install cbindgen +CARGO_BIN="$HOME/.cargo/bin/cargo" # also works for Windows. On Windows this equals to %USERPROFILE%\.cargo\bin\cargo +$CARGO_BIN install cbindgen # Setup Poetry echo "Installing poetry" curl -sSL https://install.python-poetry.org | python3 - --version "1.7.1" if [[ "$OSTYPE" == "msys"* ]]; then # Windows POETRY_BIN="$APPDATA/Python/Scripts/poetry" else - POETRY_BIN=`echo ~/.local/bin/poetry` # expand tilde + POETRY_BIN="$HOME/.local/bin/poetry" fi $POETRY_BIN self add 'poetry-dynamic-versioning[plugin]' echo "Done installing dependencies" From b0dd7d0fe2c606bb3ce35cea96ae70ca65948429 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Sun, 18 Aug 2024 04:57:01 +0000 Subject: [PATCH 221/428] fix(CI): fix Windows build for finding the `cargo` executable --- setup.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/setup.sh b/setup.sh index ca7ab7c9..4fb71487 100755 --- a/setup.sh +++ b/setup.sh @@ -34,15 +34,15 @@ fi # Install rust compiler echo "Installing rust compiler" curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.76 -. $HOME/.cargo/env -cargo install cbindgen +CARGO_BIN="$HOME/.cargo/bin/cargo" # also works for Windows. On Windows this equals to %USERPROFILE%\.cargo\bin\cargo +$CARGO_BIN install cbindgen # Setup Poetry echo "Installing poetry" curl -sSL https://install.python-poetry.org | python3 - --version "1.7.1" if [[ "$OSTYPE" == "msys"* ]]; then # Windows POETRY_BIN="$APPDATA/Python/Scripts/poetry" else - POETRY_BIN=`echo ~/.local/bin/poetry` # expand tilde + POETRY_BIN="$HOME/.local/bin/poetry" fi $POETRY_BIN self add 'poetry-dynamic-versioning[plugin]' echo "Done installing dependencies" From 7aa946491dd6fbbc434478c038b2bbbe5163f138 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Sun, 18 Aug 2024 06:57:15 +0000 Subject: [PATCH 222/428] fix: the build system would try to install the binary files from an invalid path prefix Shall we file a bug in bugzilla? --- setup.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setup.sh b/setup.sh index ca7ab7c9..e564eb47 100755 --- a/setup.sh +++ b/setup.sh @@ -63,7 +63,8 @@ sed -i'' -e '/"winheap.cpp"/d' ./memory/mozalloc/moz.build # https://bugzilla.mo sed -i'' -e 's/"install-name-tool"/"install_name_tool"/' ./moz.configure # `install-name-tool` does not exist, but we have `install_name_tool` sed -i'' -e 's/bool Unbox/JS_PUBLIC_API bool Unbox/g' ./js/public/Class.h # need to manually add JS_PUBLIC_API to js::Unbox until it gets fixed in Spidermonkey sed -i'' -e 's/bool js::Unbox/JS_PUBLIC_API bool js::Unbox/g' ./js/src/vm/JSObject.cpp # same here -sed -i'' -e 's/shared_lib = self._pretty_path(libdef.output_path, backend_file)/shared_lib = libdef.lib_name/' ./python/mozbuild/mozbuild/backend/recursivemake.py +sed -i'' -e 's/shared_lib = self._pretty_path(libdef.output_path, backend_file)/shared_lib = libdef.lib_name/' ./python/mozbuild/mozbuild/backend/recursivemake.py # would generate a Makefile to install the binary files from an invalid path prefix +sed -i'' -e 's/% self._pretty_path(libdef.import_path, backend_file)/% libdef.import_name/' ./python/mozbuild/mozbuild/backend/recursivemake.py # same as above. Shall we file a bug in bugzilla? sed -i'' -e 's/if version < Version(mac_sdk_min_version())/if False/' ./build/moz.configure/toolchain.configure # do not verify the macOS SDK version as the required version is not available on Github Actions runner sed -i'' -e 's/return JS::GetWeakRefsEnabled() == JS::WeakRefSpecifier::Disabled/return false/' ./js/src/vm/GlobalObject.cpp # forcibly enable FinalizationRegistry sed -i'' -e 's/return !IsIteratorHelpersEnabled()/return false/' ./js/src/vm/GlobalObject.cpp # forcibly enable iterator helpers From e00885122c66dd771b15be572056f44e492393ae Mon Sep 17 00:00:00 2001 From: philippedistributive <151072087+philippedistributive@users.noreply.github.com> Date: Mon, 19 Aug 2024 14:07:16 +0000 Subject: [PATCH 223/428] chore(deps): upgrade SpiderMonkey to `8a28ad54f9f516c41ceddfa7ea32368fccf4a0eb` --- mozcentral.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mozcentral.version b/mozcentral.version index 758c56ec..0efd2b63 100644 --- a/mozcentral.version +++ b/mozcentral.version @@ -1 +1 @@ -bc4609b7aa7a3dff961f43d527bc66c5c85f6f4b \ No newline at end of file +8a28ad54f9f516c41ceddfa7ea32368fccf4a0eb \ No newline at end of file From a1f75bbc574f26f914b03e4f8adf017cce8386b3 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Mon, 19 Aug 2024 20:04:08 +0000 Subject: [PATCH 224/428] chore: remove the installation of doxygen + graphviz from `setup.sh` `doxygen` and `graphviz` are only required to generate the docs. Compiling PythonMonkey doesn't actually need them. The CI job to generate the docs (for https://docs.pythonmonkey.io/) will install doxygen on its own in https://github.com/Distributive-Network/PythonMonkey/blob/2633b5a/.github/workflows/test-and-publish.yaml#L168-L177. There's no point to install them automatically in `setup.sh`, if the user doesn't care about the docs. --- setup.sh | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/setup.sh b/setup.sh index 34ba0880..bbe1b272 100755 --- a/setup.sh +++ b/setup.sh @@ -13,18 +13,11 @@ if [[ "$OSTYPE" == "linux-gnu"* ]]; then # Linux SUDO='sudo' fi echo "Installing apt packages" - $SUDO apt-get install --yes cmake graphviz llvm clang pkg-config m4 unzip \ + $SUDO apt-get install --yes cmake llvm clang pkg-config m4 unzip \ wget curl python3-dev - # Install Doxygen - # the newest version in Ubuntu 20.04 repository is 1.8.17, but we need Doxygen 1.9 series - echo "Installing doxygen" - wget -c -q https://www.doxygen.nl/files/doxygen-1.9.7.linux.bin.tar.gz - tar xf doxygen-1.9.7.linux.bin.tar.gz - cd doxygen-1.9.7 && $SUDO make install && cd - - rm -rf doxygen-1.9.7 doxygen-1.9.7.linux.bin.tar.gz elif [[ "$OSTYPE" == "darwin"* ]]; then # macOS brew update || true # allow failure - brew install cmake doxygen pkg-config wget unzip coreutils # `coreutils` installs the `realpath` command + brew install cmake pkg-config wget unzip coreutils # `coreutils` installs the `realpath` command elif [[ "$OSTYPE" == "msys"* ]]; then # Windows echo "Dependencies are not going to be installed automatically on Windows." else From ef5a632387fbd9134c2382cc21ae904553b78e1b Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Mon, 19 Aug 2024 20:24:21 +0000 Subject: [PATCH 225/428] chore(CI): remove CI runs on Ubuntu 24.04 Binaries built on Ubuntu 20.04 (uses glibc version 2.31) can run on Ubuntu 24.04 (glibc version 2.38) without any problem, but not the other way around. We should only build on the lowest OS version possible. --- .github/workflows/test-and-publish.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index afcadfc9..6f3521c6 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -59,9 +59,9 @@ jobs: strategy: fail-fast: false matrix: - # Use Ubuntu 20.04 / Ubuntu 24.04 / macOS 13 x86_64 / macOS 14 arm64 + Python 3.10 to build SpiderMonkey - os: [ 'ubuntu-20.04', 'ubuntu-24.04', 'macos-13', 'macos-14', 'pi' ] # macOS 14 runner exclusively runs on M1 hardwares - # see https://github.blog/changelog/2024-01-30-github-actions-macos-14-sonoma-is-now-available + # Use Ubuntu 20.04 / macOS 13 x86_64 / macOS 14 arm64 + Python 3.10 to build SpiderMonkey + os: [ 'ubuntu-20.04', 'macos-13', 'macos-14', 'pi' ] # macOS 14 runner exclusively runs on M1 hardwares + # see https://github.blog/changelog/2024-01-30-github-actions-macos-14-sonoma-is-now-available python_version: [ '3.10' ] runs-on: ${{ matrix.os }} steps: @@ -127,7 +127,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ 'ubuntu-20.04', 'ubuntu-24.04', 'macos-12', 'macos-14', 'windows-2022', 'pi' ] + os: [ 'ubuntu-20.04', 'macos-12', 'macos-14', 'windows-2022', 'pi' ] python_version: [ '3.8', '3.9', '3.10', '3.11', '3.12' ] exclude: # actions/setup-python: The version '3.8'/'3.9' with architecture 'arm64' was not found for macOS. From 75141d878fdfe5a9b805235cd98fefcdaf10a9c6 Mon Sep 17 00:00:00 2001 From: Caleb Aikens Date: Tue, 20 Aug 2024 09:53:13 -0400 Subject: [PATCH 226/428] fix(JSStringProxy): keep track of all JSStringProxies and repoint their data pointers have a GC occurs --- include/JSStringProxy.hh | 16 ++++++++++------ src/JSStringProxy.cc | 3 ++- src/StrType.cc | 1 + src/modules/pythonmonkey/pythonmonkey.cc | 19 +++++++++++++++++-- 4 files changed, 30 insertions(+), 9 deletions(-) diff --git a/include/JSStringProxy.hh b/include/JSStringProxy.hh index fb376cc0..ed696c19 100644 --- a/include/JSStringProxy.hh +++ b/include/JSStringProxy.hh @@ -15,6 +15,8 @@ #include +#include + /** * @brief The typedef for the backing store that will be used by JSStringProxy objects. All it contains is a pointer to the JSString * @@ -24,6 +26,8 @@ typedef struct { JS::PersistentRootedValue *jsString; } JSStringProxy; +extern std::unordered_set jsStringProxies; // a collection of all JSStringProxy objects, used during a GCCallback to ensure they continue to point to the correct char buffer + /** * @brief This struct is a bundle of methods used by the JSStringProxy type * @@ -37,7 +41,7 @@ public: */ static void JSStringProxy_dealloc(JSStringProxy *self); - /** + /** * @brief copy protocol method for both copy and deepcopy * * @param self - The JSObjectProxy @@ -49,13 +53,13 @@ public: // docs for methods, copied from cpython PyDoc_STRVAR(stringproxy_deepcopy__doc__, "__deepcopy__($self, memo, /)\n" -"--\n" -"\n"); + "--\n" + "\n"); PyDoc_STRVAR(stringproxy_copy__doc__, -"__copy__($self, /)\n" -"--\n" -"\n"); + "__copy__($self, /)\n" + "--\n" + "\n"); /** * @brief Struct for the other methods diff --git a/src/JSStringProxy.cc b/src/JSStringProxy.cc index 90ae9d5a..2b68f6bb 100644 --- a/src/JSStringProxy.cc +++ b/src/JSStringProxy.cc @@ -12,12 +12,13 @@ #include "include/StrType.hh" - +std::unordered_set jsStringProxies; extern JSContext *GLOBAL_CX; void JSStringProxyMethodDefinitions::JSStringProxy_dealloc(JSStringProxy *self) { + jsStringProxies.erase(self); delete self->jsString; } diff --git a/src/StrType.cc b/src/StrType.cc index f01ce1ac..714bed7d 100644 --- a/src/StrType.cc +++ b/src/StrType.cc @@ -112,6 +112,7 @@ PyObject *StrType::proxifyString(JSContext *cx, JS::HandleValue strVal) { JS::RootedObject obj(cx); pyString->jsString = new JS::PersistentRootedValue(cx); pyString->jsString->setString((JSString *)lstr); + jsStringProxies.insert(pyString); // Initialize as legacy string (https://github.com/python/cpython/blob/v3.12.0b1/Include/cpython/unicodeobject.h#L78-L93) // see https://github.com/python/cpython/blob/v3.11.3/Objects/unicodeobject.c#L1230-L1245 diff --git a/src/modules/pythonmonkey/pythonmonkey.cc b/src/modules/pythonmonkey/pythonmonkey.cc index e49b6f81..93412150 100644 --- a/src/modules/pythonmonkey/pythonmonkey.cc +++ b/src/modules/pythonmonkey/pythonmonkey.cc @@ -48,10 +48,25 @@ JS::PersistentRootedObject jsFunctionRegistry; -void finalizationRegistryGCCallback(JSContext *cx, JSGCStatus status, JS::GCReason reason, void *data) { +void pythonmonkeyGCCallback(JSContext *cx, JSGCStatus status, JS::GCReason reason, void *data) { if (status == JSGCStatus::JSGC_END) { JS::ClearKeptObjects(GLOBAL_CX); while (JOB_QUEUE->runFinalizationRegistryCallbacks(GLOBAL_CX)); + + if (_Py_IsFinalizing()) { + return; // do not move char pointers around if python is finalizing + } + + JS::AutoCheckCannotGC nogc; + for (const JSStringProxy *jsStringProxy: jsStringProxies) { // char buffers may have moved, so we need to re-point our JSStringProxies + JSLinearString *str = (JSLinearString *)(jsStringProxy->jsString->toString()); // jsString is guaranteed to be linear + if (JS::LinearStringHasLatin1Chars(str)) { + (((PyUnicodeObject *)(jsStringProxy))->data.any) = (void *)JS::GetLatin1LinearStringChars(nogc, str); + } + else { // utf16 / ucs2 string + (((PyUnicodeObject *)(jsStringProxy))->data.any) = (void *)JS::GetTwoByteLinearStringChars(nogc, str); + } + } } } @@ -547,7 +562,7 @@ PyMODINIT_FUNC PyInit_pythonmonkey(void) return NULL; } - JS_SetGCCallback(GLOBAL_CX, finalizationRegistryGCCallback, NULL); + JS_SetGCCallback(GLOBAL_CX, pythonmonkeyGCCallback, NULL); JS::RealmCreationOptions creationOptions = JS::RealmCreationOptions(); JS::RealmBehaviors behaviours = JS::RealmBehaviors(); From d540ed6e0edfe9538dc726cf587dfb2cc76dde34 Mon Sep 17 00:00:00 2001 From: Caleb Aikens Date: Tue, 20 Aug 2024 10:35:31 -0400 Subject: [PATCH 227/428] chore(linting): lint PyBytesProxyHandler.cc --- src/PyBytesProxyHandler.cc | 44 +++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/PyBytesProxyHandler.cc b/src/PyBytesProxyHandler.cc index 753e67e5..d36fcd28 100644 --- a/src/PyBytesProxyHandler.cc +++ b/src/PyBytesProxyHandler.cc @@ -26,30 +26,30 @@ static bool array_valueOf(JSContext *cx, unsigned argc, JS::Value *vp) { return false; } - JS::PersistentRootedObject* arrayBuffer = JS::GetMaybePtrFromReservedSlot(proxy, OtherSlot); + JS::PersistentRootedObject *arrayBuffer = JS::GetMaybePtrFromReservedSlot(proxy, OtherSlot); JS::RootedObject rootedArrayBuffer(cx, arrayBuffer->get()); auto byteLength = JS::GetArrayBufferByteLength(rootedArrayBuffer); - bool isSharedMemory; + bool isSharedMemory; JS::AutoCheckCannotGC autoNoGC(cx); uint8_t *data = JS::GetArrayBufferData(rootedArrayBuffer, &isSharedMemory, autoNoGC); - + size_t numberOfDigits = 0; for (size_t i = 0; i < byteLength; i++) { - numberOfDigits += data[i] < 10 ? 1 : data[i] < 100 ? 2 : 3; + numberOfDigits += data[i] < 10 ? 1 : data[i] < 100 ? 2 : 3; } const size_t STRING_LENGTH = byteLength + numberOfDigits; - JS::Latin1Char* buffer = (JS::Latin1Char *)malloc(sizeof(JS::Latin1Char) * STRING_LENGTH); - + JS::Latin1Char *buffer = (JS::Latin1Char *)malloc(sizeof(JS::Latin1Char) * STRING_LENGTH); + size_t charIndex = 0; - sprintf((char*)&buffer[charIndex], "%d", data[0]); + sprintf((char *)&buffer[charIndex], "%d", data[0]); charIndex += data[0] < 10 ? 1 : data[0] < 100 ? 2 : 3; for (size_t dataIndex = 1; dataIndex < byteLength; dataIndex++) { buffer[charIndex] = ','; charIndex++; - sprintf((char*)&buffer[charIndex], "%d", data[dataIndex]); + sprintf((char *)&buffer[charIndex], "%d", data[dataIndex]); charIndex += data[dataIndex] < 10 ? 1 : data[dataIndex] < 100 ? 2 : 3; } @@ -84,7 +84,7 @@ static bool iterator_next(JSContext *cx, unsigned argc, JS::Value *vp) { JS::RootedObject thisObj(cx); if (!args.computeThis(cx, &thisObj)) return false; - JS::PersistentRootedObject* arrayBuffer = JS::GetMaybePtrFromReservedSlot(thisObj, BytesIteratorSlotIteratedObject); + JS::PersistentRootedObject *arrayBuffer = JS::GetMaybePtrFromReservedSlot(thisObj, BytesIteratorSlotIteratedObject); JS::RootedObject rootedArrayBuffer(cx, arrayBuffer->get()); JS::RootedValue rootedNextIndex(cx, JS::GetReservedSlot(thisObj, BytesIteratorSlotNextIndex)); @@ -112,7 +112,7 @@ static bool iterator_next(JSContext *cx, unsigned argc, JS::Value *vp) { if (!JS_SetProperty(cx, result, "done", done)) return false; if (itemKind == ITEM_KIND_VALUE) { - bool isSharedMemory; + bool isSharedMemory; JS::AutoCheckCannotGC autoNoGC(cx); uint8_t *data = JS::GetArrayBufferData(rootedArrayBuffer, &isSharedMemory, autoNoGC); @@ -125,7 +125,7 @@ static bool iterator_next(JSContext *cx, unsigned argc, JS::Value *vp) { JS::RootedValue rootedNextIndex(cx, JS::Int32Value(nextIndex)); items[0].set(rootedNextIndex); - bool isSharedMemory; + bool isSharedMemory; JS::AutoCheckCannotGC autoNoGC(cx); uint8_t *data = JS::GetArrayBufferData(rootedArrayBuffer, &isSharedMemory, autoNoGC); @@ -216,8 +216,8 @@ static bool array_iterator_func(JSContext *cx, unsigned argc, JS::Value *vp, int if (!JS::Construct(cx, constructor_val, JS::HandleValueArray::empty(), &obj)) return false; if (!obj) return false; - JS::PersistentRootedObject* arrayBuffer = JS::GetMaybePtrFromReservedSlot(proxy, OtherSlot); - + JS::PersistentRootedObject *arrayBuffer = JS::GetMaybePtrFromReservedSlot(proxy, OtherSlot); + JS::SetReservedSlot(obj, BytesIteratorSlotIteratedObject, JS::PrivateValue(arrayBuffer)); JS::SetReservedSlot(obj, BytesIteratorSlotNextIndex, JS::Int32Value(0)); JS::SetReservedSlot(obj, BytesIteratorSlotItemKind, JS::Int32Value(itemKind)); @@ -253,13 +253,13 @@ bool PyBytesProxyHandler::set(JSContext *cx, JS::HandleObject proxy, JS::HandleI JS::HandleValue v, JS::HandleValue receiver, JS::ObjectOpResult &result) const { - // block all modifications - + // block all modifications + PyObject *self = JS::GetMaybePtrFromReservedSlot(proxy, PyObjectSlot); PyErr_Format(PyExc_TypeError, - "'%.100s' object has only read-only attributes", - Py_TYPE(self)->tp_name); + "'%.100s' object has only read-only attributes", + Py_TYPE(self)->tp_name); return result.failReadOnly(); } @@ -298,7 +298,7 @@ bool PyBytesProxyHandler::getOwnPropertyDescriptor( // "length" and "byteLength" properties have the same value if ((JS_StringEqualsLiteral(cx, idString, "length", &isProperty) && isProperty) || (JS_StringEqualsLiteral(cx, id.toString(), "byteLength", &isProperty) && isProperty)) { - JS::PersistentRootedObject* arrayBuffer = JS::GetMaybePtrFromReservedSlot(proxy, OtherSlot); + JS::PersistentRootedObject *arrayBuffer = JS::GetMaybePtrFromReservedSlot(proxy, OtherSlot); JS::RootedObject rootedArrayBuffer(cx, arrayBuffer->get()); @@ -314,7 +314,7 @@ bool PyBytesProxyHandler::getOwnPropertyDescriptor( // "buffer" property if (JS_StringEqualsLiteral(cx, idString, "buffer", &isProperty) && isProperty) { - JS::PersistentRootedObject* arrayBuffer = JS::GetMaybePtrFromReservedSlot(proxy, OtherSlot); + JS::PersistentRootedObject *arrayBuffer = JS::GetMaybePtrFromReservedSlot(proxy, OtherSlot); desc.set(mozilla::Some( JS::PropertyDescriptor::Data( @@ -392,10 +392,10 @@ bool PyBytesProxyHandler::getOwnPropertyDescriptor( // item Py_ssize_t index; if (idToIndex(cx, id, &index)) { - JS::PersistentRootedObject* arrayBuffer = JS::GetMaybePtrFromReservedSlot(proxy, OtherSlot); + JS::PersistentRootedObject *arrayBuffer = JS::GetMaybePtrFromReservedSlot(proxy, OtherSlot); JS::RootedObject rootedArrayBuffer(cx, arrayBuffer->get()); - bool isSharedMemory; + bool isSharedMemory; JS::AutoCheckCannotGC autoNoGC(cx); uint8_t *data = JS::GetArrayBufferData(rootedArrayBuffer, &isSharedMemory, autoNoGC); @@ -406,7 +406,7 @@ bool PyBytesProxyHandler::getOwnPropertyDescriptor( )); return true; - } + } PyObject *attrName = idToKey(cx, id); PyObject *self = JS::GetMaybePtrFromReservedSlot(proxy, PyObjectSlot); From fadb7a69238bfb209b5dedd8b8f4a8faeef24cc2 Mon Sep 17 00:00:00 2001 From: Caleb Aikens Date: Tue, 20 Aug 2024 10:36:20 -0400 Subject: [PATCH 228/428] chore(meta): update .git-blame-ignore-revs --- .git-blame-ignore-revs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index a1715720..eace15d3 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -5,4 +5,7 @@ aae30e864449442cf0b04e94f8a242b1b667de9a 16dc3153b3cb684ca72445ed058babc8f5d97f42 # chore(linting): lint all C++ files -58cd4b45777b046f03a63255c1d93e289e1cab5e \ No newline at end of file +58cd4b45777b046f03a63255c1d93e289e1cab5e + +# chore(linting): lint PyBytesProxyHandler.cc +d540ed6e0edfe9538dc726cf587dfb2cc76dde34 \ No newline at end of file From 3c585e24740db98c8e13be897a226a8ae9e8821c Mon Sep 17 00:00:00 2001 From: Caleb Aikens Date: Tue, 20 Aug 2024 10:37:06 -0400 Subject: [PATCH 229/428] chore(meta): fix sprintf warnings --- src/PyBytesProxyHandler.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PyBytesProxyHandler.cc b/src/PyBytesProxyHandler.cc index d36fcd28..14da16c9 100644 --- a/src/PyBytesProxyHandler.cc +++ b/src/PyBytesProxyHandler.cc @@ -43,13 +43,13 @@ static bool array_valueOf(JSContext *cx, unsigned argc, JS::Value *vp) { JS::Latin1Char *buffer = (JS::Latin1Char *)malloc(sizeof(JS::Latin1Char) * STRING_LENGTH); size_t charIndex = 0; - sprintf((char *)&buffer[charIndex], "%d", data[0]); + snprintf((char *)&buffer[charIndex], 4, "%d", data[0]); charIndex += data[0] < 10 ? 1 : data[0] < 100 ? 2 : 3; for (size_t dataIndex = 1; dataIndex < byteLength; dataIndex++) { buffer[charIndex] = ','; charIndex++; - sprintf((char *)&buffer[charIndex], "%d", data[dataIndex]); + snprintf((char *)&buffer[charIndex], 4, "%d", data[dataIndex]); charIndex += data[dataIndex] < 10 ? 1 : data[dataIndex] < 100 ? 2 : 3; } From a9144eabd79b2e66c44e51b122d2d5901104c6df Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 21 Aug 2024 21:22:00 +0000 Subject: [PATCH 230/428] chore(deps): upgrade numpy to support Python 3.13 NumPy 2.1.0 added support for Python 3.13, but drops support for Python 3.9. See https://numpy.org/news/#numpy-210-released --- poetry.lock | 512 ++++++++++++++++++++++++++++++------------------- pyproject.toml | 5 +- 2 files changed, 315 insertions(+), 202 deletions(-) diff --git a/poetry.lock b/poetry.lock index 5c5912ae..29419286 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,106 +1,133 @@ -# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. [[package]] name = "aiodns" -version = "3.1.1" +version = "3.2.0" description = "Simple DNS resolver for asyncio" optional = false python-versions = "*" files = [ - {file = "aiodns-3.1.1-py3-none-any.whl", hash = "sha256:a387b63da4ced6aad35b1dda2d09620ad608a1c7c0fb71efa07ebb4cd511928d"}, - {file = "aiodns-3.1.1.tar.gz", hash = "sha256:1073eac48185f7a4150cad7f96a5192d6911f12b4fb894de80a088508c9b3a99"}, + {file = "aiodns-3.2.0-py3-none-any.whl", hash = "sha256:e443c0c27b07da3174a109fd9e736d69058d808f144d3c9d56dbd1776964c5f5"}, + {file = "aiodns-3.2.0.tar.gz", hash = "sha256:62869b23409349c21b072883ec8998316b234c9a9e36675756e8e317e8768f72"}, ] [package.dependencies] pycares = ">=4.0.0" +[[package]] +name = "aiohappyeyeballs" +version = "2.4.0" +description = "Happy Eyeballs for asyncio" +optional = false +python-versions = ">=3.8" +files = [ + {file = "aiohappyeyeballs-2.4.0-py3-none-any.whl", hash = "sha256:7ce92076e249169a13c2f49320d1967425eaf1f407522d707d59cac7628d62bd"}, + {file = "aiohappyeyeballs-2.4.0.tar.gz", hash = "sha256:55a1714f084e63d49639800f95716da97a1f173d46a16dfcfda0016abb93b6b2"}, +] + [[package]] name = "aiohttp" -version = "3.9.5" +version = "3.10.5" description = "Async http client/server framework (asyncio)" optional = false python-versions = ">=3.8" files = [ - {file = "aiohttp-3.9.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:fcde4c397f673fdec23e6b05ebf8d4751314fa7c24f93334bf1f1364c1c69ac7"}, - {file = "aiohttp-3.9.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5d6b3f1fabe465e819aed2c421a6743d8debbde79b6a8600739300630a01bf2c"}, - {file = "aiohttp-3.9.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6ae79c1bc12c34082d92bf9422764f799aee4746fd7a392db46b7fd357d4a17a"}, - {file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d3ebb9e1316ec74277d19c5f482f98cc65a73ccd5430540d6d11682cd857430"}, - {file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84dabd95154f43a2ea80deffec9cb44d2e301e38a0c9d331cc4aa0166fe28ae3"}, - {file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c8a02fbeca6f63cb1f0475c799679057fc9268b77075ab7cf3f1c600e81dd46b"}, - {file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c26959ca7b75ff768e2776d8055bf9582a6267e24556bb7f7bd29e677932be72"}, - {file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:714d4e5231fed4ba2762ed489b4aec07b2b9953cf4ee31e9871caac895a839c0"}, - {file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e7a6a8354f1b62e15d48e04350f13e726fa08b62c3d7b8401c0a1314f02e3558"}, - {file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:c413016880e03e69d166efb5a1a95d40f83d5a3a648d16486592c49ffb76d0db"}, - {file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:ff84aeb864e0fac81f676be9f4685f0527b660f1efdc40dcede3c251ef1e867f"}, - {file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:ad7f2919d7dac062f24d6f5fe95d401597fbb015a25771f85e692d043c9d7832"}, - {file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:702e2c7c187c1a498a4e2b03155d52658fdd6fda882d3d7fbb891a5cf108bb10"}, - {file = "aiohttp-3.9.5-cp310-cp310-win32.whl", hash = "sha256:67c3119f5ddc7261d47163ed86d760ddf0e625cd6246b4ed852e82159617b5fb"}, - {file = "aiohttp-3.9.5-cp310-cp310-win_amd64.whl", hash = "sha256:471f0ef53ccedec9995287f02caf0c068732f026455f07db3f01a46e49d76bbb"}, - {file = "aiohttp-3.9.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e0ae53e33ee7476dd3d1132f932eeb39bf6125083820049d06edcdca4381f342"}, - {file = "aiohttp-3.9.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c088c4d70d21f8ca5c0b8b5403fe84a7bc8e024161febdd4ef04575ef35d474d"}, - {file = "aiohttp-3.9.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:639d0042b7670222f33b0028de6b4e2fad6451462ce7df2af8aee37dcac55424"}, - {file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f26383adb94da5e7fb388d441bf09c61e5e35f455a3217bfd790c6b6bc64b2ee"}, - {file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:66331d00fb28dc90aa606d9a54304af76b335ae204d1836f65797d6fe27f1ca2"}, - {file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4ff550491f5492ab5ed3533e76b8567f4b37bd2995e780a1f46bca2024223233"}, - {file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f22eb3a6c1080d862befa0a89c380b4dafce29dc6cd56083f630073d102eb595"}, - {file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a81b1143d42b66ffc40a441379387076243ef7b51019204fd3ec36b9f69e77d6"}, - {file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f64fd07515dad67f24b6ea4a66ae2876c01031de91c93075b8093f07c0a2d93d"}, - {file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:93e22add827447d2e26d67c9ac0161756007f152fdc5210277d00a85f6c92323"}, - {file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:55b39c8684a46e56ef8c8d24faf02de4a2b2ac60d26cee93bc595651ff545de9"}, - {file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4715a9b778f4293b9f8ae7a0a7cef9829f02ff8d6277a39d7f40565c737d3771"}, - {file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:afc52b8d969eff14e069a710057d15ab9ac17cd4b6753042c407dcea0e40bf75"}, - {file = "aiohttp-3.9.5-cp311-cp311-win32.whl", hash = "sha256:b3df71da99c98534be076196791adca8819761f0bf6e08e07fd7da25127150d6"}, - {file = "aiohttp-3.9.5-cp311-cp311-win_amd64.whl", hash = "sha256:88e311d98cc0bf45b62fc46c66753a83445f5ab20038bcc1b8a1cc05666f428a"}, - {file = "aiohttp-3.9.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:c7a4b7a6cf5b6eb11e109a9755fd4fda7d57395f8c575e166d363b9fc3ec4678"}, - {file = "aiohttp-3.9.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:0a158704edf0abcac8ac371fbb54044f3270bdbc93e254a82b6c82be1ef08f3c"}, - {file = "aiohttp-3.9.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d153f652a687a8e95ad367a86a61e8d53d528b0530ef382ec5aaf533140ed00f"}, - {file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82a6a97d9771cb48ae16979c3a3a9a18b600a8505b1115cfe354dfb2054468b4"}, - {file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:60cdbd56f4cad9f69c35eaac0fbbdf1f77b0ff9456cebd4902f3dd1cf096464c"}, - {file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8676e8fd73141ded15ea586de0b7cda1542960a7b9ad89b2b06428e97125d4fa"}, - {file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da00da442a0e31f1c69d26d224e1efd3a1ca5bcbf210978a2ca7426dfcae9f58"}, - {file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:18f634d540dd099c262e9f887c8bbacc959847cfe5da7a0e2e1cf3f14dbf2daf"}, - {file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:320e8618eda64e19d11bdb3bd04ccc0a816c17eaecb7e4945d01deee2a22f95f"}, - {file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:2faa61a904b83142747fc6a6d7ad8fccff898c849123030f8e75d5d967fd4a81"}, - {file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:8c64a6dc3fe5db7b1b4d2b5cb84c4f677768bdc340611eca673afb7cf416ef5a"}, - {file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:393c7aba2b55559ef7ab791c94b44f7482a07bf7640d17b341b79081f5e5cd1a"}, - {file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:c671dc117c2c21a1ca10c116cfcd6e3e44da7fcde37bf83b2be485ab377b25da"}, - {file = "aiohttp-3.9.5-cp312-cp312-win32.whl", hash = "sha256:5a7ee16aab26e76add4afc45e8f8206c95d1d75540f1039b84a03c3b3800dd59"}, - {file = "aiohttp-3.9.5-cp312-cp312-win_amd64.whl", hash = "sha256:5ca51eadbd67045396bc92a4345d1790b7301c14d1848feaac1d6a6c9289e888"}, - {file = "aiohttp-3.9.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:694d828b5c41255e54bc2dddb51a9f5150b4eefa9886e38b52605a05d96566e8"}, - {file = "aiohttp-3.9.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0605cc2c0088fcaae79f01c913a38611ad09ba68ff482402d3410bf59039bfb8"}, - {file = "aiohttp-3.9.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4558e5012ee03d2638c681e156461d37b7a113fe13970d438d95d10173d25f78"}, - {file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dbc053ac75ccc63dc3a3cc547b98c7258ec35a215a92bd9f983e0aac95d3d5b"}, - {file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4109adee842b90671f1b689901b948f347325045c15f46b39797ae1bf17019de"}, - {file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6ea1a5b409a85477fd8e5ee6ad8f0e40bf2844c270955e09360418cfd09abac"}, - {file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3c2890ca8c59ee683fd09adf32321a40fe1cf164e3387799efb2acebf090c11"}, - {file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3916c8692dbd9d55c523374a3b8213e628424d19116ac4308e434dbf6d95bbdd"}, - {file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8d1964eb7617907c792ca00b341b5ec3e01ae8c280825deadbbd678447b127e1"}, - {file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:d5ab8e1f6bee051a4bf6195e38a5c13e5e161cb7bad83d8854524798bd9fcd6e"}, - {file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:52c27110f3862a1afbcb2af4281fc9fdc40327fa286c4625dfee247c3ba90156"}, - {file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:7f64cbd44443e80094309875d4f9c71d0401e966d191c3d469cde4642bc2e031"}, - {file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8b4f72fbb66279624bfe83fd5eb6aea0022dad8eec62b71e7bf63ee1caadeafe"}, - {file = "aiohttp-3.9.5-cp38-cp38-win32.whl", hash = "sha256:6380c039ec52866c06d69b5c7aad5478b24ed11696f0e72f6b807cfb261453da"}, - {file = "aiohttp-3.9.5-cp38-cp38-win_amd64.whl", hash = "sha256:da22dab31d7180f8c3ac7c7635f3bcd53808f374f6aa333fe0b0b9e14b01f91a"}, - {file = "aiohttp-3.9.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1732102949ff6087589408d76cd6dea656b93c896b011ecafff418c9661dc4ed"}, - {file = "aiohttp-3.9.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c6021d296318cb6f9414b48e6a439a7f5d1f665464da507e8ff640848ee2a58a"}, - {file = "aiohttp-3.9.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:239f975589a944eeb1bad26b8b140a59a3a320067fb3cd10b75c3092405a1372"}, - {file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b7b30258348082826d274504fbc7c849959f1989d86c29bc355107accec6cfb"}, - {file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cd2adf5c87ff6d8b277814a28a535b59e20bfea40a101db6b3bdca7e9926bc24"}, - {file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e9a3d838441bebcf5cf442700e3963f58b5c33f015341f9ea86dcd7d503c07e2"}, - {file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e3a1ae66e3d0c17cf65c08968a5ee3180c5a95920ec2731f53343fac9bad106"}, - {file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9c69e77370cce2d6df5d12b4e12bdcca60c47ba13d1cbbc8645dd005a20b738b"}, - {file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0cbf56238f4bbf49dab8c2dc2e6b1b68502b1e88d335bea59b3f5b9f4c001475"}, - {file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:d1469f228cd9ffddd396d9948b8c9cd8022b6d1bf1e40c6f25b0fb90b4f893ed"}, - {file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:45731330e754f5811c314901cebdf19dd776a44b31927fa4b4dbecab9e457b0c"}, - {file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:3fcb4046d2904378e3aeea1df51f697b0467f2aac55d232c87ba162709478c46"}, - {file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8cf142aa6c1a751fcb364158fd710b8a9be874b81889c2bd13aa8893197455e2"}, - {file = "aiohttp-3.9.5-cp39-cp39-win32.whl", hash = "sha256:7b179eea70833c8dee51ec42f3b4097bd6370892fa93f510f76762105568cf09"}, - {file = "aiohttp-3.9.5-cp39-cp39-win_amd64.whl", hash = "sha256:38d80498e2e169bc61418ff36170e0aad0cd268da8b38a17c4cf29d254a8b3f1"}, - {file = "aiohttp-3.9.5.tar.gz", hash = "sha256:edea7d15772ceeb29db4aff55e482d4bcfb6ae160ce144f2682de02f6d693551"}, + {file = "aiohttp-3.10.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:18a01eba2574fb9edd5f6e5fb25f66e6ce061da5dab5db75e13fe1558142e0a3"}, + {file = "aiohttp-3.10.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:94fac7c6e77ccb1ca91e9eb4cb0ac0270b9fb9b289738654120ba8cebb1189c6"}, + {file = "aiohttp-3.10.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2f1f1c75c395991ce9c94d3e4aa96e5c59c8356a15b1c9231e783865e2772699"}, + {file = "aiohttp-3.10.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f7acae3cf1a2a2361ec4c8e787eaaa86a94171d2417aae53c0cca6ca3118ff6"}, + {file = "aiohttp-3.10.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:94c4381ffba9cc508b37d2e536b418d5ea9cfdc2848b9a7fea6aebad4ec6aac1"}, + {file = "aiohttp-3.10.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c31ad0c0c507894e3eaa843415841995bf8de4d6b2d24c6e33099f4bc9fc0d4f"}, + {file = "aiohttp-3.10.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0912b8a8fadeb32ff67a3ed44249448c20148397c1ed905d5dac185b4ca547bb"}, + {file = "aiohttp-3.10.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d93400c18596b7dc4794d48a63fb361b01a0d8eb39f28800dc900c8fbdaca91"}, + {file = "aiohttp-3.10.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d00f3c5e0d764a5c9aa5a62d99728c56d455310bcc288a79cab10157b3af426f"}, + {file = "aiohttp-3.10.5-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:d742c36ed44f2798c8d3f4bc511f479b9ceef2b93f348671184139e7d708042c"}, + {file = "aiohttp-3.10.5-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:814375093edae5f1cb31e3407997cf3eacefb9010f96df10d64829362ae2df69"}, + {file = "aiohttp-3.10.5-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8224f98be68a84b19f48e0bdc14224b5a71339aff3a27df69989fa47d01296f3"}, + {file = "aiohttp-3.10.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d9a487ef090aea982d748b1b0d74fe7c3950b109df967630a20584f9a99c0683"}, + {file = "aiohttp-3.10.5-cp310-cp310-win32.whl", hash = "sha256:d9ef084e3dc690ad50137cc05831c52b6ca428096e6deb3c43e95827f531d5ef"}, + {file = "aiohttp-3.10.5-cp310-cp310-win_amd64.whl", hash = "sha256:66bf9234e08fe561dccd62083bf67400bdbf1c67ba9efdc3dac03650e97c6088"}, + {file = "aiohttp-3.10.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8c6a4e5e40156d72a40241a25cc226051c0a8d816610097a8e8f517aeacd59a2"}, + {file = "aiohttp-3.10.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c634a3207a5445be65536d38c13791904fda0748b9eabf908d3fe86a52941cf"}, + {file = "aiohttp-3.10.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4aff049b5e629ef9b3e9e617fa6e2dfeda1bf87e01bcfecaf3949af9e210105e"}, + {file = "aiohttp-3.10.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1942244f00baaacaa8155eca94dbd9e8cc7017deb69b75ef67c78e89fdad3c77"}, + {file = "aiohttp-3.10.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e04a1f2a65ad2f93aa20f9ff9f1b672bf912413e5547f60749fa2ef8a644e061"}, + {file = "aiohttp-3.10.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7f2bfc0032a00405d4af2ba27f3c429e851d04fad1e5ceee4080a1c570476697"}, + {file = "aiohttp-3.10.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:424ae21498790e12eb759040bbb504e5e280cab64693d14775c54269fd1d2bb7"}, + {file = "aiohttp-3.10.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:975218eee0e6d24eb336d0328c768ebc5d617609affaca5dbbd6dd1984f16ed0"}, + {file = "aiohttp-3.10.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4120d7fefa1e2d8fb6f650b11489710091788de554e2b6f8347c7a20ceb003f5"}, + {file = "aiohttp-3.10.5-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:b90078989ef3fc45cf9221d3859acd1108af7560c52397ff4ace8ad7052a132e"}, + {file = "aiohttp-3.10.5-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:ba5a8b74c2a8af7d862399cdedce1533642fa727def0b8c3e3e02fcb52dca1b1"}, + {file = "aiohttp-3.10.5-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:02594361128f780eecc2a29939d9dfc870e17b45178a867bf61a11b2a4367277"}, + {file = "aiohttp-3.10.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8fb4fc029e135859f533025bc82047334e24b0d489e75513144f25408ecaf058"}, + {file = "aiohttp-3.10.5-cp311-cp311-win32.whl", hash = "sha256:e1ca1ef5ba129718a8fc827b0867f6aa4e893c56eb00003b7367f8a733a9b072"}, + {file = "aiohttp-3.10.5-cp311-cp311-win_amd64.whl", hash = "sha256:349ef8a73a7c5665cca65c88ab24abe75447e28aa3bc4c93ea5093474dfdf0ff"}, + {file = "aiohttp-3.10.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:305be5ff2081fa1d283a76113b8df7a14c10d75602a38d9f012935df20731487"}, + {file = "aiohttp-3.10.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3a1c32a19ee6bbde02f1cb189e13a71b321256cc1d431196a9f824050b160d5a"}, + {file = "aiohttp-3.10.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:61645818edd40cc6f455b851277a21bf420ce347baa0b86eaa41d51ef58ba23d"}, + {file = "aiohttp-3.10.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c225286f2b13bab5987425558baa5cbdb2bc925b2998038fa028245ef421e75"}, + {file = "aiohttp-3.10.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8ba01ebc6175e1e6b7275c907a3a36be48a2d487549b656aa90c8a910d9f3178"}, + {file = "aiohttp-3.10.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8eaf44ccbc4e35762683078b72bf293f476561d8b68ec8a64f98cf32811c323e"}, + {file = "aiohttp-3.10.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1c43eb1ab7cbf411b8e387dc169acb31f0ca0d8c09ba63f9eac67829585b44f"}, + {file = "aiohttp-3.10.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de7a5299827253023c55ea549444e058c0eb496931fa05d693b95140a947cb73"}, + {file = "aiohttp-3.10.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4790f0e15f00058f7599dab2b206d3049d7ac464dc2e5eae0e93fa18aee9e7bf"}, + {file = "aiohttp-3.10.5-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:44b324a6b8376a23e6ba25d368726ee3bc281e6ab306db80b5819999c737d820"}, + {file = "aiohttp-3.10.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:0d277cfb304118079e7044aad0b76685d30ecb86f83a0711fc5fb257ffe832ca"}, + {file = "aiohttp-3.10.5-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:54d9ddea424cd19d3ff6128601a4a4d23d54a421f9b4c0fff740505813739a91"}, + {file = "aiohttp-3.10.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4f1c9866ccf48a6df2b06823e6ae80573529f2af3a0992ec4fe75b1a510df8a6"}, + {file = "aiohttp-3.10.5-cp312-cp312-win32.whl", hash = "sha256:dc4826823121783dccc0871e3f405417ac116055bf184ac04c36f98b75aacd12"}, + {file = "aiohttp-3.10.5-cp312-cp312-win_amd64.whl", hash = "sha256:22c0a23a3b3138a6bf76fc553789cb1a703836da86b0f306b6f0dc1617398abc"}, + {file = "aiohttp-3.10.5-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7f6b639c36734eaa80a6c152a238242bedcee9b953f23bb887e9102976343092"}, + {file = "aiohttp-3.10.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f29930bc2921cef955ba39a3ff87d2c4398a0394ae217f41cb02d5c26c8b1b77"}, + {file = "aiohttp-3.10.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f489a2c9e6455d87eabf907ac0b7d230a9786be43fbe884ad184ddf9e9c1e385"}, + {file = "aiohttp-3.10.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:123dd5b16b75b2962d0fff566effb7a065e33cd4538c1692fb31c3bda2bfb972"}, + {file = "aiohttp-3.10.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b98e698dc34966e5976e10bbca6d26d6724e6bdea853c7c10162a3235aba6e16"}, + {file = "aiohttp-3.10.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c3b9162bab7e42f21243effc822652dc5bb5e8ff42a4eb62fe7782bcbcdfacf6"}, + {file = "aiohttp-3.10.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1923a5c44061bffd5eebeef58cecf68096e35003907d8201a4d0d6f6e387ccaa"}, + {file = "aiohttp-3.10.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d55f011da0a843c3d3df2c2cf4e537b8070a419f891c930245f05d329c4b0689"}, + {file = "aiohttp-3.10.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:afe16a84498441d05e9189a15900640a2d2b5e76cf4efe8cbb088ab4f112ee57"}, + {file = "aiohttp-3.10.5-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f8112fb501b1e0567a1251a2fd0747baae60a4ab325a871e975b7bb67e59221f"}, + {file = "aiohttp-3.10.5-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:1e72589da4c90337837fdfe2026ae1952c0f4a6e793adbbfbdd40efed7c63599"}, + {file = "aiohttp-3.10.5-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:4d46c7b4173415d8e583045fbc4daa48b40e31b19ce595b8d92cf639396c15d5"}, + {file = "aiohttp-3.10.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:33e6bc4bab477c772a541f76cd91e11ccb6d2efa2b8d7d7883591dfb523e5987"}, + {file = "aiohttp-3.10.5-cp313-cp313-win32.whl", hash = "sha256:c58c6837a2c2a7cf3133983e64173aec11f9c2cd8e87ec2fdc16ce727bcf1a04"}, + {file = "aiohttp-3.10.5-cp313-cp313-win_amd64.whl", hash = "sha256:38172a70005252b6893088c0f5e8a47d173df7cc2b2bd88650957eb84fcf5022"}, + {file = "aiohttp-3.10.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:f6f18898ace4bcd2d41a122916475344a87f1dfdec626ecde9ee802a711bc569"}, + {file = "aiohttp-3.10.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5ede29d91a40ba22ac1b922ef510aab871652f6c88ef60b9dcdf773c6d32ad7a"}, + {file = "aiohttp-3.10.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:673f988370f5954df96cc31fd99c7312a3af0a97f09e407399f61583f30da9bc"}, + {file = "aiohttp-3.10.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:58718e181c56a3c02d25b09d4115eb02aafe1a732ce5714ab70326d9776457c3"}, + {file = "aiohttp-3.10.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4b38b1570242fbab8d86a84128fb5b5234a2f70c2e32f3070143a6d94bc854cf"}, + {file = "aiohttp-3.10.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:074d1bff0163e107e97bd48cad9f928fa5a3eb4b9d33366137ffce08a63e37fe"}, + {file = "aiohttp-3.10.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd31f176429cecbc1ba499d4aba31aaccfea488f418d60376b911269d3b883c5"}, + {file = "aiohttp-3.10.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7384d0b87d4635ec38db9263e6a3f1eb609e2e06087f0aa7f63b76833737b471"}, + {file = "aiohttp-3.10.5-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:8989f46f3d7ef79585e98fa991e6ded55d2f48ae56d2c9fa5e491a6e4effb589"}, + {file = "aiohttp-3.10.5-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:c83f7a107abb89a227d6c454c613e7606c12a42b9a4ca9c5d7dad25d47c776ae"}, + {file = "aiohttp-3.10.5-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:cde98f323d6bf161041e7627a5fd763f9fd829bcfcd089804a5fdce7bb6e1b7d"}, + {file = "aiohttp-3.10.5-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:676f94c5480d8eefd97c0c7e3953315e4d8c2b71f3b49539beb2aa676c58272f"}, + {file = "aiohttp-3.10.5-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:2d21ac12dc943c68135ff858c3a989f2194a709e6e10b4c8977d7fcd67dfd511"}, + {file = "aiohttp-3.10.5-cp38-cp38-win32.whl", hash = "sha256:17e997105bd1a260850272bfb50e2a328e029c941c2708170d9d978d5a30ad9a"}, + {file = "aiohttp-3.10.5-cp38-cp38-win_amd64.whl", hash = "sha256:1c19de68896747a2aa6257ae4cf6ef59d73917a36a35ee9d0a6f48cff0f94db8"}, + {file = "aiohttp-3.10.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7e2fe37ac654032db1f3499fe56e77190282534810e2a8e833141a021faaab0e"}, + {file = "aiohttp-3.10.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f5bf3ead3cb66ab990ee2561373b009db5bc0e857549b6c9ba84b20bc462e172"}, + {file = "aiohttp-3.10.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1b2c16a919d936ca87a3c5f0e43af12a89a3ce7ccbce59a2d6784caba945b68b"}, + {file = "aiohttp-3.10.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad146dae5977c4dd435eb31373b3fe9b0b1bf26858c6fc452bf6af394067e10b"}, + {file = "aiohttp-3.10.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8c5c6fa16412b35999320f5c9690c0f554392dc222c04e559217e0f9ae244b92"}, + {file = "aiohttp-3.10.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:95c4dc6f61d610bc0ee1edc6f29d993f10febfe5b76bb470b486d90bbece6b22"}, + {file = "aiohttp-3.10.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da452c2c322e9ce0cfef392e469a26d63d42860f829026a63374fde6b5c5876f"}, + {file = "aiohttp-3.10.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:898715cf566ec2869d5cb4d5fb4be408964704c46c96b4be267442d265390f32"}, + {file = "aiohttp-3.10.5-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:391cc3a9c1527e424c6865e087897e766a917f15dddb360174a70467572ac6ce"}, + {file = "aiohttp-3.10.5-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:380f926b51b92d02a34119d072f178d80bbda334d1a7e10fa22d467a66e494db"}, + {file = "aiohttp-3.10.5-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ce91db90dbf37bb6fa0997f26574107e1b9d5ff939315247b7e615baa8ec313b"}, + {file = "aiohttp-3.10.5-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:9093a81e18c45227eebe4c16124ebf3e0d893830c6aca7cc310bfca8fe59d857"}, + {file = "aiohttp-3.10.5-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:ee40b40aa753d844162dcc80d0fe256b87cba48ca0054f64e68000453caead11"}, + {file = "aiohttp-3.10.5-cp39-cp39-win32.whl", hash = "sha256:03f2645adbe17f274444953bdea69f8327e9d278d961d85657cb0d06864814c1"}, + {file = "aiohttp-3.10.5-cp39-cp39-win_amd64.whl", hash = "sha256:d17920f18e6ee090bdd3d0bfffd769d9f2cb4c8ffde3eb203777a3895c128862"}, + {file = "aiohttp-3.10.5.tar.gz", hash = "sha256:f071854b47d39591ce9a17981c46790acb30518e2f83dfca8db2dfa091178691"}, ] [package.dependencies] -aiodns = {version = "*", optional = true, markers = "(sys_platform == \"linux\" or sys_platform == \"darwin\") and extra == \"speedups\""} +aiodns = {version = ">=3.2.0", optional = true, markers = "(sys_platform == \"linux\" or sys_platform == \"darwin\") and extra == \"speedups\""} +aiohappyeyeballs = ">=2.3.0" aiosignal = ">=1.1.2" async-timeout = {version = ">=4.0,<5.0", markers = "python_version < \"3.11\""} attrs = ">=17.3.0" @@ -111,7 +138,7 @@ multidict = ">=4.5,<7.0" yarl = ">=1.0,<2.0" [package.extras] -speedups = ["Brotli", "aiodns", "brotlicffi"] +speedups = ["Brotli", "aiodns (>=3.2.0)", "brotlicffi"] [[package]] name = "aiosignal" @@ -140,22 +167,22 @@ files = [ [[package]] name = "attrs" -version = "23.2.0" +version = "24.2.0" description = "Classes Without Boilerplate" optional = false python-versions = ">=3.7" files = [ - {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"}, - {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"}, + {file = "attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2"}, + {file = "attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346"}, ] [package.extras] -cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] -dev = ["attrs[tests]", "pre-commit"] -docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] -tests = ["attrs[tests-no-zope]", "zope-interface"] -tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"] -tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"] +benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"] +tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"] [[package]] name = "brotli" @@ -290,63 +317,78 @@ cffi = ">=1.0.0" [[package]] name = "cffi" -version = "1.16.0" +version = "1.17.0" description = "Foreign Function Interface for Python calling C code." optional = false python-versions = ">=3.8" files = [ - {file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"}, - {file = "cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614"}, - {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743"}, - {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d"}, - {file = "cffi-1.16.0-cp310-cp310-win32.whl", hash = "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a"}, - {file = "cffi-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1"}, - {file = "cffi-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404"}, - {file = "cffi-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e"}, - {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc"}, - {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb"}, - {file = "cffi-1.16.0-cp311-cp311-win32.whl", hash = "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab"}, - {file = "cffi-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba"}, - {file = "cffi-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956"}, - {file = "cffi-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969"}, - {file = "cffi-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520"}, - {file = "cffi-1.16.0-cp312-cp312-win32.whl", hash = "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b"}, - {file = "cffi-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235"}, - {file = "cffi-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324"}, - {file = "cffi-1.16.0-cp38-cp38-win32.whl", hash = "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a"}, - {file = "cffi-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36"}, - {file = "cffi-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed"}, - {file = "cffi-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098"}, - {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000"}, - {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe"}, - {file = "cffi-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4"}, - {file = "cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8"}, - {file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"}, + {file = "cffi-1.17.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f9338cc05451f1942d0d8203ec2c346c830f8e86469903d5126c1f0a13a2bcbb"}, + {file = "cffi-1.17.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a0ce71725cacc9ebf839630772b07eeec220cbb5f03be1399e0457a1464f8e1a"}, + {file = "cffi-1.17.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c815270206f983309915a6844fe994b2fa47e5d05c4c4cef267c3b30e34dbe42"}, + {file = "cffi-1.17.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6bdcd415ba87846fd317bee0774e412e8792832e7805938987e4ede1d13046d"}, + {file = "cffi-1.17.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a98748ed1a1df4ee1d6f927e151ed6c1a09d5ec21684de879c7ea6aa96f58f2"}, + {file = "cffi-1.17.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0a048d4f6630113e54bb4b77e315e1ba32a5a31512c31a273807d0027a7e69ab"}, + {file = "cffi-1.17.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24aa705a5f5bd3a8bcfa4d123f03413de5d86e497435693b638cbffb7d5d8a1b"}, + {file = "cffi-1.17.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:856bf0924d24e7f93b8aee12a3a1095c34085600aa805693fb7f5d1962393206"}, + {file = "cffi-1.17.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:4304d4416ff032ed50ad6bb87416d802e67139e31c0bde4628f36a47a3164bfa"}, + {file = "cffi-1.17.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:331ad15c39c9fe9186ceaf87203a9ecf5ae0ba2538c9e898e3a6967e8ad3db6f"}, + {file = "cffi-1.17.0-cp310-cp310-win32.whl", hash = "sha256:669b29a9eca6146465cc574659058ed949748f0809a2582d1f1a324eb91054dc"}, + {file = "cffi-1.17.0-cp310-cp310-win_amd64.whl", hash = "sha256:48b389b1fd5144603d61d752afd7167dfd205973a43151ae5045b35793232aa2"}, + {file = "cffi-1.17.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c5d97162c196ce54af6700949ddf9409e9833ef1003b4741c2b39ef46f1d9720"}, + {file = "cffi-1.17.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5ba5c243f4004c750836f81606a9fcb7841f8874ad8f3bf204ff5e56332b72b9"}, + {file = "cffi-1.17.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bb9333f58fc3a2296fb1d54576138d4cf5d496a2cc118422bd77835e6ae0b9cb"}, + {file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:435a22d00ec7d7ea533db494da8581b05977f9c37338c80bc86314bec2619424"}, + {file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d1df34588123fcc88c872f5acb6f74ae59e9d182a2707097f9e28275ec26a12d"}, + {file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:df8bb0010fdd0a743b7542589223a2816bdde4d94bb5ad67884348fa2c1c67e8"}, + {file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8b5b9712783415695663bd463990e2f00c6750562e6ad1d28e072a611c5f2a6"}, + {file = "cffi-1.17.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ffef8fd58a36fb5f1196919638f73dd3ae0db1a878982b27a9a5a176ede4ba91"}, + {file = "cffi-1.17.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4e67d26532bfd8b7f7c05d5a766d6f437b362c1bf203a3a5ce3593a645e870b8"}, + {file = "cffi-1.17.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:45f7cd36186db767d803b1473b3c659d57a23b5fa491ad83c6d40f2af58e4dbb"}, + {file = "cffi-1.17.0-cp311-cp311-win32.whl", hash = "sha256:a9015f5b8af1bb6837a3fcb0cdf3b874fe3385ff6274e8b7925d81ccaec3c5c9"}, + {file = "cffi-1.17.0-cp311-cp311-win_amd64.whl", hash = "sha256:b50aaac7d05c2c26dfd50c3321199f019ba76bb650e346a6ef3616306eed67b0"}, + {file = "cffi-1.17.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aec510255ce690d240f7cb23d7114f6b351c733a74c279a84def763660a2c3bc"}, + {file = "cffi-1.17.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2770bb0d5e3cc0e31e7318db06efcbcdb7b31bcb1a70086d3177692a02256f59"}, + {file = "cffi-1.17.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:db9a30ec064129d605d0f1aedc93e00894b9334ec74ba9c6bdd08147434b33eb"}, + {file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a47eef975d2b8b721775a0fa286f50eab535b9d56c70a6e62842134cf7841195"}, + {file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f3e0992f23bbb0be00a921eae5363329253c3b86287db27092461c887b791e5e"}, + {file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6107e445faf057c118d5050560695e46d272e5301feffda3c41849641222a828"}, + {file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb862356ee9391dc5a0b3cbc00f416b48c1b9a52d252d898e5b7696a5f9fe150"}, + {file = "cffi-1.17.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c1c13185b90bbd3f8b5963cd8ce7ad4ff441924c31e23c975cb150e27c2bf67a"}, + {file = "cffi-1.17.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:17c6d6d3260c7f2d94f657e6872591fe8733872a86ed1345bda872cfc8c74885"}, + {file = "cffi-1.17.0-cp312-cp312-win32.whl", hash = "sha256:c3b8bd3133cd50f6b637bb4322822c94c5ce4bf0d724ed5ae70afce62187c492"}, + {file = "cffi-1.17.0-cp312-cp312-win_amd64.whl", hash = "sha256:dca802c8db0720ce1c49cce1149ff7b06e91ba15fa84b1d59144fef1a1bc7ac2"}, + {file = "cffi-1.17.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6ce01337d23884b21c03869d2f68c5523d43174d4fc405490eb0091057943118"}, + {file = "cffi-1.17.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cab2eba3830bf4f6d91e2d6718e0e1c14a2f5ad1af68a89d24ace0c6b17cced7"}, + {file = "cffi-1.17.0-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:14b9cbc8f7ac98a739558eb86fabc283d4d564dafed50216e7f7ee62d0d25377"}, + {file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b00e7bcd71caa0282cbe3c90966f738e2db91e64092a877c3ff7f19a1628fdcb"}, + {file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:41f4915e09218744d8bae14759f983e466ab69b178de38066f7579892ff2a555"}, + {file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e4760a68cab57bfaa628938e9c2971137e05ce48e762a9cb53b76c9b569f1204"}, + {file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:011aff3524d578a9412c8b3cfaa50f2c0bd78e03eb7af7aa5e0df59b158efb2f"}, + {file = "cffi-1.17.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:a003ac9edc22d99ae1286b0875c460351f4e101f8c9d9d2576e78d7e048f64e0"}, + {file = "cffi-1.17.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ef9528915df81b8f4c7612b19b8628214c65c9b7f74db2e34a646a0a2a0da2d4"}, + {file = "cffi-1.17.0-cp313-cp313-win32.whl", hash = "sha256:70d2aa9fb00cf52034feac4b913181a6e10356019b18ef89bc7c12a283bf5f5a"}, + {file = "cffi-1.17.0-cp313-cp313-win_amd64.whl", hash = "sha256:b7b6ea9e36d32582cda3465f54c4b454f62f23cb083ebc7a94e2ca6ef011c3a7"}, + {file = "cffi-1.17.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:964823b2fc77b55355999ade496c54dde161c621cb1f6eac61dc30ed1b63cd4c"}, + {file = "cffi-1.17.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:516a405f174fd3b88829eabfe4bb296ac602d6a0f68e0d64d5ac9456194a5b7e"}, + {file = "cffi-1.17.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dec6b307ce928e8e112a6bb9921a1cb00a0e14979bf28b98e084a4b8a742bd9b"}, + {file = "cffi-1.17.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e4094c7b464cf0a858e75cd14b03509e84789abf7b79f8537e6a72152109c76e"}, + {file = "cffi-1.17.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2404f3de742f47cb62d023f0ba7c5a916c9c653d5b368cc966382ae4e57da401"}, + {file = "cffi-1.17.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3aa9d43b02a0c681f0bfbc12d476d47b2b2b6a3f9287f11ee42989a268a1833c"}, + {file = "cffi-1.17.0-cp38-cp38-win32.whl", hash = "sha256:0bb15e7acf8ab35ca8b24b90af52c8b391690ef5c4aec3d31f38f0d37d2cc499"}, + {file = "cffi-1.17.0-cp38-cp38-win_amd64.whl", hash = "sha256:93a7350f6706b31f457c1457d3a3259ff9071a66f312ae64dc024f049055f72c"}, + {file = "cffi-1.17.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1a2ddbac59dc3716bc79f27906c010406155031a1c801410f1bafff17ea304d2"}, + {file = "cffi-1.17.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6327b572f5770293fc062a7ec04160e89741e8552bf1c358d1a23eba68166759"}, + {file = "cffi-1.17.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbc183e7bef690c9abe5ea67b7b60fdbca81aa8da43468287dae7b5c046107d4"}, + {file = "cffi-1.17.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5bdc0f1f610d067c70aa3737ed06e2726fd9d6f7bfee4a351f4c40b6831f4e82"}, + {file = "cffi-1.17.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6d872186c1617d143969defeadac5a904e6e374183e07977eedef9c07c8953bf"}, + {file = "cffi-1.17.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0d46ee4764b88b91f16661a8befc6bfb24806d885e27436fdc292ed7e6f6d058"}, + {file = "cffi-1.17.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f76a90c345796c01d85e6332e81cab6d70de83b829cf1d9762d0a3da59c7932"}, + {file = "cffi-1.17.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0e60821d312f99d3e1569202518dddf10ae547e799d75aef3bca3a2d9e8ee693"}, + {file = "cffi-1.17.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:eb09b82377233b902d4c3fbeeb7ad731cdab579c6c6fda1f763cd779139e47c3"}, + {file = "cffi-1.17.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:24658baf6224d8f280e827f0a50c46ad819ec8ba380a42448e24459daf809cf4"}, + {file = "cffi-1.17.0-cp39-cp39-win32.whl", hash = "sha256:0fdacad9e0d9fc23e519efd5ea24a70348305e8d7d85ecbb1a5fa66dc834e7fb"}, + {file = "cffi-1.17.0-cp39-cp39-win_amd64.whl", hash = "sha256:7cbc78dc018596315d4e7841c8c3a7ae31cc4d638c9b627f87d52e8abaaf2d29"}, + {file = "cffi-1.17.0.tar.gz", hash = "sha256:f3157624b7558b914cb039fd1af735e5e8049a87c817cc215109ad1c8779df76"}, ] [package.dependencies] @@ -365,13 +407,13 @@ files = [ [[package]] name = "exceptiongroup" -version = "1.2.0" +version = "1.2.2" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" files = [ - {file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"}, - {file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"}, + {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, + {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, ] [package.extras] @@ -465,13 +507,13 @@ files = [ [[package]] name = "idna" -version = "3.6" +version = "3.7" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.5" files = [ - {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"}, - {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"}, + {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, + {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, ] [[package]] @@ -623,58 +665,128 @@ files = [ [[package]] name = "numpy" -version = "1.26.4" +version = "2.0.1" description = "Fundamental package for array computing in Python" optional = false python-versions = ">=3.9" files = [ - {file = "numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0"}, - {file = "numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a"}, - {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4"}, - {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f"}, - {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a"}, - {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2"}, - {file = "numpy-1.26.4-cp310-cp310-win32.whl", hash = "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07"}, - {file = "numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5"}, - {file = "numpy-1.26.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71"}, - {file = "numpy-1.26.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef"}, - {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e"}, - {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5"}, - {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a"}, - {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a"}, - {file = "numpy-1.26.4-cp311-cp311-win32.whl", hash = "sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20"}, - {file = "numpy-1.26.4-cp311-cp311-win_amd64.whl", hash = "sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2"}, - {file = "numpy-1.26.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218"}, - {file = "numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b"}, - {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b"}, - {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed"}, - {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a"}, - {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0"}, - {file = "numpy-1.26.4-cp312-cp312-win32.whl", hash = "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110"}, - {file = "numpy-1.26.4-cp312-cp312-win_amd64.whl", hash = "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818"}, - {file = "numpy-1.26.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7349ab0fa0c429c82442a27a9673fc802ffdb7c7775fad780226cb234965e53c"}, - {file = "numpy-1.26.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:52b8b60467cd7dd1e9ed082188b4e6bb35aa5cdd01777621a1658910745b90be"}, - {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5241e0a80d808d70546c697135da2c613f30e28251ff8307eb72ba696945764"}, - {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f870204a840a60da0b12273ef34f7051e98c3b5961b61b0c2c1be6dfd64fbcd3"}, - {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:679b0076f67ecc0138fd2ede3a8fd196dddc2ad3254069bcb9faf9a79b1cebcd"}, - {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:47711010ad8555514b434df65f7d7b076bb8261df1ca9bb78f53d3b2db02e95c"}, - {file = "numpy-1.26.4-cp39-cp39-win32.whl", hash = "sha256:a354325ee03388678242a4d7ebcd08b5c727033fcff3b2f536aea978e15ee9e6"}, - {file = "numpy-1.26.4-cp39-cp39-win_amd64.whl", hash = "sha256:3373d5d70a5fe74a2c1bb6d2cfd9609ecf686d47a2d7b1d37a8f3b6bf6003aea"}, - {file = "numpy-1.26.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:afedb719a9dcfc7eaf2287b839d8198e06dcd4cb5d276a3df279231138e83d30"}, - {file = "numpy-1.26.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95a7476c59002f2f6c590b9b7b998306fba6a5aa646b1e22ddfeaf8f78c3a29c"}, - {file = "numpy-1.26.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7e50d0a0cc3189f9cb0aeb3a6a6af18c16f59f004b866cd2be1c14b36134a4a0"}, - {file = "numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010"}, + {file = "numpy-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0fbb536eac80e27a2793ffd787895242b7f18ef792563d742c2d673bfcb75134"}, + {file = "numpy-2.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:69ff563d43c69b1baba77af455dd0a839df8d25e8590e79c90fcbe1499ebde42"}, + {file = "numpy-2.0.1-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:1b902ce0e0a5bb7704556a217c4f63a7974f8f43e090aff03fcf262e0b135e02"}, + {file = "numpy-2.0.1-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:f1659887361a7151f89e79b276ed8dff3d75877df906328f14d8bb40bb4f5101"}, + {file = "numpy-2.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4658c398d65d1b25e1760de3157011a80375da861709abd7cef3bad65d6543f9"}, + {file = "numpy-2.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4127d4303b9ac9f94ca0441138acead39928938660ca58329fe156f84b9f3015"}, + {file = "numpy-2.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e5eeca8067ad04bc8a2a8731183d51d7cbaac66d86085d5f4766ee6bf19c7f87"}, + {file = "numpy-2.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9adbd9bb520c866e1bfd7e10e1880a1f7749f1f6e5017686a5fbb9b72cf69f82"}, + {file = "numpy-2.0.1-cp310-cp310-win32.whl", hash = "sha256:7b9853803278db3bdcc6cd5beca37815b133e9e77ff3d4733c247414e78eb8d1"}, + {file = "numpy-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:81b0893a39bc5b865b8bf89e9ad7807e16717f19868e9d234bdaf9b1f1393868"}, + {file = "numpy-2.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:75b4e316c5902d8163ef9d423b1c3f2f6252226d1aa5cd8a0a03a7d01ffc6268"}, + {file = "numpy-2.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6e4eeb6eb2fced786e32e6d8df9e755ce5be920d17f7ce00bc38fcde8ccdbf9e"}, + {file = "numpy-2.0.1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:a1e01dcaab205fbece13c1410253a9eea1b1c9b61d237b6fa59bcc46e8e89343"}, + {file = "numpy-2.0.1-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:a8fc2de81ad835d999113ddf87d1ea2b0f4704cbd947c948d2f5513deafe5a7b"}, + {file = "numpy-2.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5a3d94942c331dd4e0e1147f7a8699a4aa47dffc11bf8a1523c12af8b2e91bbe"}, + {file = "numpy-2.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15eb4eca47d36ec3f78cde0a3a2ee24cf05ca7396ef808dda2c0ddad7c2bde67"}, + {file = "numpy-2.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b83e16a5511d1b1f8a88cbabb1a6f6a499f82c062a4251892d9ad5d609863fb7"}, + {file = "numpy-2.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1f87fec1f9bc1efd23f4227becff04bd0e979e23ca50cc92ec88b38489db3b55"}, + {file = "numpy-2.0.1-cp311-cp311-win32.whl", hash = "sha256:36d3a9405fd7c511804dc56fc32974fa5533bdeb3cd1604d6b8ff1d292b819c4"}, + {file = "numpy-2.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:08458fbf403bff5e2b45f08eda195d4b0c9b35682311da5a5a0a0925b11b9bd8"}, + {file = "numpy-2.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6bf4e6f4a2a2e26655717a1983ef6324f2664d7011f6ef7482e8c0b3d51e82ac"}, + {file = "numpy-2.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7d6fddc5fe258d3328cd8e3d7d3e02234c5d70e01ebe377a6ab92adb14039cb4"}, + {file = "numpy-2.0.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:5daab361be6ddeb299a918a7c0864fa8618af66019138263247af405018b04e1"}, + {file = "numpy-2.0.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:ea2326a4dca88e4a274ba3a4405eb6c6467d3ffbd8c7d38632502eaae3820587"}, + {file = "numpy-2.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:529af13c5f4b7a932fb0e1911d3a75da204eff023ee5e0e79c1751564221a5c8"}, + {file = "numpy-2.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6790654cb13eab303d8402354fabd47472b24635700f631f041bd0b65e37298a"}, + {file = "numpy-2.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:cbab9fc9c391700e3e1287666dfd82d8666d10e69a6c4a09ab97574c0b7ee0a7"}, + {file = "numpy-2.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:99d0d92a5e3613c33a5f01db206a33f8fdf3d71f2912b0de1739894668b7a93b"}, + {file = "numpy-2.0.1-cp312-cp312-win32.whl", hash = "sha256:173a00b9995f73b79eb0191129f2455f1e34c203f559dd118636858cc452a1bf"}, + {file = "numpy-2.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:bb2124fdc6e62baae159ebcfa368708867eb56806804d005860b6007388df171"}, + {file = "numpy-2.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bfc085b28d62ff4009364e7ca34b80a9a080cbd97c2c0630bb5f7f770dae9414"}, + {file = "numpy-2.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8fae4ebbf95a179c1156fab0b142b74e4ba4204c87bde8d3d8b6f9c34c5825ef"}, + {file = "numpy-2.0.1-cp39-cp39-macosx_14_0_arm64.whl", hash = "sha256:72dc22e9ec8f6eaa206deb1b1355eb2e253899d7347f5e2fae5f0af613741d06"}, + {file = "numpy-2.0.1-cp39-cp39-macosx_14_0_x86_64.whl", hash = "sha256:ec87f5f8aca726117a1c9b7083e7656a9d0d606eec7299cc067bb83d26f16e0c"}, + {file = "numpy-2.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f682ea61a88479d9498bf2091fdcd722b090724b08b31d63e022adc063bad59"}, + {file = "numpy-2.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8efc84f01c1cd7e34b3fb310183e72fcdf55293ee736d679b6d35b35d80bba26"}, + {file = "numpy-2.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3fdabe3e2a52bc4eff8dc7a5044342f8bd9f11ef0934fcd3289a788c0eb10018"}, + {file = "numpy-2.0.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:24a0e1befbfa14615b49ba9659d3d8818a0f4d8a1c5822af8696706fbda7310c"}, + {file = "numpy-2.0.1-cp39-cp39-win32.whl", hash = "sha256:f9cf5ea551aec449206954b075db819f52adc1638d46a6738253a712d553c7b4"}, + {file = "numpy-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:e9e81fa9017eaa416c056e5d9e71be93d05e2c3c2ab308d23307a8bc4443c368"}, + {file = "numpy-2.0.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:61728fba1e464f789b11deb78a57805c70b2ed02343560456190d0501ba37b0f"}, + {file = "numpy-2.0.1-pp39-pypy39_pp73-macosx_14_0_x86_64.whl", hash = "sha256:12f5d865d60fb9734e60a60f1d5afa6d962d8d4467c120a1c0cda6eb2964437d"}, + {file = "numpy-2.0.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eacf3291e263d5a67d8c1a581a8ebbcfd6447204ef58828caf69a5e3e8c75990"}, + {file = "numpy-2.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2c3a346ae20cfd80b6cfd3e60dc179963ef2ea58da5ec074fd3d9e7a1e7ba97f"}, + {file = "numpy-2.0.1.tar.gz", hash = "sha256:485b87235796410c3519a699cfe1faab097e509e90ebb05dcd098db2ae87e7b3"}, +] + +[[package]] +name = "numpy" +version = "2.1.0" +description = "Fundamental package for array computing in Python" +optional = false +python-versions = ">=3.10" +files = [ + {file = "numpy-2.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6326ab99b52fafdcdeccf602d6286191a79fe2fda0ae90573c5814cd2b0bc1b8"}, + {file = "numpy-2.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0937e54c09f7a9a68da6889362ddd2ff584c02d015ec92672c099b61555f8911"}, + {file = "numpy-2.1.0-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:30014b234f07b5fec20f4146f69e13cfb1e33ee9a18a1879a0142fbb00d47673"}, + {file = "numpy-2.1.0-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:899da829b362ade41e1e7eccad2cf274035e1cb36ba73034946fccd4afd8606b"}, + {file = "numpy-2.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:08801848a40aea24ce16c2ecde3b756f9ad756586fb2d13210939eb69b023f5b"}, + {file = "numpy-2.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:398049e237d1aae53d82a416dade04defed1a47f87d18d5bd615b6e7d7e41d1f"}, + {file = "numpy-2.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0abb3916a35d9090088a748636b2c06dc9a6542f99cd476979fb156a18192b84"}, + {file = "numpy-2.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:10e2350aea18d04832319aac0f887d5fcec1b36abd485d14f173e3e900b83e33"}, + {file = "numpy-2.1.0-cp310-cp310-win32.whl", hash = "sha256:f6b26e6c3b98adb648243670fddc8cab6ae17473f9dc58c51574af3e64d61211"}, + {file = "numpy-2.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:f505264735ee074250a9c78247ee8618292091d9d1fcc023290e9ac67e8f1afa"}, + {file = "numpy-2.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:76368c788ccb4f4782cf9c842b316140142b4cbf22ff8db82724e82fe1205dce"}, + {file = "numpy-2.1.0-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:f8e93a01a35be08d31ae33021e5268f157a2d60ebd643cfc15de6ab8e4722eb1"}, + {file = "numpy-2.1.0-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:9523f8b46485db6939bd069b28b642fec86c30909cea90ef550373787f79530e"}, + {file = "numpy-2.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54139e0eb219f52f60656d163cbe67c31ede51d13236c950145473504fa208cb"}, + {file = "numpy-2.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5ebbf9fbdabed208d4ecd2e1dfd2c0741af2f876e7ae522c2537d404ca895c3"}, + {file = "numpy-2.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:378cb4f24c7d93066ee4103204f73ed046eb88f9ad5bb2275bb9fa0f6a02bd36"}, + {file = "numpy-2.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8f699a709120b220dfe173f79c73cb2a2cab2c0b88dd59d7b49407d032b8ebd"}, + {file = "numpy-2.1.0-cp311-cp311-win32.whl", hash = "sha256:ffbd6faeb190aaf2b5e9024bac9622d2ee549b7ec89ef3a9373fa35313d44e0e"}, + {file = "numpy-2.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:0af3a5987f59d9c529c022c8c2a64805b339b7ef506509fba7d0556649b9714b"}, + {file = "numpy-2.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fe76d75b345dc045acdbc006adcb197cc680754afd6c259de60d358d60c93736"}, + {file = "numpy-2.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f358ea9e47eb3c2d6eba121ab512dfff38a88db719c38d1e67349af210bc7529"}, + {file = "numpy-2.1.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:dd94ce596bda40a9618324547cfaaf6650b1a24f5390350142499aa4e34e53d1"}, + {file = "numpy-2.1.0-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:b47c551c6724960479cefd7353656498b86e7232429e3a41ab83be4da1b109e8"}, + {file = "numpy-2.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0756a179afa766ad7cb6f036de622e8a8f16ffdd55aa31f296c870b5679d745"}, + {file = "numpy-2.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24003ba8ff22ea29a8c306e61d316ac74111cebf942afbf692df65509a05f111"}, + {file = "numpy-2.1.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b34fa5e3b5d6dc7e0a4243fa0f81367027cb6f4a7215a17852979634b5544ee0"}, + {file = "numpy-2.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c4f982715e65036c34897eb598d64aef15150c447be2cfc6643ec7a11af06574"}, + {file = "numpy-2.1.0-cp312-cp312-win32.whl", hash = "sha256:c4cd94dfefbefec3f8b544f61286584292d740e6e9d4677769bc76b8f41deb02"}, + {file = "numpy-2.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:a0cdef204199278f5c461a0bed6ed2e052998276e6d8ab2963d5b5c39a0500bc"}, + {file = "numpy-2.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8ab81ccd753859ab89e67199b9da62c543850f819993761c1e94a75a814ed667"}, + {file = "numpy-2.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:442596f01913656d579309edcd179a2a2f9977d9a14ff41d042475280fc7f34e"}, + {file = "numpy-2.1.0-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:848c6b5cad9898e4b9ef251b6f934fa34630371f2e916261070a4eb9092ffd33"}, + {file = "numpy-2.1.0-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:54c6a63e9d81efe64bfb7bcb0ec64332a87d0b87575f6009c8ba67ea6374770b"}, + {file = "numpy-2.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:652e92fc409e278abdd61e9505649e3938f6d04ce7ef1953f2ec598a50e7c195"}, + {file = "numpy-2.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ab32eb9170bf8ffcbb14f11613f4a0b108d3ffee0832457c5d4808233ba8977"}, + {file = "numpy-2.1.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:8fb49a0ba4d8f41198ae2d52118b050fd34dace4b8f3fb0ee34e23eb4ae775b1"}, + {file = "numpy-2.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:44e44973262dc3ae79e9063a1284a73e09d01b894b534a769732ccd46c28cc62"}, + {file = "numpy-2.1.0-cp313-cp313-win32.whl", hash = "sha256:ab83adc099ec62e044b1fbb3a05499fa1e99f6d53a1dde102b2d85eff66ed324"}, + {file = "numpy-2.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:de844aaa4815b78f6023832590d77da0e3b6805c644c33ce94a1e449f16d6ab5"}, + {file = "numpy-2.1.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:343e3e152bf5a087511cd325e3b7ecfd5b92d369e80e74c12cd87826e263ec06"}, + {file = "numpy-2.1.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f07fa2f15dabe91259828ce7d71b5ca9e2eb7c8c26baa822c825ce43552f4883"}, + {file = "numpy-2.1.0-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:5474dad8c86ee9ba9bb776f4b99ef2d41b3b8f4e0d199d4f7304728ed34d0300"}, + {file = "numpy-2.1.0-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:1f817c71683fd1bb5cff1529a1d085a57f02ccd2ebc5cd2c566f9a01118e3b7d"}, + {file = "numpy-2.1.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a3336fbfa0d38d3deacd3fe7f3d07e13597f29c13abf4d15c3b6dc2291cbbdd"}, + {file = "numpy-2.1.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a894c51fd8c4e834f00ac742abad73fc485df1062f1b875661a3c1e1fb1c2f6"}, + {file = "numpy-2.1.0-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:9156ca1f79fc4acc226696e95bfcc2b486f165a6a59ebe22b2c1f82ab190384a"}, + {file = "numpy-2.1.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:624884b572dff8ca8f60fab591413f077471de64e376b17d291b19f56504b2bb"}, + {file = "numpy-2.1.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:15ef8b2177eeb7e37dd5ef4016f30b7659c57c2c0b57a779f1d537ff33a72c7b"}, + {file = "numpy-2.1.0-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:e5f0642cdf4636198a4990de7a71b693d824c56a757862230454629cf62e323d"}, + {file = "numpy-2.1.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f15976718c004466406342789f31b6673776360f3b1e3c575f25302d7e789575"}, + {file = "numpy-2.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:6c1de77ded79fef664d5098a66810d4d27ca0224e9051906e634b3f7ead134c2"}, + {file = "numpy-2.1.0.tar.gz", hash = "sha256:7dc90da0081f7e1da49ec4e398ede6a8e9cc4f5ebe5f9e06b443ed889ee9aaa2"}, ] [[package]] name = "packaging" -version = "23.2" +version = "24.1" description = "Core utilities for Python packages" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, - {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, + {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, + {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, ] [[package]] @@ -690,13 +802,13 @@ files = [ [[package]] name = "pluggy" -version = "1.4.0" +version = "1.5.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.8" files = [ - {file = "pluggy-1.4.0-py3-none-any.whl", hash = "sha256:7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981"}, - {file = "pluggy-1.4.0.tar.gz", hash = "sha256:8c85c2876142a764e5b7548e7d9a0e0ddb46f5185161049a79b7e974454223be"}, + {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, + {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, ] [package.extras] @@ -771,13 +883,13 @@ idna = ["idna (>=2.1)"] [[package]] name = "pycparser" -version = "2.21" +version = "2.22" description = "C parser in Python" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.8" files = [ - {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, - {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, + {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, + {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, ] [[package]] @@ -930,4 +1042,4 @@ multidict = ">=4.0" [metadata] lock-version = "2.0" python-versions = "^3.8" -content-hash = "11d3704623455cf65a35174a88b275bb80ab36ae0dc95074b1a943ef0be3c08d" +content-hash = "4839606a2b6399486c0131ebc56057085dc19adb2b4f5f3b3a480476a4c41fff" diff --git a/pyproject.toml b/pyproject.toml index a2d0d1cf..10385d80 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -58,8 +58,9 @@ pmjs = "pythonmonkey.cli.pmjs:main" pytest = "^7.3.1" pip = "^23.1.2" numpy = [ - {version = "^1.26.1", python = ">=3.9,<3.13"}, - {version = "^1.24.3", python = "3.8.*"}, + {version = "^2.1.0", python = ">=3.10"}, + {version = "^2.0.1", python = ">=3.9,<3.10"}, # NumPy 2.1.0 drops support for Python 3.9 + {version = "^1.24.3", python = ">=3.8,<3.9"}, # NumPy 1.25.0 drops support for Python 3.8 ] pminit = { path = "./python/pminit", develop = true } From d80c162b703c37fa100e9854986185e19a7527bf Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 21 Aug 2024 21:58:09 +0000 Subject: [PATCH 231/428] fix: `_PyDictView` removed from Python's public API --- include/JSObjectItemsProxy.hh | 1 + include/JSObjectKeysProxy.hh | 1 + include/JSObjectValuesProxy.hh | 1 + include/dictviewShim.hh | 28 ++++++++++++++++++++++++++++ src/JSObjectKeysProxy.cc | 1 + src/JSObjectProxy.cc | 1 + src/JSObjectValuesProxy.cc | 1 + 7 files changed, 34 insertions(+) create mode 100644 include/dictviewShim.hh diff --git a/include/JSObjectItemsProxy.hh b/include/JSObjectItemsProxy.hh index f71e297e..8523620c 100644 --- a/include/JSObjectItemsProxy.hh +++ b/include/JSObjectItemsProxy.hh @@ -14,6 +14,7 @@ #include #include +#include "include/dictviewShim.hh" /** diff --git a/include/JSObjectKeysProxy.hh b/include/JSObjectKeysProxy.hh index bffdb18b..f4693b68 100644 --- a/include/JSObjectKeysProxy.hh +++ b/include/JSObjectKeysProxy.hh @@ -14,6 +14,7 @@ #include #include +#include "include/dictviewShim.hh" /** diff --git a/include/JSObjectValuesProxy.hh b/include/JSObjectValuesProxy.hh index 8cb40034..82aae114 100644 --- a/include/JSObjectValuesProxy.hh +++ b/include/JSObjectValuesProxy.hh @@ -14,6 +14,7 @@ #include #include +#include "include/dictviewShim.hh" /** diff --git a/include/dictviewShim.hh b/include/dictviewShim.hh new file mode 100644 index 00000000..50883e96 --- /dev/null +++ b/include/dictviewShim.hh @@ -0,0 +1,28 @@ +/** + * @file dictviewShim.hh + * @author Tom Tang (xmader@distributive.network) + * @brief Since Python 3.13, `_PyDictView` moved from Python's public API to the **internal** header file `internal/pycore_dict.h`. + * This file behaves as a shim to bring back its definitions. + * The code here is copied from https://github.com/python/cpython/blob/v3.13.0rc1/Include/internal/pycore_dict.h#L64-L72. + * @date 2024-08-21 + * + * @copyright Copyright (c) 2024 Distributive Corp. + * + */ + +#ifndef PythonMonkey_dictview_shim_ +#define PythonMonkey_dictview_shim_ + +#include + +/* _PyDictView */ + +typedef struct { + PyObject_HEAD + PyDictObject *dv_dict; +} _PyDictViewObject; + +extern PyObject *_PyDictView_New(PyObject *, PyTypeObject *); +extern PyObject *_PyDictView_Intersect(PyObject *self, PyObject *other); + +#endif diff --git a/src/JSObjectKeysProxy.cc b/src/JSObjectKeysProxy.cc index e5d6be19..29590e52 100644 --- a/src/JSObjectKeysProxy.cc +++ b/src/JSObjectKeysProxy.cc @@ -22,6 +22,7 @@ #include #include +#include "include/dictviewShim.hh" diff --git a/src/JSObjectProxy.cc b/src/JSObjectProxy.cc index 13b3e609..547c01a7 100644 --- a/src/JSObjectProxy.cc +++ b/src/JSObjectProxy.cc @@ -27,6 +27,7 @@ #include #include +#include "include/dictviewShim.hh" #include diff --git a/src/JSObjectValuesProxy.cc b/src/JSObjectValuesProxy.cc index f5b0a1b2..ab5af78f 100644 --- a/src/JSObjectValuesProxy.cc +++ b/src/JSObjectValuesProxy.cc @@ -22,6 +22,7 @@ #include #include +#include "include/dictviewShim.hh" From 2751372dacce495da39f22f6f73ee399b5f0f8db Mon Sep 17 00:00:00 2001 From: Ciarands <74070993+Ciarands@users.noreply.github.com> Date: Wed, 21 Aug 2024 23:11:03 +0100 Subject: [PATCH 232/428] Requested changes --- python/pythonmonkey/builtin_modules/base64.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/python/pythonmonkey/builtin_modules/base64.py b/python/pythonmonkey/builtin_modules/base64.py index da18fedc..97e29ade 100644 --- a/python/pythonmonkey/builtin_modules/base64.py +++ b/python/pythonmonkey/builtin_modules/base64.py @@ -8,10 +8,8 @@ def atob(b64): - # Workaround for pythons 'Incorrect padding' error when base64 decoding, see: - # https://stackoverflow.com/questions/2941995/python-ignore-incorrect-padding-error-when-base64-decoding - append = b"==" if isinstance(b64, bytes) else "==" - return str(base64.standard_b64decode(b64 + append), 'latin1') + padding = '=' * (4 - (len(b64) & 3)) + return str(base64.standard_b64decode(b64 + padding), 'latin1') def btoa(data): From dac79df0c86c104edb163dc3521e59a40542938c Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 21 Aug 2024 22:26:52 +0000 Subject: [PATCH 233/428] fix: Python 3.13 removed `_PyThreadState_GetDict(PyThreadState *)` from the public API. We have to re-export it. --- include/PyEventLoop.hh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/PyEventLoop.hh b/include/PyEventLoop.hh index a4c643f2..5e3b56a3 100644 --- a/include/PyEventLoop.hh +++ b/include/PyEventLoop.hh @@ -331,4 +331,8 @@ private: static inline std::vector _timeoutIdMap; }; +// See https://github.com/python/cpython/blob/v3.13.0rc1/Python/pystate.c#L1940-L1951 +// Python 3.13 removed it from the public API. Re-exporting here. +extern PyObject *_PyThreadState_GetDict(PyThreadState *tstate); + #endif \ No newline at end of file From 9b7c59891d35ab618d9214b4018c0ba7b61ac6a9 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 21 Aug 2024 22:33:30 +0000 Subject: [PATCH 234/428] chore(CI): enable Python 3.13 build in the CI --- .github/workflows/test-and-publish.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 6f3521c6..6e8f98ad 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -30,6 +30,7 @@ on: - '3.10' - '3.11' - '3.12' + - '3.13-dev' build_type: type: choice description: 'Choose the build type to use' @@ -128,7 +129,7 @@ jobs: fail-fast: false matrix: os: [ 'ubuntu-20.04', 'macos-12', 'macos-14', 'windows-2022', 'pi' ] - python_version: [ '3.8', '3.9', '3.10', '3.11', '3.12' ] + python_version: [ '3.8', '3.9', '3.10', '3.11', '3.12', '3.13-dev' ] exclude: # actions/setup-python: The version '3.8'/'3.9' with architecture 'arm64' was not found for macOS. # see https://raw.githubusercontent.com/actions/python-versions/main/versions-manifest.json From dc4442df0093ba8ed351046c5d0410ff3aafe820 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 21 Aug 2024 23:44:35 +0000 Subject: [PATCH 235/428] WIP: remove the use of the `_PyArg_CheckPositional` private API --- src/JSArrayProxy.cc | 11 ----------- src/JSObjectProxy.cc | 9 --------- 2 files changed, 20 deletions(-) diff --git a/src/JSArrayProxy.cc b/src/JSArrayProxy.cc index 6fbdf465..16dfaec1 100644 --- a/src/JSArrayProxy.cc +++ b/src/JSArrayProxy.cc @@ -789,10 +789,6 @@ PyObject *JSArrayProxyMethodDefinitions::JSArrayProxy_insert(JSArrayProxy *self, Py_ssize_t index; PyObject *value; - if (!_PyArg_CheckPositional("insert", nargs, 2, 2)) { - return NULL; - } - { Py_ssize_t ival = -1; PyObject *iobj = PyNumber_Index(args[0]); @@ -899,10 +895,6 @@ PyObject *JSArrayProxyMethodDefinitions::JSArrayProxy_extend(JSArrayProxy *self, PyObject *JSArrayProxyMethodDefinitions::JSArrayProxy_pop(JSArrayProxy *self, PyObject *const *args, Py_ssize_t nargs) { Py_ssize_t index = -1; - if (!_PyArg_CheckPositional("pop", nargs, 0, 1)) { - return NULL; - } - if (nargs >= 1) { Py_ssize_t ival = -1; PyObject *iobj = PyNumber_Index(args[0]); @@ -987,9 +979,6 @@ PyObject *JSArrayProxyMethodDefinitions::JSArrayProxy_index(JSArrayProxy *self, Py_ssize_t start = 0; Py_ssize_t stop = PY_SSIZE_T_MAX; - if (!_PyArg_CheckPositional("index", nargs, 1, 3)) { - return NULL; - } value = args[0]; if (nargs < 2) { goto skip_optional; diff --git a/src/JSObjectProxy.cc b/src/JSObjectProxy.cc index 547c01a7..68029b99 100644 --- a/src/JSObjectProxy.cc +++ b/src/JSObjectProxy.cc @@ -620,9 +620,6 @@ PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_get_method(JSObjectProxy PyObject *key; PyObject *default_value = Py_None; - if (!_PyArg_CheckPositional("get", nargs, 1, 2)) { - return NULL; - } key = args[0]; if (nargs < 2) { goto skip_optional; @@ -644,9 +641,6 @@ PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_setdefault_method(JSObje PyObject *key; PyObject *default_value = Py_None; - if (!_PyArg_CheckPositional("setdefault", nargs, 1, 2)) { - return NULL; - } key = args[0]; if (nargs < 2) { goto skip_optional; @@ -676,9 +670,6 @@ PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_pop_method(JSObjectProxy PyObject *key; PyObject *default_value = NULL; - if (!_PyArg_CheckPositional("pop", nargs, 1, 2)) { - return NULL; - } key = args[0]; if (nargs < 2) { goto skip_optional; From 3feb5b725296bc9ab22cc973b430032ebf0084a7 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Thu, 22 Aug 2024 00:09:06 +0000 Subject: [PATCH 236/428] fix: Python 3.13 moved the undocumented `_PyArg_UnpackKeywords` function to private API --- src/JSArrayProxy.cc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/JSArrayProxy.cc b/src/JSArrayProxy.cc index 16dfaec1..12007ac5 100644 --- a/src/JSArrayProxy.cc +++ b/src/JSArrayProxy.cc @@ -1168,6 +1168,15 @@ static bool sort_compare_default(JSContext *cx, unsigned argc, JS::Value *vp) { return true; } +// Python 3.13 moved this function to private API. Re-exporting it. +extern PyObject *const *_PyArg_UnpackKeywords( + PyObject *const *args, Py_ssize_t nargs, + PyObject *kwargs, PyObject *kwnames, + struct _PyArg_Parser *parser, + int minpos, int maxpos, int minkw, + PyObject **buf +); + PyObject *JSArrayProxyMethodDefinitions::JSArrayProxy_sort(JSArrayProxy *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) From e4a4fda6e10be565cadd210ec4b4914b6ad498d2 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Thu, 22 Aug 2024 00:10:59 +0000 Subject: [PATCH 237/428] fix: Python 3.13 moved the undocumented `_PyErr_SetKeyError` function to private API --- src/JSObjectProxy.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/JSObjectProxy.cc b/src/JSObjectProxy.cc index 68029b99..ed6f2183 100644 --- a/src/JSObjectProxy.cc +++ b/src/JSObjectProxy.cc @@ -666,6 +666,9 @@ PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_setdefault_method(JSObje return value; } +// Python 3.13 moved this undocumented function to private API. Re-exporting it here. +extern void _PyErr_SetKeyError(PyObject *); + PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_pop_method(JSObjectProxy *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *key; PyObject *default_value = NULL; From 428353c46d9318658ebfb821fe0f1ec52ed5d839 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Thu, 22 Aug 2024 00:20:38 +0000 Subject: [PATCH 238/428] fix: Python 3.13 added the `PyLong_AsNativeBytes` API, but changed the function signature of the `_PyLong_AsByteArray` API See https://github.com/python/cpython/issues/111140 and https://github.com/capi-workgroup/decisions/issues/31 --- src/IntType.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/IntType.cc b/src/IntType.cc index c7a5cae5..30e974bf 100644 --- a/src/IntType.cc +++ b/src/IntType.cc @@ -139,7 +139,11 @@ JS::BigInt *IntType::toJsBigInt(JSContext *cx, PyObject *pyObject) { // Convert to bytes of 8-bit "digits" in **big-endian** order size_t byteCount = (size_t)JS_DIGIT_BYTE * jsDigitCount; uint8_t *bytes = (uint8_t *)PyMem_Malloc(byteCount); + #if PY_VERSION_HEX >= 0x030d0000 // Python version is greater than 3.13 + _PyLong_AsByteArray((PyLongObject *)pyObject, bytes, byteCount, /*is_little_endian*/ false, false, false); + #else _PyLong_AsByteArray((PyLongObject *)pyObject, bytes, byteCount, /*is_little_endian*/ false, false); + #endif // Convert pm.bigint to JS::BigInt through hex strings (no public API to convert directly through bytes) // TODO (Tom Tang): We could manually allocate the memory, https://hg.mozilla.org/releases/mozilla-esr102/file/tip/js/src/vm/BigIntType.cpp#l162, but still no public API From 301fcbea27e208236fc0e63c676f38d46ebe1168 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Fri, 23 Aug 2024 20:03:46 +0000 Subject: [PATCH 239/428] chore: make the wheel packages we build also support lower versions of macOS, otherwise pip would fallback to compile from source Change the platform tag part of the wheel filename to `macosx_11_xxx` (means to support macOS 11). A wheel package file will only be selected by pip to install if the platform tag satisfies, regardless of whether the binary compatibility actually is. See https://packaging.python.org/en/latest/specifications/binary-distribution-format/#file-format --- .github/workflows/test-and-publish.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 6f3521c6..7df7f813 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -208,6 +208,16 @@ jobs: WORKFLOW_BUILD_TYPE=${{ inputs.build_type }} BUILD_TYPE=${WORKFLOW_BUILD_TYPE:-"Debug"} poetry build --format=wheel ls -lah ./dist/ + - name: Make the wheels we build also support lower versions of macOS + if: ${{ matrix.os == 'macos-13' || matrix.os == 'macos-14' }} + # Change the platform tag part of the wheel filename to `macosx_11_xxx` (means to support macOS 11) + # See https://packaging.python.org/en/latest/specifications/binary-distribution-format/#file-format + # A wheel package file will only be selected by pip to install if the platform tag satisfies, regardless of whether the binary compatibility actually is. + # Otherwise, pip would fallback to compile from the source distribution. + run: | + for file in *.whl; do + mv "$file" "$(echo "$file" | sed 's/macosx_[0-9]\+/macosx_11/')"; + done - name: Upload wheel as CI artifacts uses: actions/upload-artifact@v3 with: From d6dc01d62e67da9707ba8f28a5f6269dbb511c9b Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Fri, 23 Aug 2024 20:11:20 +0000 Subject: [PATCH 240/428] chore: make the wheel packages we build for macOS support macOS 11.0 and above --- .github/workflows/test-and-publish.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 7df7f813..65211076 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -210,13 +210,13 @@ jobs: ls -lah ./dist/ - name: Make the wheels we build also support lower versions of macOS if: ${{ matrix.os == 'macos-13' || matrix.os == 'macos-14' }} - # Change the platform tag part of the wheel filename to `macosx_11_xxx` (means to support macOS 11) + # Change the platform tag part of the wheel filename to `macosx_11_0_xxx` (means to support macOS 11.0 and above) # See https://packaging.python.org/en/latest/specifications/binary-distribution-format/#file-format # A wheel package file will only be selected by pip to install if the platform tag satisfies, regardless of whether the binary compatibility actually is. # Otherwise, pip would fallback to compile from the source distribution. run: | for file in *.whl; do - mv "$file" "$(echo "$file" | sed 's/macosx_[0-9]\+/macosx_11/')"; + mv "$file" "$(echo "$file" | sed 's/macosx_[0-9]\+_[0-9]\+/macosx_11_0/')"; done - name: Upload wheel as CI artifacts uses: actions/upload-artifact@v3 From 80b5111755ea22815863b4842ceb8eab37675d80 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Fri, 23 Aug 2024 20:28:47 +0000 Subject: [PATCH 241/428] fix: the wheel package files should be in the `./dist/` directory --- .github/workflows/test-and-publish.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 65211076..610e89ac 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -215,6 +215,7 @@ jobs: # A wheel package file will only be selected by pip to install if the platform tag satisfies, regardless of whether the binary compatibility actually is. # Otherwise, pip would fallback to compile from the source distribution. run: | + cd ./dist/ for file in *.whl; do mv "$file" "$(echo "$file" | sed 's/macosx_[0-9]\+_[0-9]\+/macosx_11_0/')"; done From 4e7596bae42f956652b916a1c2c10ccf86383b52 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Fri, 23 Aug 2024 20:30:08 +0000 Subject: [PATCH 242/428] fix: we are building on macOS 12 in the CI --- .github/workflows/test-and-publish.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 610e89ac..fecc55f1 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -209,7 +209,7 @@ jobs: BUILD_TYPE=${WORKFLOW_BUILD_TYPE:-"Debug"} poetry build --format=wheel ls -lah ./dist/ - name: Make the wheels we build also support lower versions of macOS - if: ${{ matrix.os == 'macos-13' || matrix.os == 'macos-14' }} + if: ${{ matrix.os == 'macos-12' || matrix.os == 'macos-14' }} # Change the platform tag part of the wheel filename to `macosx_11_0_xxx` (means to support macOS 11.0 and above) # See https://packaging.python.org/en/latest/specifications/binary-distribution-format/#file-format # A wheel package file will only be selected by pip to install if the platform tag satisfies, regardless of whether the binary compatibility actually is. From ab8ba460d45598c38d025cbc73e07b81e303a3c1 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Fri, 23 Aug 2024 20:44:25 +0000 Subject: [PATCH 243/428] fix: `sed` works differently on macOS as it's the BSD variant --- .github/workflows/test-and-publish.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index fecc55f1..1544ba71 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -217,7 +217,7 @@ jobs: run: | cd ./dist/ for file in *.whl; do - mv "$file" "$(echo "$file" | sed 's/macosx_[0-9]\+_[0-9]\+/macosx_11_0/')"; + mv "$file" "$(echo "$file" | sed -E 's/macosx_[0-9]+_[0-9]+/macosx_11_0/')"; done - name: Upload wheel as CI artifacts uses: actions/upload-artifact@v3 From 778ca86797c12498bd98d10f85f774e6502d413a Mon Sep 17 00:00:00 2001 From: Caleb Aikens Date: Mon, 26 Aug 2024 10:55:04 -0400 Subject: [PATCH 244/428] fix(PyProxyHandler): don't finalize if python itself is finalizing --- src/PyListProxyHandler.cc | 4 ++-- src/PyObjectProxyHandler.cc | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/PyListProxyHandler.cc b/src/PyListProxyHandler.cc index 688cf82d..d6d9747b 100644 --- a/src/PyListProxyHandler.cc +++ b/src/PyListProxyHandler.cc @@ -2099,8 +2099,8 @@ void PyListProxyHandler::finalize(JS::GCContext *gcx, JSObject *proxy) const { // We cannot call Py_DECREF here when shutting down as the thread state is gone. // Then, when shutting down, there is only on reference left, and we don't need // to free the object since the entire process memory is being released. - PyObject *self = JS::GetMaybePtrFromReservedSlot(proxy, PyObjectSlot); - if (Py_REFCNT(self) > 1) { + if (!_Py_IsFinalizing()) { + PyObject *self = JS::GetMaybePtrFromReservedSlot(proxy, PyObjectSlot); Py_DECREF(self); } } diff --git a/src/PyObjectProxyHandler.cc b/src/PyObjectProxyHandler.cc index aae9ad94..871e619c 100644 --- a/src/PyObjectProxyHandler.cc +++ b/src/PyObjectProxyHandler.cc @@ -87,8 +87,8 @@ void PyObjectProxyHandler::finalize(JS::GCContext *gcx, JSObject *proxy) const { // We cannot call Py_DECREF here when shutting down as the thread state is gone. // Then, when shutting down, there is only on reference left, and we don't need // to free the object since the entire process memory is being released. - PyObject *self = JS::GetMaybePtrFromReservedSlot(proxy, PyObjectSlot); - if (Py_REFCNT(self) > 1) { + if (!_Py_IsFinalizing()) { + PyObject *self = JS::GetMaybePtrFromReservedSlot(proxy, PyObjectSlot); Py_DECREF(self); } } From 1d45ea98e42294cce16deec5454725d4de36f59f Mon Sep 17 00:00:00 2001 From: Caleb Aikens Date: Mon, 26 Aug 2024 10:55:46 -0400 Subject: [PATCH 245/428] chore(linting): lint PyObjectProxyHandler.cc --- src/PyObjectProxyHandler.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/PyObjectProxyHandler.cc b/src/PyObjectProxyHandler.cc index 871e619c..565e6122 100644 --- a/src/PyObjectProxyHandler.cc +++ b/src/PyObjectProxyHandler.cc @@ -109,12 +109,12 @@ bool PyObjectProxyHandler::ownPropertyKeys(JSContext *cx, JS::HandleObject proxy } return handleOwnPropertyKeys(cx, nonDunderKeys, PyList_Size(nonDunderKeys), props); - } + } else { if (PyErr_Occurred()) { - PyErr_Clear(); + PyErr_Clear(); } - + return handleOwnPropertyKeys(cx, PyList_New(0), 0, props); } } From bbcb6c65900eaef6e7ae5fdcd9a0e09ac91b6838 Mon Sep 17 00:00:00 2001 From: Caleb Aikens Date: Mon, 26 Aug 2024 10:57:05 -0400 Subject: [PATCH 246/428] chore(meta): update .git-blame-ignore-revs --- .git-blame-ignore-revs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index eace15d3..1ddbe74c 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -8,4 +8,7 @@ aae30e864449442cf0b04e94f8a242b1b667de9a 58cd4b45777b046f03a63255c1d93e289e1cab5e # chore(linting): lint PyBytesProxyHandler.cc -d540ed6e0edfe9538dc726cf587dfb2cc76dde34 \ No newline at end of file +d540ed6e0edfe9538dc726cf587dfb2cc76dde34 + +# chore(linting): lint PyObjectProxyHandler.cc +1d45ea98e42294cce16deec5454725d4de36f59f \ No newline at end of file From 4e07043631af4ab94d17e9fdf718f0c5812628dd Mon Sep 17 00:00:00 2001 From: Caleb Aikens Date: Mon, 26 Aug 2024 10:57:51 -0400 Subject: [PATCH 247/428] fix(JSExternalStrings): fix reference counting on JSExternalStrings --- src/jsTypeFactory.cc | 51 ++++++++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 16 deletions(-) diff --git a/src/jsTypeFactory.cc b/src/jsTypeFactory.cc index a5ccead4..8d6f12c5 100644 --- a/src/jsTypeFactory.cc +++ b/src/jsTypeFactory.cc @@ -49,17 +49,23 @@ static PyObjectProxyHandler pyObjectProxyHandler; static PyListProxyHandler pyListProxyHandler; static PyIterableProxyHandler pyIterableProxyHandler; -std::unordered_map ucs2ToPyObjectMap; // a map of char16_t (UCS-2) buffers to their corresponding PyObjects, used when finalizing JSExternalStrings -std::unordered_map latin1ToPyObjectMap; // a map of Latin-1 char buffers to their corresponding PyObjects, used when finalizing JSExternalStrings +std::unordered_map jsExternalStringPyObjects;// a map of python string objects to the number of JSExternalStrings that depend on it, used when finalizing JSExternalStrings PyObject *PythonExternalString::getPyString(const char16_t *chars) { - return ucs2ToPyObjectMap[chars]; + for (auto it: jsExternalStringPyObjects) { + if (PyUnicode_DATA(it.first) == (void *)chars) { + return it.first; + } + } + + return NULL; // this shouldn't be reachable } PyObject *PythonExternalString::getPyString(const JS::Latin1Char *chars) { - return latin1ToPyObjectMap[chars]; + + return PythonExternalString::getPyString((const char16_t *)chars); } void PythonExternalString::finalize(char16_t *chars) const @@ -67,28 +73,40 @@ void PythonExternalString::finalize(char16_t *chars) const // We cannot call Py_DECREF here when shutting down as the thread state is gone. // Then, when shutting down, there is only on reference left, and we don't need // to free the object since the entire process memory is being released. - PyObject *object = ucs2ToPyObjectMap[chars]; - if (Py_REFCNT(object) > 1) { - Py_DECREF(object); + if (_Py_IsFinalizing()) { return; } + + for (auto it = jsExternalStringPyObjects.cbegin(), next_it = it; it != jsExternalStringPyObjects.cend(); it = next_it) { + next_it++; + if (PyUnicode_DATA(it->first) == (void *)chars) { + Py_DECREF(it->first); + jsExternalStringPyObjects[it->first] = jsExternalStringPyObjects[it->first] - 1; + + if (jsExternalStringPyObjects[it->first] == 0) { + jsExternalStringPyObjects.erase(it); + } + } } } void PythonExternalString::finalize(JS::Latin1Char *chars) const { - PyObject *object = latin1ToPyObjectMap[chars]; - if (Py_REFCNT(object) > 1) { - Py_DECREF(object); - } + PythonExternalString::finalize((char16_t *)chars); } size_t PythonExternalString::sizeOfBuffer(const char16_t *chars, mozilla::MallocSizeOf mallocSizeOf) const { - return PyUnicode_GetLength(ucs2ToPyObjectMap[chars]); + for (auto it: jsExternalStringPyObjects) { + if (PyUnicode_DATA(it.first) == (void *)chars) { + return PyUnicode_GetLength(it.first); + } + } + + return 0; // // this shouldn't be reachable } size_t PythonExternalString::sizeOfBuffer(const JS::Latin1Char *chars, mozilla::MallocSizeOf mallocSizeOf) const { - return PyUnicode_GetLength(latin1ToPyObjectMap[chars]); + return PythonExternalString::sizeOfBuffer((const char16_t *)chars, mallocSizeOf); } PythonExternalString PythonExternalStringCallbacks = {}; @@ -151,13 +169,15 @@ JS::Value jsTypeFactory(JSContext *cx, PyObject *object) { break; } case (PyUnicode_2BYTE_KIND): { - ucs2ToPyObjectMap[(char16_t *)PyUnicode_2BYTE_DATA(object)] = object; + jsExternalStringPyObjects[object] = jsExternalStringPyObjects[object] + 1; + Py_INCREF(object); JSString *str = JS_NewExternalUCString(cx, (char16_t *)PyUnicode_2BYTE_DATA(object), PyUnicode_GET_LENGTH(object), &PythonExternalStringCallbacks); returnType.setString(str); break; } case (PyUnicode_1BYTE_KIND): { - latin1ToPyObjectMap[(JS::Latin1Char *)PyUnicode_1BYTE_DATA(object)] = object; + jsExternalStringPyObjects[object] = jsExternalStringPyObjects[object] + 1; + Py_INCREF(object); JSString *str = JS_NewExternalStringLatin1(cx, (JS::Latin1Char *)PyUnicode_1BYTE_DATA(object), PyUnicode_GET_LENGTH(object), &PythonExternalStringCallbacks); // JSExternalString can now be properly treated as either one-byte or two-byte strings when GCed // see https://hg.mozilla.org/releases/mozilla-esr128/file/tip/js/src/vm/StringType-inl.h#l785 @@ -165,7 +185,6 @@ JS::Value jsTypeFactory(JSContext *cx, PyObject *object) { break; } } - Py_INCREF(object); } else if (PyMethod_Check(object) || PyFunction_Check(object) || PyCFunction_Check(object)) { // can't determine number of arguments for PyCFunctions, so just assume potentially unbounded From 4f67bfa071223a2abf55e4c676a24ac4b3a4cb4f Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 27 Aug 2024 01:44:27 +0000 Subject: [PATCH 248/428] chore(CI): add support for Python 3.8 & 3.9 on arm64 macOS --- .github/workflows/test-and-publish.yaml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 6f3521c6..9456782e 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -129,13 +129,6 @@ jobs: matrix: os: [ 'ubuntu-20.04', 'macos-12', 'macos-14', 'windows-2022', 'pi' ] python_version: [ '3.8', '3.9', '3.10', '3.11', '3.12' ] - exclude: - # actions/setup-python: The version '3.8'/'3.9' with architecture 'arm64' was not found for macOS. - # see https://raw.githubusercontent.com/actions/python-versions/main/versions-manifest.json - - os: 'macos-14' - python_version: '3.8' - - os: 'macos-14' - python_version: '3.9' runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 From ab20f54a0adac53bda9c24e4e6f7f2f2025920c3 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 27 Aug 2024 09:18:14 +0000 Subject: [PATCH 249/428] chore(CI): make the commit author be a bot --- .github/workflows/update-mozcentral-version.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/update-mozcentral-version.yaml b/.github/workflows/update-mozcentral-version.yaml index 8f95895f..acc10136 100644 --- a/.github/workflows/update-mozcentral-version.yaml +++ b/.github/workflows/update-mozcentral-version.yaml @@ -33,6 +33,7 @@ jobs: add-paths: mozcentral.version commit-message: | chore(deps): upgrade SpiderMonkey to `${{ env.MOZCENTRAL_VERSION }}` + author: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> branch: chore/upgrade-spidermonkey-to-${{ env.MOZCENTRAL_VERSION_SHORT }} title: Upgrade SpiderMonkey to mozilla-central commit `${{ env.MOZCENTRAL_VERSION }}` body: | From 91edcc88ed7157c9479eeb50c0f2b16397f6d4e5 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 27 Aug 2024 09:35:22 +0000 Subject: [PATCH 250/428] chore(CI): lower the update frequency to every month as we don't have enough bandwidth --- .github/workflows/update-mozcentral-version.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/update-mozcentral-version.yaml b/.github/workflows/update-mozcentral-version.yaml index acc10136..470aeeac 100644 --- a/.github/workflows/update-mozcentral-version.yaml +++ b/.github/workflows/update-mozcentral-version.yaml @@ -2,7 +2,8 @@ name: 'Create pull requests to update mozilla-central version to the latest' on: schedule: - - cron: "00 14 * * 1" # run every Monday at 14:00 UTC (10:00 Eastern Daylight Time) + - cron: "00 14 */100,1-7 * 1" # run on the first Monday of each month at 14:00 UTC (10:00 Eastern Daylight Time) + # See https://blog.healthchecks.io/2022/09/schedule-cron-job-the-funky-way/ workflow_call: workflow_dispatch: # or you can run it manually From a6acc569513819264849f9ac782cfcc2fe784cd3 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 27 Aug 2024 09:37:10 +0000 Subject: [PATCH 251/428] chore(CI): automatically assign the PR to @Xmader --- .github/workflows/update-mozcentral-version.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/update-mozcentral-version.yaml b/.github/workflows/update-mozcentral-version.yaml index 470aeeac..027720b8 100644 --- a/.github/workflows/update-mozcentral-version.yaml +++ b/.github/workflows/update-mozcentral-version.yaml @@ -40,3 +40,4 @@ jobs: body: | Changeset: https://hg.mozilla.org/mozilla-central/rev/${{ env.MOZCENTRAL_VERSION }} labels: dependencies + assignees: Xmader From 1951efcc6f80e99a6b822d0a04658b3175e6b0a9 Mon Sep 17 00:00:00 2001 From: Caleb Aikens Date: Wed, 28 Aug 2024 10:12:30 -0400 Subject: [PATCH 252/428] chore(jsTypeFactory) rename variable, add comment explaining PyUnicode_DATA casting --- src/jsTypeFactory.cc | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/jsTypeFactory.cc b/src/jsTypeFactory.cc index 8d6f12c5..60834188 100644 --- a/src/jsTypeFactory.cc +++ b/src/jsTypeFactory.cc @@ -49,12 +49,12 @@ static PyObjectProxyHandler pyObjectProxyHandler; static PyListProxyHandler pyListProxyHandler; static PyIterableProxyHandler pyIterableProxyHandler; -std::unordered_map jsExternalStringPyObjects;// a map of python string objects to the number of JSExternalStrings that depend on it, used when finalizing JSExternalStrings +std::unordered_map externalStringObjToRefCountMap;// a map of python string objects to the number of JSExternalStrings that depend on it, used when finalizing JSExternalStrings PyObject *PythonExternalString::getPyString(const char16_t *chars) { - for (auto it: jsExternalStringPyObjects) { - if (PyUnicode_DATA(it.first) == (void *)chars) { + for (auto it: externalStringObjToRefCountMap) { + if (PyUnicode_DATA(it.first) == (void *)chars) { // PyUnicode_<2/1>BYTE_DATA are just type casts of PyUnicode_DATA return it.first; } } @@ -75,14 +75,14 @@ void PythonExternalString::finalize(char16_t *chars) const // to free the object since the entire process memory is being released. if (_Py_IsFinalizing()) { return; } - for (auto it = jsExternalStringPyObjects.cbegin(), next_it = it; it != jsExternalStringPyObjects.cend(); it = next_it) { + for (auto it = externalStringObjToRefCountMap.cbegin(), next_it = it; it != externalStringObjToRefCountMap.cend(); it = next_it) { next_it++; if (PyUnicode_DATA(it->first) == (void *)chars) { Py_DECREF(it->first); - jsExternalStringPyObjects[it->first] = jsExternalStringPyObjects[it->first] - 1; + externalStringObjToRefCountMap[it->first] = externalStringObjToRefCountMap[it->first] - 1; - if (jsExternalStringPyObjects[it->first] == 0) { - jsExternalStringPyObjects.erase(it); + if (externalStringObjToRefCountMap[it->first] == 0) { + externalStringObjToRefCountMap.erase(it); } } } @@ -95,7 +95,7 @@ void PythonExternalString::finalize(JS::Latin1Char *chars) const size_t PythonExternalString::sizeOfBuffer(const char16_t *chars, mozilla::MallocSizeOf mallocSizeOf) const { - for (auto it: jsExternalStringPyObjects) { + for (auto it: externalStringObjToRefCountMap) { if (PyUnicode_DATA(it.first) == (void *)chars) { return PyUnicode_GetLength(it.first); } @@ -169,14 +169,14 @@ JS::Value jsTypeFactory(JSContext *cx, PyObject *object) { break; } case (PyUnicode_2BYTE_KIND): { - jsExternalStringPyObjects[object] = jsExternalStringPyObjects[object] + 1; + externalStringObjToRefCountMap[object] = externalStringObjToRefCountMap[object] + 1; Py_INCREF(object); JSString *str = JS_NewExternalUCString(cx, (char16_t *)PyUnicode_2BYTE_DATA(object), PyUnicode_GET_LENGTH(object), &PythonExternalStringCallbacks); returnType.setString(str); break; } case (PyUnicode_1BYTE_KIND): { - jsExternalStringPyObjects[object] = jsExternalStringPyObjects[object] + 1; + externalStringObjToRefCountMap[object] = externalStringObjToRefCountMap[object] + 1; Py_INCREF(object); JSString *str = JS_NewExternalStringLatin1(cx, (JS::Latin1Char *)PyUnicode_1BYTE_DATA(object), PyUnicode_GET_LENGTH(object), &PythonExternalStringCallbacks); // JSExternalString can now be properly treated as either one-byte or two-byte strings when GCed From 18a419749532a1649b507db9e66c146c3339b354 Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Wed, 28 Aug 2024 16:45:55 -0400 Subject: [PATCH 253/428] set max gc heap size to maximum --- src/modules/pythonmonkey/pythonmonkey.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/modules/pythonmonkey/pythonmonkey.cc b/src/modules/pythonmonkey/pythonmonkey.cc index 93412150..e1610a27 100644 --- a/src/modules/pythonmonkey/pythonmonkey.cc +++ b/src/modules/pythonmonkey/pythonmonkey.cc @@ -562,6 +562,8 @@ PyMODINIT_FUNC PyInit_pythonmonkey(void) return NULL; } + JS_SetGCParameter(GLOBAL_CX, JSGC_MAX_BYTES, (uint32_t)-1); + JS_SetGCCallback(GLOBAL_CX, pythonmonkeyGCCallback, NULL); JS::RealmCreationOptions creationOptions = JS::RealmCreationOptions(); From bcfd87a048f29f88f9dcfe87b7b39e74c704eaa5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 2 Sep 2024 14:13:09 +0000 Subject: [PATCH 254/428] chore(deps): upgrade SpiderMonkey to `a283127a5d0aa005c54d339e8ca27414b55f079b` --- mozcentral.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mozcentral.version b/mozcentral.version index 0efd2b63..9f4b8194 100644 --- a/mozcentral.version +++ b/mozcentral.version @@ -1 +1 @@ -8a28ad54f9f516c41ceddfa7ea32368fccf4a0eb \ No newline at end of file +a283127a5d0aa005c54d339e8ca27414b55f079b \ No newline at end of file From 0f3039b6135b32f42ffd949dcca2170b55c60b7a Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 4 Sep 2024 23:48:57 +0000 Subject: [PATCH 255/428] fix: heap use-after-free for `JS::UniqueChars` `JS::UniqueChars` will free the string buffer in its destructor, so it must be kept alive until the end of the function --- src/PyObjectProxyHandler.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/PyObjectProxyHandler.cc b/src/PyObjectProxyHandler.cc index 565e6122..63e77dd2 100644 --- a/src/PyObjectProxyHandler.cc +++ b/src/PyObjectProxyHandler.cc @@ -44,8 +44,9 @@ bool PyObjectProxyHandler::handleGetOwnPropertyDescriptor(JSContext *cx, JS::Han JS::MutableHandle> desc, PyObject *item) { // see if we're calling a function if (id.isString()) { - JS::RootedString idString(cx, id.toString()); - const char *methodName = JS_EncodeStringToUTF8(cx, idString).get(); + JS::UniqueChars idString = JS_EncodeStringToUTF8(cx, JS::RootedString(cx, id.toString())); + const char *methodName = idString.get(); + if (!strcmp(methodName, "toString") || !strcmp(methodName, "toLocaleString") || !strcmp(methodName, "valueOf")) { JS::RootedObject objectPrototype(cx); if (!JS_GetClassPrototype(cx, JSProto_Object, &objectPrototype)) { From dc97949b9b730c6157fca64eb2a5cf7aa8f84f25 Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Thu, 5 Sep 2024 16:26:04 -0400 Subject: [PATCH 256/428] readme updates for 1.0 release --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 899a0090..cf2fa283 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # PythonMonkey -![Testing Suite](https://github.com/Kings-Distributed-Systems/PythonMonkey/actions/workflows/tests.yaml/badge.svg) +[![Test and Publish Suite](https://github.com/Distributive-Network/PythonMonkey/actions/workflows/test-and-publish.yaml/badge.svg)](https://github.com/Distributive-Network/PythonMonkey/actions/workflows/test-and-publish.yaml) ## About [PythonMonkey](https://pythonmonkey.io) is a Mozilla [SpiderMonkey](https://firefox-source-docs.mozilla.org/js/index.html) JavaScript engine embedded into the Python Runtime, @@ -8,7 +8,7 @@ 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 product is in an advanced stage, approximately 98% to MVP as of August 2024. It is under active development by [Distributive](https://distributive.network/). +This product is in release stage, having reached MVP in September 2024. It is under maintenance by [Distributive](https://distributive.network/). External contributions and feedback are welcome and encouraged. @@ -73,7 +73,7 @@ Read this if you want to build a local version. - llvm - rust - python3.8 or later with header files (python3-dev) - - spidermonkey 115.1.0 or later + - spidermonkey latest from mozilla-central - npm (nodejs) - [Poetry](https://python-poetry.org/docs/#installation) - [poetry-dynamic-versioning](https://github.com/mtkennerly/poetry-dynamic-versioning) @@ -462,7 +462,7 @@ List of commands: ```console $ pmjs -Welcome to PythonMonkey v0.4.0. +Welcome to PythonMonkey v1.0.0. Type ".help" for more information. > .python import sys > .python sys.path From 2185eaa218cf10ef8277da3dc758de06e273135a Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Thu, 5 Sep 2024 16:27:32 -0400 Subject: [PATCH 257/428] release status rewording --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cf2fa283..d43e19c9 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ 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 product is in release stage, having reached MVP in September 2024. It is under maintenance by [Distributive](https://distributive.network/). +This project has reached MVP as of September 2024. It is under maintenance by [Distributive](https://distributive.network/). External contributions and feedback are welcome and encouraged. From 935e9e99cf89ca826b2be3100e61d9cb2d5bb953 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Fri, 6 Sep 2024 06:08:05 +0000 Subject: [PATCH 258/428] fix: the string corruption bug String buffers memory would be moved around during a minor GC (nursery collection). The string buffer pointer obtained by `JS::Get{Latin1,TwoByte}LinearStringChars` remains valid only as long as no GC happens. Even though `JS::PersistentRootedValue` does keep the string buffer from being garbage-collected, it does not guarantee the buffer would not be moved elsewhere during a GC, and so invalidates the string buffer pointer. --- src/modules/pythonmonkey/pythonmonkey.cc | 43 ++++++++++++++++-------- 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/src/modules/pythonmonkey/pythonmonkey.cc b/src/modules/pythonmonkey/pythonmonkey.cc index e1610a27..36a15d20 100644 --- a/src/modules/pythonmonkey/pythonmonkey.cc +++ b/src/modules/pythonmonkey/pythonmonkey.cc @@ -48,25 +48,39 @@ JS::PersistentRootedObject jsFunctionRegistry; +/** + * @brief During a GC, string buffers may have moved, so we need to re-point our JSStringProxies + * The char buffer pointer obtained by previous `JS::Get{Latin1,TwoByte}LinearStringChars` calls remains valid only as long as no GC occurs. + */ +void updateCharBufferPointers() { + if (_Py_IsFinalizing()) { + return; // do not move char pointers around if python is finalizing + } + + JS::AutoCheckCannotGC nogc; + for (const JSStringProxy *jsStringProxy: jsStringProxies) { + JSLinearString *str = JS_ASSERT_STRING_IS_LINEAR(jsStringProxy->jsString->toString()); + void *updatedCharBufPtr; // pointer to the moved char buffer after a GC + if (JS::LinearStringHasLatin1Chars(str)) { + updatedCharBufPtr = (void *)JS::GetLatin1LinearStringChars(nogc, str); + } else { // utf16 / ucs2 string + updatedCharBufPtr = (void *)JS::GetTwoByteLinearStringChars(nogc, str); + } + ((PyUnicodeObject *)(jsStringProxy))->data.any = updatedCharBufPtr; + } +} + void pythonmonkeyGCCallback(JSContext *cx, JSGCStatus status, JS::GCReason reason, void *data) { if (status == JSGCStatus::JSGC_END) { JS::ClearKeptObjects(GLOBAL_CX); while (JOB_QUEUE->runFinalizationRegistryCallbacks(GLOBAL_CX)); + updateCharBufferPointers(); + } +} - if (_Py_IsFinalizing()) { - return; // do not move char pointers around if python is finalizing - } - - JS::AutoCheckCannotGC nogc; - for (const JSStringProxy *jsStringProxy: jsStringProxies) { // char buffers may have moved, so we need to re-point our JSStringProxies - JSLinearString *str = (JSLinearString *)(jsStringProxy->jsString->toString()); // jsString is guaranteed to be linear - if (JS::LinearStringHasLatin1Chars(str)) { - (((PyUnicodeObject *)(jsStringProxy))->data.any) = (void *)JS::GetLatin1LinearStringChars(nogc, str); - } - else { // utf16 / ucs2 string - (((PyUnicodeObject *)(jsStringProxy))->data.any) = (void *)JS::GetTwoByteLinearStringChars(nogc, str); - } - } +void nurseryCollectionCallback(JSContext *cx, JS::GCNurseryProgress progress, JS::GCReason reason, void *data) { + if (progress == JS::GCNurseryProgress::GC_NURSERY_COLLECTION_END) { + updateCharBufferPointers(); } } @@ -565,6 +579,7 @@ PyMODINIT_FUNC PyInit_pythonmonkey(void) JS_SetGCParameter(GLOBAL_CX, JSGC_MAX_BYTES, (uint32_t)-1); JS_SetGCCallback(GLOBAL_CX, pythonmonkeyGCCallback, NULL); + JS::AddGCNurseryCollectionCallback(GLOBAL_CX, nurseryCollectionCallback, NULL); JS::RealmCreationOptions creationOptions = JS::RealmCreationOptions(); JS::RealmBehaviors behaviours = JS::RealmBehaviors(); From 3fcd1dbb18c2a0adea6388c4fae84fa2483fb4f1 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Mon, 9 Sep 2024 23:07:17 +0000 Subject: [PATCH 259/428] docs: add uninstallation instructions --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index d43e19c9..1532ae6f 100644 --- a/README.md +++ b/README.md @@ -136,6 +136,15 @@ $ 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 uninstall`ing a package won't automatically remove its dependencies. +If you want to cleanly remove `pythonmonkey` from your system, do the following: + +```bash +$ pip uninstall pythonmonkey pminit +``` + ## Debugging Steps 1. [build the project locally](#build-instructions) From 15b8cd024d0e107422616d50e49f2ed34a03ed64 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 10 Sep 2024 04:53:31 +0000 Subject: [PATCH 260/428] chore(CI): publish nightly builds even for tagged releases --- .github/workflows/test-and-publish.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index ca4cc8fc..143217e9 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -297,7 +297,7 @@ jobs: publish: needs: [build-and-test, sdist] runs-on: ubuntu-20.04 - if: ${{ success() && github.event_name == 'push' && contains(github.ref, 'refs/tags/') }} + if: ${{ success() && github.event_name == 'push' && github.ref_type == 'tag' }} steps: # no need to checkout - uses: actions/setup-python@v5 @@ -320,7 +320,7 @@ jobs: # and deploy the static files to GitHub Pages needs: [build-and-test, sdist] runs-on: ubuntu-20.04 - if: ${{ (success() || failure()) && github.ref_name == 'main' }} # publish nightly builds regardless of tests failure + if: ${{ (success() || failure()) && (github.ref_name == 'main' || github.ref_type == 'tag') }} # publish nightly builds regardless of tests failure permissions: # grant GITHUB_TOKEN the permissions required to make a Pages deployment pages: write id-token: write From 412ca1055f95acd5e9e30a1b7706393d09e55821 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 10 Sep 2024 04:58:37 +0000 Subject: [PATCH 261/428] fix(CI): trigger CI only on release tags instead of all tags --- .github/workflows/test-and-publish.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 143217e9..2ac3e699 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -5,7 +5,7 @@ on: branches: - main tags: - - '*' + - 'v*' workflow_call: workflow_dispatch: inputs: From 4ee52daa4c0505ce93f4233797c3129aa90eaec9 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 10 Sep 2024 05:03:11 +0000 Subject: [PATCH 262/428] chore(CI): only allow one concurrent CI run for a single branch --- .github/workflows/test-and-publish.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 2ac3e699..c77a083f 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -54,6 +54,10 @@ defaults: # run with Git Bash on Windows shell: bash +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: build-spidermonkey-unix: strategy: From 0fa946f6e6f893e3aa5110062829b9d155305f8e Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 10 Sep 2024 05:53:04 +0000 Subject: [PATCH 263/428] =?UTF-8?q?CI:=20publish=20to=20=E2=8A=87istributi?= =?UTF-8?q?ve's=20archive=20server?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit URL: https://archive.distributed.computer/releases/pythonmonkey/ --- .github/workflows/test-and-publish.yaml | 41 +++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index c77a083f..814be3c0 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -379,3 +379,44 @@ jobs: - name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@v2 + publish-archive: + # Publish to ⊇istributive's archive server (https://archive.distributed.computer/releases/pythonmonkey/) + needs: [build-and-test, sdist] + runs-on: ubuntu-20.04 + if: ${{ (success() || failure()) && true }} # (github.ref_name == 'main' || github.ref_type == 'tag') + environment: + name: archive + url: https://archive.distributed.computer/releases/pythonmonkey/${{ steps.get_path.outputs.ARCHIVE_PATH }} + steps: + # no need to checkout + - name: Download wheels built + uses: actions/download-artifact@v3 + with: + name: wheel-${{ github.run_id }}-${{ github.sha }} + path: ./ + - name: Download docs html generated by Doxygen + uses: actions/download-artifact@v3 + with: + name: docs-${{ github.run_id }}-${{ github.sha }} + path: ./docs/ + - name: Get the pythonmonkey/pminit version number + run: | + file=$(ls ./pminit*.tar.gz | head -1) + pm_version=$(basename "${file%.tar.gz}" | cut -d- -f2) # match /pminit-([^-]+).tar.gz/ + echo "PM_VERSION=$pm_version" >> $GITHUB_ENV + - name: Get the archive type (nightly or releases) and path + id: get_path + run: | + path="$ARCHIVE_TYPE/$PM_VERSION/" + echo "$path" + echo "ARCHIVE_PATH=$path" >> $GITHUB_OUTPUT + env: + ARCHIVE_TYPE: ${{ (github.ref_type == 'tag' && 'releases') || 'nightly' }} + - name: SCP to the archive server + uses: appleboy/scp-action@v0.1.7 + with: + host: ${{ secrets.ARCHIVE_HOST }} + username: ${{ secrets.ARCHIVE_USERNAME }} + key: ${{ secrets.ARCHIVE_KEY }} + source: ./* + target: ${{ steps.get_path.outputs.ARCHIVE_PATH }} From 7e9f53c5c16d7927d551839a2f0c2853d7e47b4d Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 10 Sep 2024 06:09:59 +0000 Subject: [PATCH 264/428] =?UTF-8?q?fix(CI):=20publishing=20to=20=E2=8A=87i?= =?UTF-8?q?stributive's=20archive=20server?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/test-and-publish.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 814be3c0..9eb33d4a 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -416,7 +416,7 @@ jobs: uses: appleboy/scp-action@v0.1.7 with: host: ${{ secrets.ARCHIVE_HOST }} - username: ${{ secrets.ARCHIVE_USERNAME }} + username: pythonmonkey key: ${{ secrets.ARCHIVE_KEY }} source: ./* - target: ${{ steps.get_path.outputs.ARCHIVE_PATH }} + target: archive/${{ steps.get_path.outputs.ARCHIVE_PATH }} From b774b58a7517e6f9c1714628c72c531e980ae27f Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 10 Sep 2024 06:29:07 +0000 Subject: [PATCH 265/428] fix(CI): publishing to the archive server only for nightly&release builds --- .github/workflows/test-and-publish.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 9eb33d4a..c0261c67 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -383,7 +383,7 @@ jobs: # Publish to ⊇istributive's archive server (https://archive.distributed.computer/releases/pythonmonkey/) needs: [build-and-test, sdist] runs-on: ubuntu-20.04 - if: ${{ (success() || failure()) && true }} # (github.ref_name == 'main' || github.ref_type == 'tag') + if: ${{ (success() || failure()) && (github.ref_name == 'main' || github.ref_type == 'tag') }} environment: name: archive url: https://archive.distributed.computer/releases/pythonmonkey/${{ steps.get_path.outputs.ARCHIVE_PATH }} @@ -420,3 +420,4 @@ jobs: key: ${{ secrets.ARCHIVE_KEY }} source: ./* target: archive/${{ steps.get_path.outputs.ARCHIVE_PATH }} + overwrite: true From b53b8c1658a3f52336616f329517cea9d1abd1bf Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Tue, 10 Sep 2024 14:11:20 -0400 Subject: [PATCH 266/428] snprintf warning fix --- src/PyBytesProxyHandler.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/PyBytesProxyHandler.cc b/src/PyBytesProxyHandler.cc index 14da16c9..c49f2580 100644 --- a/src/PyBytesProxyHandler.cc +++ b/src/PyBytesProxyHandler.cc @@ -39,22 +39,22 @@ static bool array_valueOf(JSContext *cx, unsigned argc, JS::Value *vp) { for (size_t i = 0; i < byteLength; i++) { numberOfDigits += data[i] < 10 ? 1 : data[i] < 100 ? 2 : 3; } + const size_t STRING_LENGTH = byteLength + numberOfDigits; JS::Latin1Char *buffer = (JS::Latin1Char *)malloc(sizeof(JS::Latin1Char) * STRING_LENGTH); - size_t charIndex = 0; - snprintf((char *)&buffer[charIndex], 4, "%d", data[0]); - charIndex += data[0] < 10 ? 1 : data[0] < 100 ? 2 : 3; + snprintf((char *)&buffer[0], 3 + 1, "%hu", data[0]); + size_t charIndex = data[0] < 10 ? 1 : data[0] < 100 ? 2 : 3; for (size_t dataIndex = 1; dataIndex < byteLength; dataIndex++) { buffer[charIndex] = ','; charIndex++; - snprintf((char *)&buffer[charIndex], 4, "%d", data[dataIndex]); + snprintf((char *)&buffer[charIndex], 3 + 1, "%hu", data[dataIndex]); charIndex += data[dataIndex] < 10 ? 1 : data[dataIndex] < 100 ? 2 : 3; } JS::UniqueLatin1Chars str(buffer); - args.rval().setString(JS_NewLatin1String(cx, std::move(str), STRING_LENGTH - 1)); // don't include null byte + args.rval().setString(JS_NewLatin1String(cx, std::move(str), STRING_LENGTH - 1)); // don't include the null terminating byte return true; } From 52181e17c35711dc24a41f03f748387e3513a129 Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Tue, 10 Sep 2024 15:39:51 -0400 Subject: [PATCH 267/428] check for snprintf return value for full fix to warning --- src/PyBytesProxyHandler.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/PyBytesProxyHandler.cc b/src/PyBytesProxyHandler.cc index c49f2580..525b0068 100644 --- a/src/PyBytesProxyHandler.cc +++ b/src/PyBytesProxyHandler.cc @@ -43,13 +43,17 @@ static bool array_valueOf(JSContext *cx, unsigned argc, JS::Value *vp) { const size_t STRING_LENGTH = byteLength + numberOfDigits; JS::Latin1Char *buffer = (JS::Latin1Char *)malloc(sizeof(JS::Latin1Char) * STRING_LENGTH); - snprintf((char *)&buffer[0], 3 + 1, "%hu", data[0]); + if (snprintf((char *)&buffer[0], 3 + 1, "%hu", data[0]) < 0) { + return false; + } size_t charIndex = data[0] < 10 ? 1 : data[0] < 100 ? 2 : 3; for (size_t dataIndex = 1; dataIndex < byteLength; dataIndex++) { buffer[charIndex] = ','; charIndex++; - snprintf((char *)&buffer[charIndex], 3 + 1, "%hu", data[dataIndex]); + if (snprintf((char *)&buffer[charIndex], 3 + 1, "%hu", data[dataIndex]) < 0) { + return false; + } charIndex += data[dataIndex] < 10 ? 1 : data[dataIndex] < 100 ? 2 : 3; } From c4efe828f0d1ecf9611e4ff5b8940d03c8349a12 Mon Sep 17 00:00:00 2001 From: Caleb Aikens Date: Wed, 11 Sep 2024 10:20:53 -0400 Subject: [PATCH 268/428] fix(tests): remove old xhr.simple test, add new test that uses a local server --- tests/python/test_xhr.py | 97 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 tests/python/test_xhr.py diff --git a/tests/python/test_xhr.py b/tests/python/test_xhr.py new file mode 100644 index 00000000..40d99e62 --- /dev/null +++ b/tests/python/test_xhr.py @@ -0,0 +1,97 @@ +from http.server import HTTPServer, BaseHTTPRequestHandler +import pythonmonkey as pm +import threading +import asyncio +import json + +def test_xhr(): + class TestHTTPRequestHandler(BaseHTTPRequestHandler): + def log_request(self, code: int | str = "-", size: int | str = "-") -> None: + return + + def do_GET(self): + self.send_response(200) + self.end_headers() + self.wfile.write(b"get response") + + def do_POST(self): + self.send_response(200) + self.send_header('Content-Type', 'application/json') + self.end_headers() + length = int(self.headers.get('Content-Length')) + json_string = self.rfile.read(length).decode("utf-8") + parameter_dict = json.loads(json_string) + parameter_dict["User-Agent"] = self.headers['User-Agent'] + data = json.dumps(parameter_dict).encode("utf-8") + self.wfile.write(data) + + httpd = HTTPServer(('localhost', 4001), TestHTTPRequestHandler) + thread = threading.Thread(target = httpd.serve_forever) + thread.daemon = True + thread.start() + + async def async_fn(): + assert "get response" == await pm.eval(""" + new Promise(function (resolve, reject) { + let xhr = new XMLHttpRequest(); + xhr.open('GET', 'http://localhost:4001'); + + xhr.onload = function () + { + if (this.status >= 200 && this.status < 300) + { + resolve(this.response); + } + else + { + reject(new Error(JSON.stringify({ + status: this.status, + statusText: this.statusText + }))); + } + }; + + xhr.onerror = function (ev) + { + reject(ev.error); + }; + xhr.send(); + }); + """) + + post_result = await pm.eval(""" + new Promise(function (resolve, reject) + { + let xhr = new XMLHttpRequest(); + xhr.open('POST', 'http://localhost:4001'); + + xhr.onload = function () + { + if (this.status >= 200 && this.status < 300) + { + resolve(this.response); + } + else + { + reject(new Error(JSON.stringify({ + status: this.status, + statusText: this.statusText + }))); + } + }; + + xhr.onerror = function (ev) + { + console.log(ev) + reject(ev.error); + }; + + xhr.send(JSON.stringify({fromPM: "snakesandmonkeys"})); + }) + """) + + result_json = json.loads(post_result) + assert result_json["fromPM"] == "snakesandmonkeys" + assert result_json["User-Agent"].startswith("Python/") + httpd.shutdown() + asyncio.run(async_fn()) \ No newline at end of file From 67f92487502896fcd1c0f8de96279a27df1907c6 Mon Sep 17 00:00:00 2001 From: Caleb Aikens Date: Wed, 11 Sep 2024 10:37:20 -0400 Subject: [PATCH 269/428] remove old test --- tests/js/xhr.simple | 136 -------------------------------------------- 1 file changed, 136 deletions(-) delete mode 100644 tests/js/xhr.simple diff --git a/tests/js/xhr.simple b/tests/js/xhr.simple deleted file mode 100644 index 8c61e6dc..00000000 --- a/tests/js/xhr.simple +++ /dev/null @@ -1,136 +0,0 @@ -/** - * @file xhr.simple - * - * Simple smoke test which ensures that XMLHttpRequest is initialized, that the - * constructor works, and that it can send requests and receive responses. - * - * @author Caleb Aikens, caleb@distributive.network - * @date September 2023 - */ - -const expectedBody = ` - - - Example Domain - - - - - - - - -
-

Example Domain

-

This domain is for use in illustrative examples in documents. You may use this - domain in literature without prior coordination or asking for permission.

-

More information...

-
- - -`; - -new Promise(function (resolve, reject) -{ - let xhr = new XMLHttpRequest(); - xhr.open('GET', 'http://www.example.org/'); - - xhr.onload = function () - { - if (this.status >= 200 && this.status < 300) - { - resolve(this.response); - } - else - { - reject(new Error(JSON.stringify({ - status: this.status, - statusText: this.statusText - }))); - } - }; - - xhr.onerror = function (ev) - { - reject(ev.error); - }; - - xhr.send(); -}).then((value) => -{ - if (value !== expectedBody) - { - console.error('expected ', expectedBody, ' but got ', value); - throw new Error('Test failed'); - } - console.log('Test passed'); -}).catch((error) => -{ - throw error; -}); - - -new Promise(function (resolve, reject) -{ - let xhr = new XMLHttpRequest(); - xhr.open('POST', 'http://httpbin.org/post'); - - xhr.onload = function () - { - if (this.status >= 200 && this.status < 300) - { - resolve(this.response); - } - else - { - reject(new Error(JSON.stringify({ - status: this.status, - statusText: this.statusText - }))); - } - }; - - xhr.onerror = function (ev) - { - reject(ev.error); - }; - - xhr.send(); -}).then((value) => -{ - value = JSON.parse(value); - if (!value['headers']['User-Agent'].startsWith('Python/')) - { - console.error('expected Python/* User-Agent, but got ', value.headers['User-Agent']); - } - console.log('Test passed'); -}).catch((error) => -{ - throw error; -}); \ No newline at end of file From 225c7531257c03521a30ff1dd8ec8f2186871074 Mon Sep 17 00:00:00 2001 From: Caleb Aikens Date: Wed, 11 Sep 2024 11:10:17 -0400 Subject: [PATCH 270/428] fix(tests): fix syntax error in test_xhr.py for python3.8-3.9 --- tests/python/test_xhr.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/python/test_xhr.py b/tests/python/test_xhr.py index 40d99e62..990193eb 100644 --- a/tests/python/test_xhr.py +++ b/tests/python/test_xhr.py @@ -6,7 +6,7 @@ def test_xhr(): class TestHTTPRequestHandler(BaseHTTPRequestHandler): - def log_request(self, code: int | str = "-", size: int | str = "-") -> None: + def log_request(self, *args) -> None: return def do_GET(self): From eca9450a8d0dfb72378fa7d1f3a5f62ced563500 Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Wed, 11 Sep 2024 13:36:21 -0400 Subject: [PATCH 271/428] Detect exception in iterator next call and StopIteration --- src/JSObjectProxy.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/JSObjectProxy.cc b/src/JSObjectProxy.cc index 13b3e609..f6c41f24 100644 --- a/src/JSObjectProxy.cc +++ b/src/JSObjectProxy.cc @@ -320,6 +320,13 @@ PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_iter_next(JSObjectProxy PyObject *retVal = JSFunctionProxyMethodDefinitions::JSFunctionProxy_call(nextFunction, PyTuple_New(0), NULL); Py_DECREF(nextFunction); + if (retVal == NULL) { + if (PyErr_Occurred()) { + PyErr_PrintEx(0); + } + PyErr_SetNone(PyExc_StopIteration); + return NULL; + } // check if end of iteration key = PyUnicode_FromString("done"); From face6db48e525fe957a45f71baceb59748cd39c7 Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Wed, 11 Sep 2024 13:59:44 -0400 Subject: [PATCH 272/428] added relevant test --- tests/python/test_dict_methods.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/python/test_dict_methods.py b/tests/python/test_dict_methods.py index a303f73a..1fd7fcbb 100644 --- a/tests/python/test_dict_methods.py +++ b/tests/python/test_dict_methods.py @@ -555,3 +555,19 @@ def test_next_operator(): assert (True) fourth = next(myit, 'default') assert fourth == 'default' + + +def test_next_operator_non_iterator(): + make_js_generator = pm.eval(""" + function* sliceGenerator(pyIter) + { + yield python.eval('lambda x: next(x)')(pyIter); + } + sliceGenerator; + """) + + try: + next(make_js_generator(range(0,5))) + assert (False) + except StopIteration as e: + assert (True) \ No newline at end of file From 639c1a1eca49e16ff3a0a30d7ef7026eced4d2e7 Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Wed, 11 Sep 2024 15:03:31 -0400 Subject: [PATCH 273/428] Class method must declare self arg by python rules. Enforce it --- src/jsTypeFactory.cc | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/jsTypeFactory.cc b/src/jsTypeFactory.cc index 60834188..24eb5c4e 100644 --- a/src/jsTypeFactory.cc +++ b/src/jsTypeFactory.cc @@ -379,14 +379,22 @@ bool callPyFunc(JSContext *cx, unsigned int argc, JS::Value *vp) { else { nNormalArgs = 1; PyObject *f = pyFunc; + bool isMethod; if (PyMethod_Check(pyFunc)) { f = PyMethod_Function(pyFunc); // borrowed reference nNormalArgs -= 1; // don't include the implicit `self` of the method as an argument + isMethod = true; + } else { + isMethod = false; } PyCodeObject *bytecode = (PyCodeObject *)PyFunction_GetCode(f); // borrowed reference PyObject *defaults = PyFunction_GetDefaults(f); // borrowed reference nDefaultArgs = defaults ? PyTuple_Size(defaults) : 0; - nNormalArgs += bytecode->co_argcount - nDefaultArgs - 1; + if (bytecode->co_argcount == 0 && isMethod) { + nNormalArgs += nDefaultArgs; + } else { + nNormalArgs += bytecode->co_argcount - nDefaultArgs - 1; + } if (bytecode->co_flags & CO_VARARGS) { varargs = true; } From 81c69150a65d662fdc50af1748d9f383534e5b31 Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Wed, 11 Sep 2024 15:14:54 -0400 Subject: [PATCH 274/428] test for method missing self in JS call --- tests/python/test_functions_this.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/python/test_functions_this.py b/tests/python/test_functions_this.py index dc20f416..cbfd7157 100644 --- a/tests/python/test_functions_this.py +++ b/tests/python/test_functions_this.py @@ -202,3 +202,19 @@ def pyFunc(): pm.collect() # this should collect the JS proxy to pyFunc, which should decref pyFunc # pyFunc should be collected by now assert ref[0]() is None + + +def test_method_no_self(): + class What: + def some_method(): + return 3 + + obj = What() + + try: + pm.eval('x => x.some_method()')(obj) + assert (False) + except Exception as e: + assert str(type(e)) == "" + assert str(e).__contains__('TypeError:') + assert str(e).__contains__('takes 0 positional arguments but 1 was given') \ No newline at end of file From dc12241fb726c553c6a09b2e83fcd75c7054f51e Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Wed, 11 Sep 2024 15:37:36 -0400 Subject: [PATCH 275/428] test fix: more generic to work on Python < 3.12 --- tests/python/test_functions_this.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/python/test_functions_this.py b/tests/python/test_functions_this.py index cbfd7157..5f17c584 100644 --- a/tests/python/test_functions_this.py +++ b/tests/python/test_functions_this.py @@ -216,5 +216,4 @@ def some_method(): assert (False) except Exception as e: assert str(type(e)) == "" - assert str(e).__contains__('TypeError:') assert str(e).__contains__('takes 0 positional arguments but 1 was given') \ No newline at end of file From 2d2dcbf3d2eb3664eb3a6bc5166bb8755709c2b5 Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Wed, 11 Sep 2024 16:31:55 -0400 Subject: [PATCH 276/428] simplify exception logic --- src/JSObjectProxy.cc | 4 ---- tests/python/test_dict_methods.py | 5 +++-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/JSObjectProxy.cc b/src/JSObjectProxy.cc index f6c41f24..359b072d 100644 --- a/src/JSObjectProxy.cc +++ b/src/JSObjectProxy.cc @@ -321,10 +321,6 @@ PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_iter_next(JSObjectProxy PyObject *retVal = JSFunctionProxyMethodDefinitions::JSFunctionProxy_call(nextFunction, PyTuple_New(0), NULL); Py_DECREF(nextFunction); if (retVal == NULL) { - if (PyErr_Occurred()) { - PyErr_PrintEx(0); - } - PyErr_SetNone(PyExc_StopIteration); return NULL; } diff --git a/tests/python/test_dict_methods.py b/tests/python/test_dict_methods.py index 1fd7fcbb..f5d32a95 100644 --- a/tests/python/test_dict_methods.py +++ b/tests/python/test_dict_methods.py @@ -569,5 +569,6 @@ def test_next_operator_non_iterator(): try: next(make_js_generator(range(0,5))) assert (False) - except StopIteration as e: - assert (True) \ No newline at end of file + except Exception as e: + assert str(type(e)) == "" + assert str(e).__contains__("'range' object is not an iterator") \ No newline at end of file From 9c9ecf917026635261901bdcecc9be31c6ac932f Mon Sep 17 00:00:00 2001 From: Caleb Aikens Date: Wed, 11 Sep 2024 16:50:53 -0400 Subject: [PATCH 277/428] chore(tests): simplify test --- tests/python/test_dict_methods.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/python/test_dict_methods.py b/tests/python/test_dict_methods.py index f5d32a95..d0fccba9 100644 --- a/tests/python/test_dict_methods.py +++ b/tests/python/test_dict_methods.py @@ -569,6 +569,5 @@ def test_next_operator_non_iterator(): try: next(make_js_generator(range(0,5))) assert (False) - except Exception as e: - assert str(type(e)) == "" - assert str(e).__contains__("'range' object is not an iterator") \ No newline at end of file + except pm.SpiderMonkeyError as e: + assert "'range' object is not an iterator" in str(e) \ No newline at end of file From a72ae89d340f14b5431fce2541079a618047546a Mon Sep 17 00:00:00 2001 From: philippedistributive <151072087+philippedistributive@users.noreply.github.com> Date: Wed, 11 Sep 2024 16:56:30 -0400 Subject: [PATCH 278/428] Update tests/python/test_functions_this.py Co-authored-by: Caleb Aikens --- tests/python/test_functions_this.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/python/test_functions_this.py b/tests/python/test_functions_this.py index 5f17c584..d9cbf528 100644 --- a/tests/python/test_functions_this.py +++ b/tests/python/test_functions_this.py @@ -214,6 +214,5 @@ def some_method(): try: pm.eval('x => x.some_method()')(obj) assert (False) - except Exception as e: - assert str(type(e)) == "" - assert str(e).__contains__('takes 0 positional arguments but 1 was given') \ No newline at end of file + except pm.SpiderMonkeyError as e: + assert 'takes 0 positional arguments but 1 was given' in str(e) \ No newline at end of file From ca1d37ca573b5843e8887a33f7dbd3b3004eb7d9 Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Wed, 11 Sep 2024 16:57:46 -0400 Subject: [PATCH 279/428] logic simplification --- src/jsTypeFactory.cc | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/jsTypeFactory.cc b/src/jsTypeFactory.cc index 24eb5c4e..3e4f89d3 100644 --- a/src/jsTypeFactory.cc +++ b/src/jsTypeFactory.cc @@ -379,29 +379,21 @@ bool callPyFunc(JSContext *cx, unsigned int argc, JS::Value *vp) { else { nNormalArgs = 1; PyObject *f = pyFunc; - bool isMethod; if (PyMethod_Check(pyFunc)) { f = PyMethod_Function(pyFunc); // borrowed reference nNormalArgs -= 1; // don't include the implicit `self` of the method as an argument - isMethod = true; - } else { - isMethod = false; - } + } PyCodeObject *bytecode = (PyCodeObject *)PyFunction_GetCode(f); // borrowed reference PyObject *defaults = PyFunction_GetDefaults(f); // borrowed reference nDefaultArgs = defaults ? PyTuple_Size(defaults) : 0; - if (bytecode->co_argcount == 0 && isMethod) { - nNormalArgs += nDefaultArgs; - } else { - nNormalArgs += bytecode->co_argcount - nDefaultArgs - 1; - } + nNormalArgs += bytecode->co_argcount - nDefaultArgs - 1; if (bytecode->co_flags & CO_VARARGS) { varargs = true; } } // use faster calling if no arguments are needed - if (((nNormalArgs + nDefaultArgs) == 0 && !varargs)) { + if (((nNormalArgs + nDefaultArgs) <= 0 && !varargs)) { #if PY_VERSION_HEX >= 0x03090000 pyRval = PyObject_CallNoArgs(pyFunc); #else From 2f30f991eb199efdeffb1988482d1f1832722553 Mon Sep 17 00:00:00 2001 From: Philippe Laporte Date: Tue, 17 Sep 2024 11:44:27 -0400 Subject: [PATCH 280/428] cleanup unused code --- src/JSArrayProxy.cc | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/src/JSArrayProxy.cc b/src/JSArrayProxy.cc index 12007ac5..5f7d7ec9 100644 --- a/src/JSArrayProxy.cc +++ b/src/JSArrayProxy.cc @@ -1178,31 +1178,12 @@ extern PyObject *const *_PyArg_UnpackKeywords( ); PyObject *JSArrayProxyMethodDefinitions::JSArrayProxy_sort(JSArrayProxy *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - - #define NUM_KEYWORDS 2 - static struct { - PyGC_Head _this_is_not_used; - PyObject_VAR_HEAD - PyObject *ob_item[NUM_KEYWORDS]; - } _kwtuple = { - .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = {&_Py_ID(key), &_Py_ID(reverse), }, - }; - #undef NUM_KEYWORDS - #define KWTUPLE (&_kwtuple.ob_base.ob_base) - - #else // !Py_BUILD_CORE - # define KWTUPLE NULL - #endif // !Py_BUILD_CORE - static const char *const _keywords[] = {"key", "reverse", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, .fname = "sort", - .kwtuple = KWTUPLE, + .kwtuple = NULL, }; - #undef KWTUPLE PyObject *argsbuf[2]; Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; From db5ba719ff090c18b99b4a5bd41d16e728c7a10c Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Fri, 20 Sep 2024 04:29:39 +0000 Subject: [PATCH 281/428] fix: `_Py_IsFinalizing` is renamed to `Py_IsFinalizing` in Python 3.13 `_Py_IsFinalizing` becomes a stable API in Python 3.13, and is renamed to `Py_IsFinalizing` https://docs.python.org/3.13/c-api/init.html#c.Py_IsFinalizing --- include/pyshim.hh | 28 ++++++++++++++++++++++++ src/PyListProxyHandler.cc | 4 ++-- src/PyObjectProxyHandler.cc | 3 ++- src/jsTypeFactory.cc | 8 +++---- src/modules/pythonmonkey/pythonmonkey.cc | 3 ++- 5 files changed, 38 insertions(+), 8 deletions(-) create mode 100644 include/pyshim.hh diff --git a/include/pyshim.hh b/include/pyshim.hh new file mode 100644 index 00000000..ba6b4caa --- /dev/null +++ b/include/pyshim.hh @@ -0,0 +1,28 @@ +/** + * @file pyshim.hh + * @author Tom Tang (xmader@distributive.network) + * @brief Python's C APIs are constantly changing in different versions of CPython. + * PythonMonkey has a wide variety of CPython versions' support. (Currently Python 3.8-3.13) + * This file helps our Python API calls work with different Python versions in the same code base. + * @date 2024-09-20 + * + * @copyright Copyright (c) 2024 Distributive Corp. + * + */ + +#ifndef PythonMonkey_py_version_shim_ +#define PythonMonkey_py_version_shim_ + +#include + +/** + * @brief `_Py_IsFinalizing` becomes a stable API in Python 3.13, + * and renames to `Py_IsFinalizing` + */ +#if PY_VERSION_HEX >= 0x030d0000 // Python version is greater than 3.13 + #define Py_IsFinalizing Py_IsFinalizing +#else + #define Py_IsFinalizing _Py_IsFinalizing +#endif + +#endif // #ifndef PythonMonkey_py_version_shim_ diff --git a/src/PyListProxyHandler.cc b/src/PyListProxyHandler.cc index d6d9747b..f03fb67d 100644 --- a/src/PyListProxyHandler.cc +++ b/src/PyListProxyHandler.cc @@ -24,7 +24,7 @@ #include #include - +#include "include/pyshim.hh" const char PyListProxyHandler::family = 0; @@ -2099,7 +2099,7 @@ void PyListProxyHandler::finalize(JS::GCContext *gcx, JSObject *proxy) const { // We cannot call Py_DECREF here when shutting down as the thread state is gone. // Then, when shutting down, there is only on reference left, and we don't need // to free the object since the entire process memory is being released. - if (!_Py_IsFinalizing()) { + if (!Py_IsFinalizing()) { PyObject *self = JS::GetMaybePtrFromReservedSlot(proxy, PyObjectSlot); Py_DECREF(self); } diff --git a/src/PyObjectProxyHandler.cc b/src/PyObjectProxyHandler.cc index 63e77dd2..7f5e4b70 100644 --- a/src/PyObjectProxyHandler.cc +++ b/src/PyObjectProxyHandler.cc @@ -21,6 +21,7 @@ #include #include +#include "include/pyshim.hh" const char PyObjectProxyHandler::family = 0; @@ -88,7 +89,7 @@ void PyObjectProxyHandler::finalize(JS::GCContext *gcx, JSObject *proxy) const { // We cannot call Py_DECREF here when shutting down as the thread state is gone. // Then, when shutting down, there is only on reference left, and we don't need // to free the object since the entire process memory is being released. - if (!_Py_IsFinalizing()) { + if (!Py_IsFinalizing()) { PyObject *self = JS::GetMaybePtrFromReservedSlot(proxy, PyObjectSlot); Py_DECREF(self); } diff --git a/src/jsTypeFactory.cc b/src/jsTypeFactory.cc index 3e4f89d3..36139c09 100644 --- a/src/jsTypeFactory.cc +++ b/src/jsTypeFactory.cc @@ -36,6 +36,7 @@ #include #include +#include "include/pyshim.hh" #include @@ -49,7 +50,7 @@ static PyObjectProxyHandler pyObjectProxyHandler; static PyListProxyHandler pyListProxyHandler; static PyIterableProxyHandler pyIterableProxyHandler; -std::unordered_map externalStringObjToRefCountMap;// a map of python string objects to the number of JSExternalStrings that depend on it, used when finalizing JSExternalStrings +std::unordered_map externalStringObjToRefCountMap; // a map of python string objects to the number of JSExternalStrings that depend on it, used when finalizing JSExternalStrings PyObject *PythonExternalString::getPyString(const char16_t *chars) { @@ -64,7 +65,6 @@ PyObject *PythonExternalString::getPyString(const char16_t *chars) PyObject *PythonExternalString::getPyString(const JS::Latin1Char *chars) { - return PythonExternalString::getPyString((const char16_t *)chars); } @@ -73,7 +73,7 @@ void PythonExternalString::finalize(char16_t *chars) const // We cannot call Py_DECREF here when shutting down as the thread state is gone. // Then, when shutting down, there is only on reference left, and we don't need // to free the object since the entire process memory is being released. - if (_Py_IsFinalizing()) { return; } + if (Py_IsFinalizing()) { return; } for (auto it = externalStringObjToRefCountMap.cbegin(), next_it = it; it != externalStringObjToRefCountMap.cend(); it = next_it) { next_it++; @@ -382,7 +382,7 @@ bool callPyFunc(JSContext *cx, unsigned int argc, JS::Value *vp) { if (PyMethod_Check(pyFunc)) { f = PyMethod_Function(pyFunc); // borrowed reference nNormalArgs -= 1; // don't include the implicit `self` of the method as an argument - } + } PyCodeObject *bytecode = (PyCodeObject *)PyFunction_GetCode(f); // borrowed reference PyObject *defaults = PyFunction_GetDefaults(f); // borrowed reference nDefaultArgs = defaults ? PyTuple_Size(defaults) : 0; diff --git a/src/modules/pythonmonkey/pythonmonkey.cc b/src/modules/pythonmonkey/pythonmonkey.cc index 36a15d20..597f937b 100644 --- a/src/modules/pythonmonkey/pythonmonkey.cc +++ b/src/modules/pythonmonkey/pythonmonkey.cc @@ -41,6 +41,7 @@ #include #include +#include "include/pyshim.hh" #include #include @@ -53,7 +54,7 @@ JS::PersistentRootedObject jsFunctionRegistry; * The char buffer pointer obtained by previous `JS::Get{Latin1,TwoByte}LinearStringChars` calls remains valid only as long as no GC occurs. */ void updateCharBufferPointers() { - if (_Py_IsFinalizing()) { + if (Py_IsFinalizing()) { return; // do not move char pointers around if python is finalizing } From 07da1db421effdd10c0c65a0e6c625b3ba747154 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Fri, 20 Sep 2024 04:50:21 +0000 Subject: [PATCH 282/428] refactor: move the `_PyDictViewObject` shim to the `pyshim.hh` header file --- include/JSObjectItemsProxy.hh | 2 +- include/JSObjectKeysProxy.hh | 2 +- include/JSObjectValuesProxy.hh | 2 +- include/dictviewShim.hh | 28 ---------------------------- include/pyshim.hh | 11 +++++++++++ src/JSObjectKeysProxy.cc | 4 +--- src/JSObjectProxy.cc | 2 +- src/JSObjectValuesProxy.cc | 4 +--- 8 files changed, 17 insertions(+), 38 deletions(-) delete mode 100644 include/dictviewShim.hh diff --git a/include/JSObjectItemsProxy.hh b/include/JSObjectItemsProxy.hh index 8523620c..59d16517 100644 --- a/include/JSObjectItemsProxy.hh +++ b/include/JSObjectItemsProxy.hh @@ -14,7 +14,7 @@ #include #include -#include "include/dictviewShim.hh" +#include "include/pyshim.hh" /** diff --git a/include/JSObjectKeysProxy.hh b/include/JSObjectKeysProxy.hh index f4693b68..e2a8beef 100644 --- a/include/JSObjectKeysProxy.hh +++ b/include/JSObjectKeysProxy.hh @@ -14,7 +14,7 @@ #include #include -#include "include/dictviewShim.hh" +#include "include/pyshim.hh" /** diff --git a/include/JSObjectValuesProxy.hh b/include/JSObjectValuesProxy.hh index 82aae114..17c2af23 100644 --- a/include/JSObjectValuesProxy.hh +++ b/include/JSObjectValuesProxy.hh @@ -14,7 +14,7 @@ #include #include -#include "include/dictviewShim.hh" +#include "include/pyshim.hh" /** diff --git a/include/dictviewShim.hh b/include/dictviewShim.hh deleted file mode 100644 index 50883e96..00000000 --- a/include/dictviewShim.hh +++ /dev/null @@ -1,28 +0,0 @@ -/** - * @file dictviewShim.hh - * @author Tom Tang (xmader@distributive.network) - * @brief Since Python 3.13, `_PyDictView` moved from Python's public API to the **internal** header file `internal/pycore_dict.h`. - * This file behaves as a shim to bring back its definitions. - * The code here is copied from https://github.com/python/cpython/blob/v3.13.0rc1/Include/internal/pycore_dict.h#L64-L72. - * @date 2024-08-21 - * - * @copyright Copyright (c) 2024 Distributive Corp. - * - */ - -#ifndef PythonMonkey_dictview_shim_ -#define PythonMonkey_dictview_shim_ - -#include - -/* _PyDictView */ - -typedef struct { - PyObject_HEAD - PyDictObject *dv_dict; -} _PyDictViewObject; - -extern PyObject *_PyDictView_New(PyObject *, PyTypeObject *); -extern PyObject *_PyDictView_Intersect(PyObject *self, PyObject *other); - -#endif diff --git a/include/pyshim.hh b/include/pyshim.hh index ba6b4caa..058a5572 100644 --- a/include/pyshim.hh +++ b/include/pyshim.hh @@ -25,4 +25,15 @@ #define Py_IsFinalizing _Py_IsFinalizing #endif +/** + * @brief `_PyDictViewObject` type definition moved from Python's public API + * to the **internal** header file `internal/pycore_dict.h` in Python 3.13. + * + * @see https://github.com/python/cpython/blob/v3.13.0rc1/Include/internal/pycore_dict.h#L64-L72 + */ +typedef struct { + PyObject_HEAD + PyDictObject *dv_dict; +} _PyDictViewObject; + #endif // #ifndef PythonMonkey_py_version_shim_ diff --git a/src/JSObjectKeysProxy.cc b/src/JSObjectKeysProxy.cc index 29590e52..4c4e54ce 100644 --- a/src/JSObjectKeysProxy.cc +++ b/src/JSObjectKeysProxy.cc @@ -22,9 +22,7 @@ #include #include -#include "include/dictviewShim.hh" - - +#include "include/pyshim.hh" void JSObjectKeysProxyMethodDefinitions::JSObjectKeysProxy_dealloc(JSObjectKeysProxy *self) { diff --git a/src/JSObjectProxy.cc b/src/JSObjectProxy.cc index 9bb643a5..83295f2f 100644 --- a/src/JSObjectProxy.cc +++ b/src/JSObjectProxy.cc @@ -27,7 +27,7 @@ #include #include -#include "include/dictviewShim.hh" +#include "include/pyshim.hh" #include diff --git a/src/JSObjectValuesProxy.cc b/src/JSObjectValuesProxy.cc index ab5af78f..ead71b66 100644 --- a/src/JSObjectValuesProxy.cc +++ b/src/JSObjectValuesProxy.cc @@ -22,9 +22,7 @@ #include #include -#include "include/dictviewShim.hh" - - +#include "include/pyshim.hh" void JSObjectValuesProxyMethodDefinitions::JSObjectValuesProxy_dealloc(JSObjectValuesProxy *self) { From a8ac1f6e116781dbebdd909b6b22ffc6d012ddb2 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Fri, 20 Sep 2024 05:12:46 +0000 Subject: [PATCH 283/428] feat: add shim for `_PyDictView_New` Since Python 3.13, `_PyDictView_New` function became an internal API. --- src/JSObjectProxy.cc | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/JSObjectProxy.cc b/src/JSObjectProxy.cc index 83295f2f..2c542855 100644 --- a/src/JSObjectProxy.cc +++ b/src/JSObjectProxy.cc @@ -774,14 +774,29 @@ PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_update_method(JSObjectPr Py_RETURN_NONE; } +/** + * @brief Shim for `_PyDictView_New`. + * Since Python 3.13, `_PyDictView_New` function became an internal API. + * @see Modified from https://github.com/python/cpython/blob/v3.13.0rc1/Objects/dictobject.c#L5806-L5827 + */ +PyObject *newPyDictViewObject(PyObject *dict, PyTypeObject *type) { + _PyDictViewObject *dv; + dv = PyObject_GC_New(_PyDictViewObject, type); + if (dv == NULL) + return NULL; + dv->dv_dict = (PyDictObject *)Py_NewRef(dict); + PyObject_GC_Track(dv); + return (PyObject *)dv; +} + PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_keys_method(JSObjectProxy *self) { - return _PyDictView_New((PyObject *)self, &JSObjectKeysProxyType); + return newPyDictViewObject((PyObject *)self, &JSObjectKeysProxyType); } PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_values_method(JSObjectProxy *self) { - return _PyDictView_New((PyObject *)self, &JSObjectValuesProxyType); + return newPyDictViewObject((PyObject *)self, &JSObjectValuesProxyType); } PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_items_method(JSObjectProxy *self) { - return _PyDictView_New((PyObject *)self, &JSObjectItemsProxyType); + return newPyDictViewObject((PyObject *)self, &JSObjectItemsProxyType); } \ No newline at end of file From 9fd54126bc089a3d12c1f22200f339161c7363d1 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Fri, 20 Sep 2024 05:50:30 +0000 Subject: [PATCH 284/428] fix: `_PyErr_SetKeyError` is removed in Python 3.13 Python 3.13 moved this undocumented function to private API. See https://github.com/python/cpython/pull/108607 --- src/JSObjectProxy.cc | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/JSObjectProxy.cc b/src/JSObjectProxy.cc index 2c542855..487e554a 100644 --- a/src/JSObjectProxy.cc +++ b/src/JSObjectProxy.cc @@ -669,9 +669,6 @@ PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_setdefault_method(JSObje return value; } -// Python 3.13 moved this undocumented function to private API. Re-exporting it here. -extern void _PyErr_SetKeyError(PyObject *); - PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_pop_method(JSObjectProxy *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *key; PyObject *default_value = NULL; @@ -696,7 +693,7 @@ PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_pop_method(JSObjectProxy Py_INCREF(default_value); return default_value; } - _PyErr_SetKeyError(key); + PyErr_SetObject(PyExc_KeyError, key); return NULL; } else { From 8d2f1a11452f6f07a4e5c83b5c9340b514ffde5d Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Fri, 20 Sep 2024 06:04:42 +0000 Subject: [PATCH 285/428] WIP: `_PyThreadState_GetDict(tstate)` API gets removed in Python 3.13 --- include/PyEventLoop.hh | 4 ---- src/PyEventLoop.cc | 8 +++++++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/include/PyEventLoop.hh b/include/PyEventLoop.hh index 5e3b56a3..a4c643f2 100644 --- a/include/PyEventLoop.hh +++ b/include/PyEventLoop.hh @@ -331,8 +331,4 @@ private: static inline std::vector _timeoutIdMap; }; -// See https://github.com/python/cpython/blob/v3.13.0rc1/Python/pystate.c#L1940-L1951 -// Python 3.13 removed it from the public API. Re-exporting here. -extern PyObject *_PyThreadState_GetDict(PyThreadState *tstate); - #endif \ No newline at end of file diff --git a/src/PyEventLoop.cc b/src/PyEventLoop.cc index 13d6759e..14ed2084 100644 --- a/src/PyEventLoop.cc +++ b/src/PyEventLoop.cc @@ -140,7 +140,13 @@ PyEventLoop PyEventLoop::_loopNotFound() { /* static */ PyEventLoop PyEventLoop::_getLoopOnThread(PyThreadState *tstate) { // Modified from Python 3.9 `get_running_loop` https://github.com/python/cpython/blob/7cb3a44/Modules/_asynciomodule.c#L241-L278 - #if PY_VERSION_HEX >= 0x03090000 // Python version is greater than 3.9 + + #if PY_VERSION_HEX >= 0x030d0000 // Python version is greater than 3.13 + // The private `_PyThreadState_GetDict(tstate)` API gets removed in Python 3.13. + // However, the fix below cannot be a perfect replacement since the public `PyThreadState_GetDict()` API can only get from the current thread. + // We need to somehow get the thread dictionary on the main thread instead of the current thread. + PyObject *ts_dict = PyThreadState_GetDict(); + #elif PY_VERSION_HEX >= 0x03090000 // Python version is greater than 3.9 PyObject *ts_dict = _PyThreadState_GetDict(tstate); // borrowed reference #else // Python 3.8 PyObject *ts_dict = tstate->dict; // see https://github.com/python/cpython/blob/v3.8.17/Modules/_asynciomodule.c#L244-L245 From 9826939c7403c9d63a688623f6e6a67692ee3e8c Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Fri, 20 Sep 2024 06:18:44 +0000 Subject: [PATCH 286/428] WIP: `_PyArg_UnpackKeywords` is removed --- src/JSArrayProxy.cc | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/JSArrayProxy.cc b/src/JSArrayProxy.cc index 5f7d7ec9..ccc44cb8 100644 --- a/src/JSArrayProxy.cc +++ b/src/JSArrayProxy.cc @@ -1168,15 +1168,6 @@ static bool sort_compare_default(JSContext *cx, unsigned argc, JS::Value *vp) { return true; } -// Python 3.13 moved this function to private API. Re-exporting it. -extern PyObject *const *_PyArg_UnpackKeywords( - PyObject *const *args, Py_ssize_t nargs, - PyObject *kwargs, PyObject *kwnames, - struct _PyArg_Parser *parser, - int minpos, int maxpos, int minkw, - PyObject **buf -); - PyObject *JSArrayProxyMethodDefinitions::JSArrayProxy_sort(JSArrayProxy *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { static const char *const _keywords[] = {"key", "reverse", NULL}; static _PyArg_Parser _parser = { @@ -1190,7 +1181,9 @@ PyObject *JSArrayProxyMethodDefinitions::JSArrayProxy_sort(JSArrayProxy *self, P PyObject *keyfunc = Py_None; int reverse = 0; - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 0, 0, argsbuf); + // args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 0, 0, argsbuf); + Py_RETURN_NONE; + if (!args) { return NULL; } From f6de9c3d0c1c648d5be9b2a0495b9978ed6c5c6f Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Fri, 20 Sep 2024 06:26:03 +0000 Subject: [PATCH 287/428] fix: `_PyDictViewObject` typedef redefinition with different types on Python < 3.13 --- include/pyshim.hh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/pyshim.hh b/include/pyshim.hh index 058a5572..250d289d 100644 --- a/include/pyshim.hh +++ b/include/pyshim.hh @@ -31,9 +31,11 @@ * * @see https://github.com/python/cpython/blob/v3.13.0rc1/Include/internal/pycore_dict.h#L64-L72 */ +#if PY_VERSION_HEX >= 0x030d0000 // Python version is greater than 3.13 typedef struct { PyObject_HEAD PyDictObject *dv_dict; } _PyDictViewObject; +#endif #endif // #ifndef PythonMonkey_py_version_shim_ From 7d07ee1c25edfecc463c8f9ea88d566c04665106 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Fri, 20 Sep 2024 06:30:57 +0000 Subject: [PATCH 288/428] fix: `Py_NewRef` API is not available in Python < 3.10 --- src/JSObjectProxy.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/JSObjectProxy.cc b/src/JSObjectProxy.cc index 487e554a..076e1fd5 100644 --- a/src/JSObjectProxy.cc +++ b/src/JSObjectProxy.cc @@ -781,7 +781,8 @@ PyObject *newPyDictViewObject(PyObject *dict, PyTypeObject *type) { dv = PyObject_GC_New(_PyDictViewObject, type); if (dv == NULL) return NULL; - dv->dv_dict = (PyDictObject *)Py_NewRef(dict); + Py_INCREF(dict); + dv->dv_dict = (PyDictObject *)dict; PyObject_GC_Track(dv); return (PyObject *)dv; } From 3368d3b631a4ab15a87efc60de6ad543a10ded04 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Fri, 20 Sep 2024 06:57:49 +0000 Subject: [PATCH 289/428] Revert "WIP: remove the use of the `_PyArg_CheckPositional` private API" This reverts commit dc4442df0093ba8ed351046c5d0410ff3aafe820. --- src/JSArrayProxy.cc | 11 +++++++++++ src/JSObjectProxy.cc | 9 +++++++++ 2 files changed, 20 insertions(+) diff --git a/src/JSArrayProxy.cc b/src/JSArrayProxy.cc index ccc44cb8..1bf7236e 100644 --- a/src/JSArrayProxy.cc +++ b/src/JSArrayProxy.cc @@ -789,6 +789,10 @@ PyObject *JSArrayProxyMethodDefinitions::JSArrayProxy_insert(JSArrayProxy *self, Py_ssize_t index; PyObject *value; + if (!_PyArg_CheckPositional("insert", nargs, 2, 2)) { + return NULL; + } + { Py_ssize_t ival = -1; PyObject *iobj = PyNumber_Index(args[0]); @@ -895,6 +899,10 @@ PyObject *JSArrayProxyMethodDefinitions::JSArrayProxy_extend(JSArrayProxy *self, PyObject *JSArrayProxyMethodDefinitions::JSArrayProxy_pop(JSArrayProxy *self, PyObject *const *args, Py_ssize_t nargs) { Py_ssize_t index = -1; + if (!_PyArg_CheckPositional("pop", nargs, 0, 1)) { + return NULL; + } + if (nargs >= 1) { Py_ssize_t ival = -1; PyObject *iobj = PyNumber_Index(args[0]); @@ -979,6 +987,9 @@ PyObject *JSArrayProxyMethodDefinitions::JSArrayProxy_index(JSArrayProxy *self, Py_ssize_t start = 0; Py_ssize_t stop = PY_SSIZE_T_MAX; + if (!_PyArg_CheckPositional("index", nargs, 1, 3)) { + return NULL; + } value = args[0]; if (nargs < 2) { goto skip_optional; diff --git a/src/JSObjectProxy.cc b/src/JSObjectProxy.cc index 076e1fd5..74b33b2a 100644 --- a/src/JSObjectProxy.cc +++ b/src/JSObjectProxy.cc @@ -623,6 +623,9 @@ PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_get_method(JSObjectProxy PyObject *key; PyObject *default_value = Py_None; + if (!_PyArg_CheckPositional("get", nargs, 1, 2)) { + return NULL; + } key = args[0]; if (nargs < 2) { goto skip_optional; @@ -644,6 +647,9 @@ PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_setdefault_method(JSObje PyObject *key; PyObject *default_value = Py_None; + if (!_PyArg_CheckPositional("setdefault", nargs, 1, 2)) { + return NULL; + } key = args[0]; if (nargs < 2) { goto skip_optional; @@ -673,6 +679,9 @@ PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_pop_method(JSObjectProxy PyObject *key; PyObject *default_value = NULL; + if (!_PyArg_CheckPositional("pop", nargs, 1, 2)) { + return NULL; + } key = args[0]; if (nargs < 2) { goto skip_optional; From 943a431631f1c3b958fc76609fbf671df9547435 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Fri, 20 Sep 2024 07:15:20 +0000 Subject: [PATCH 290/428] fix: `_PyArg_CheckPositional` function became an internal API since Python 3.13 --- include/pyshim.hh | 31 +++++++++++++++++++++++++++++++ src/JSArrayProxy.cc | 1 + 2 files changed, 32 insertions(+) diff --git a/include/pyshim.hh b/include/pyshim.hh index 250d289d..0ab95d92 100644 --- a/include/pyshim.hh +++ b/include/pyshim.hh @@ -38,4 +38,35 @@ typedef struct { } _PyDictViewObject; #endif +/** + * @brief Shim for `_PyArg_CheckPositional`. + * Since Python 3.13, `_PyArg_CheckPositional` function became an internal API. + * @see Modified from https://github.com/python/cpython/blob/v3.13.0rc1/Python/getargs.c#L2738-L2780 + */ +#if PY_VERSION_HEX >= 0x030d0000 // Python version is greater than 3.13 +inline int _PyArg_CheckPositional(const char *name, Py_ssize_t nargs, Py_ssize_t min, Py_ssize_t max) { + if (nargs < min) { + PyErr_Format( + PyExc_TypeError, + "%.200s expected %s%zd argument%s, got %zd", + name, (min == max ? "" : "at least "), min, min == 1 ? "" : "s", nargs); + return 0; + } + + if (nargs == 0) { + return 1; + } + + if (nargs > max) { + PyErr_Format( + PyExc_TypeError, + "%.200s expected %s%zd argument%s, got %zd", + name, (min == max ? "" : "at most "), max, max == 1 ? "" : "s", nargs); + return 0; + } + + return 1; +} +#endif + #endif // #ifndef PythonMonkey_py_version_shim_ diff --git a/src/JSArrayProxy.cc b/src/JSArrayProxy.cc index 1bf7236e..15e83377 100644 --- a/src/JSArrayProxy.cc +++ b/src/JSArrayProxy.cc @@ -23,6 +23,7 @@ #include #include +#include "include/pyshim.hh" void JSArrayProxyMethodDefinitions::JSArrayProxy_dealloc(JSArrayProxy *self) From 7c451e5bf12da9ba9338a15e9c5df766bace5f49 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Fri, 20 Sep 2024 07:17:43 +0000 Subject: [PATCH 291/428] refactor: move the `_PyDictView_New` shim to pyshim.hh --- include/pyshim.hh | 16 ++++++++++++++++ src/JSObjectProxy.cc | 22 +++------------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/include/pyshim.hh b/include/pyshim.hh index 0ab95d92..a1758064 100644 --- a/include/pyshim.hh +++ b/include/pyshim.hh @@ -69,4 +69,20 @@ inline int _PyArg_CheckPositional(const char *name, Py_ssize_t nargs, Py_ssize_t } #endif +/** + * @brief Shim for `_PyDictView_New`. + * Since Python 3.13, `_PyDictView_New` function became an internal API. + * @see Modified from https://github.com/python/cpython/blob/v3.13.0rc1/Objects/dictobject.c#L5806-L5827 + */ +inline PyObject *PyDictViewObject_new(PyObject *dict, PyTypeObject *type) { + _PyDictViewObject *dv; + dv = PyObject_GC_New(_PyDictViewObject, type); + if (dv == NULL) + return NULL; + Py_INCREF(dict); + dv->dv_dict = (PyDictObject *)dict; + PyObject_GC_Track(dv); + return (PyObject *)dv; +} + #endif // #ifndef PythonMonkey_py_version_shim_ diff --git a/src/JSObjectProxy.cc b/src/JSObjectProxy.cc index 74b33b2a..9f34436a 100644 --- a/src/JSObjectProxy.cc +++ b/src/JSObjectProxy.cc @@ -780,30 +780,14 @@ PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_update_method(JSObjectPr Py_RETURN_NONE; } -/** - * @brief Shim for `_PyDictView_New`. - * Since Python 3.13, `_PyDictView_New` function became an internal API. - * @see Modified from https://github.com/python/cpython/blob/v3.13.0rc1/Objects/dictobject.c#L5806-L5827 - */ -PyObject *newPyDictViewObject(PyObject *dict, PyTypeObject *type) { - _PyDictViewObject *dv; - dv = PyObject_GC_New(_PyDictViewObject, type); - if (dv == NULL) - return NULL; - Py_INCREF(dict); - dv->dv_dict = (PyDictObject *)dict; - PyObject_GC_Track(dv); - return (PyObject *)dv; -} - PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_keys_method(JSObjectProxy *self) { - return newPyDictViewObject((PyObject *)self, &JSObjectKeysProxyType); + return PyDictViewObject_new((PyObject *)self, &JSObjectKeysProxyType); } PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_values_method(JSObjectProxy *self) { - return newPyDictViewObject((PyObject *)self, &JSObjectValuesProxyType); + return PyDictViewObject_new((PyObject *)self, &JSObjectValuesProxyType); } PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_items_method(JSObjectProxy *self) { - return newPyDictViewObject((PyObject *)self, &JSObjectItemsProxyType); + return PyDictViewObject_new((PyObject *)self, &JSObjectItemsProxyType); } \ No newline at end of file From d6e4cff05eab9e9da57dea9932cced4412782ced Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Fri, 20 Sep 2024 07:23:56 +0000 Subject: [PATCH 292/428] refactor: shim for `_PyArg_CheckPositional` --- include/pyshim.hh | 4 +--- src/JSArrayProxy.cc | 6 +++--- src/JSObjectProxy.cc | 6 +++--- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/include/pyshim.hh b/include/pyshim.hh index a1758064..a5e19ff5 100644 --- a/include/pyshim.hh +++ b/include/pyshim.hh @@ -43,8 +43,7 @@ typedef struct { * Since Python 3.13, `_PyArg_CheckPositional` function became an internal API. * @see Modified from https://github.com/python/cpython/blob/v3.13.0rc1/Python/getargs.c#L2738-L2780 */ -#if PY_VERSION_HEX >= 0x030d0000 // Python version is greater than 3.13 -inline int _PyArg_CheckPositional(const char *name, Py_ssize_t nargs, Py_ssize_t min, Py_ssize_t max) { +inline int PyArg_CheckNArgs(const char *name, Py_ssize_t nargs, Py_ssize_t min, Py_ssize_t max) { if (nargs < min) { PyErr_Format( PyExc_TypeError, @@ -67,7 +66,6 @@ inline int _PyArg_CheckPositional(const char *name, Py_ssize_t nargs, Py_ssize_t return 1; } -#endif /** * @brief Shim for `_PyDictView_New`. diff --git a/src/JSArrayProxy.cc b/src/JSArrayProxy.cc index 15e83377..0509f9c4 100644 --- a/src/JSArrayProxy.cc +++ b/src/JSArrayProxy.cc @@ -790,7 +790,7 @@ PyObject *JSArrayProxyMethodDefinitions::JSArrayProxy_insert(JSArrayProxy *self, Py_ssize_t index; PyObject *value; - if (!_PyArg_CheckPositional("insert", nargs, 2, 2)) { + if (!PyArg_CheckNArgs("insert", nargs, 2, 2)) { return NULL; } @@ -900,7 +900,7 @@ PyObject *JSArrayProxyMethodDefinitions::JSArrayProxy_extend(JSArrayProxy *self, PyObject *JSArrayProxyMethodDefinitions::JSArrayProxy_pop(JSArrayProxy *self, PyObject *const *args, Py_ssize_t nargs) { Py_ssize_t index = -1; - if (!_PyArg_CheckPositional("pop", nargs, 0, 1)) { + if (!PyArg_CheckNArgs("pop", nargs, 0, 1)) { return NULL; } @@ -988,7 +988,7 @@ PyObject *JSArrayProxyMethodDefinitions::JSArrayProxy_index(JSArrayProxy *self, Py_ssize_t start = 0; Py_ssize_t stop = PY_SSIZE_T_MAX; - if (!_PyArg_CheckPositional("index", nargs, 1, 3)) { + if (!PyArg_CheckNArgs("index", nargs, 1, 3)) { return NULL; } value = args[0]; diff --git a/src/JSObjectProxy.cc b/src/JSObjectProxy.cc index 9f34436a..36cf51e4 100644 --- a/src/JSObjectProxy.cc +++ b/src/JSObjectProxy.cc @@ -623,7 +623,7 @@ PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_get_method(JSObjectProxy PyObject *key; PyObject *default_value = Py_None; - if (!_PyArg_CheckPositional("get", nargs, 1, 2)) { + if (!PyArg_CheckNArgs("get", nargs, 1, 2)) { return NULL; } key = args[0]; @@ -647,7 +647,7 @@ PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_setdefault_method(JSObje PyObject *key; PyObject *default_value = Py_None; - if (!_PyArg_CheckPositional("setdefault", nargs, 1, 2)) { + if (!PyArg_CheckNArgs("setdefault", nargs, 1, 2)) { return NULL; } key = args[0]; @@ -679,7 +679,7 @@ PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_pop_method(JSObjectProxy PyObject *key; PyObject *default_value = NULL; - if (!_PyArg_CheckPositional("pop", nargs, 1, 2)) { + if (!PyArg_CheckNArgs("pop", nargs, 1, 2)) { return NULL; } key = args[0]; From 7c03098252f43fb35f686e7a280cc461fb1f8d9b Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Fri, 20 Sep 2024 07:30:21 +0000 Subject: [PATCH 293/428] Revert "refactor: shim for `_PyArg_CheckPositional`" This reverts commit d6e4cff05eab9e9da57dea9932cced4412782ced. --- include/pyshim.hh | 4 +++- src/JSArrayProxy.cc | 6 +++--- src/JSObjectProxy.cc | 6 +++--- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/include/pyshim.hh b/include/pyshim.hh index a5e19ff5..a1758064 100644 --- a/include/pyshim.hh +++ b/include/pyshim.hh @@ -43,7 +43,8 @@ typedef struct { * Since Python 3.13, `_PyArg_CheckPositional` function became an internal API. * @see Modified from https://github.com/python/cpython/blob/v3.13.0rc1/Python/getargs.c#L2738-L2780 */ -inline int PyArg_CheckNArgs(const char *name, Py_ssize_t nargs, Py_ssize_t min, Py_ssize_t max) { +#if PY_VERSION_HEX >= 0x030d0000 // Python version is greater than 3.13 +inline int _PyArg_CheckPositional(const char *name, Py_ssize_t nargs, Py_ssize_t min, Py_ssize_t max) { if (nargs < min) { PyErr_Format( PyExc_TypeError, @@ -66,6 +67,7 @@ inline int PyArg_CheckNArgs(const char *name, Py_ssize_t nargs, Py_ssize_t min, return 1; } +#endif /** * @brief Shim for `_PyDictView_New`. diff --git a/src/JSArrayProxy.cc b/src/JSArrayProxy.cc index 0509f9c4..15e83377 100644 --- a/src/JSArrayProxy.cc +++ b/src/JSArrayProxy.cc @@ -790,7 +790,7 @@ PyObject *JSArrayProxyMethodDefinitions::JSArrayProxy_insert(JSArrayProxy *self, Py_ssize_t index; PyObject *value; - if (!PyArg_CheckNArgs("insert", nargs, 2, 2)) { + if (!_PyArg_CheckPositional("insert", nargs, 2, 2)) { return NULL; } @@ -900,7 +900,7 @@ PyObject *JSArrayProxyMethodDefinitions::JSArrayProxy_extend(JSArrayProxy *self, PyObject *JSArrayProxyMethodDefinitions::JSArrayProxy_pop(JSArrayProxy *self, PyObject *const *args, Py_ssize_t nargs) { Py_ssize_t index = -1; - if (!PyArg_CheckNArgs("pop", nargs, 0, 1)) { + if (!_PyArg_CheckPositional("pop", nargs, 0, 1)) { return NULL; } @@ -988,7 +988,7 @@ PyObject *JSArrayProxyMethodDefinitions::JSArrayProxy_index(JSArrayProxy *self, Py_ssize_t start = 0; Py_ssize_t stop = PY_SSIZE_T_MAX; - if (!PyArg_CheckNArgs("index", nargs, 1, 3)) { + if (!_PyArg_CheckPositional("index", nargs, 1, 3)) { return NULL; } value = args[0]; diff --git a/src/JSObjectProxy.cc b/src/JSObjectProxy.cc index 36cf51e4..9f34436a 100644 --- a/src/JSObjectProxy.cc +++ b/src/JSObjectProxy.cc @@ -623,7 +623,7 @@ PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_get_method(JSObjectProxy PyObject *key; PyObject *default_value = Py_None; - if (!PyArg_CheckNArgs("get", nargs, 1, 2)) { + if (!_PyArg_CheckPositional("get", nargs, 1, 2)) { return NULL; } key = args[0]; @@ -647,7 +647,7 @@ PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_setdefault_method(JSObje PyObject *key; PyObject *default_value = Py_None; - if (!PyArg_CheckNArgs("setdefault", nargs, 1, 2)) { + if (!_PyArg_CheckPositional("setdefault", nargs, 1, 2)) { return NULL; } key = args[0]; @@ -679,7 +679,7 @@ PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_pop_method(JSObjectProxy PyObject *key; PyObject *default_value = NULL; - if (!PyArg_CheckNArgs("pop", nargs, 1, 2)) { + if (!_PyArg_CheckPositional("pop", nargs, 1, 2)) { return NULL; } key = args[0]; From d3c0f8581ab75b7fb63a4d690df7429019aa8f82 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Fri, 20 Sep 2024 07:59:07 +0000 Subject: [PATCH 294/428] fix: `_PyArg_UnpackKeywords` API is removed, use `PyArg_ParseTupleAndKeywords` instead --- include/JSArrayProxy.hh | 7 +++---- src/JSArrayProxy.cc | 34 +++------------------------------- 2 files changed, 6 insertions(+), 35 deletions(-) diff --git a/include/JSArrayProxy.hh b/include/JSArrayProxy.hh index 6cf98ea0..0f452708 100644 --- a/include/JSArrayProxy.hh +++ b/include/JSArrayProxy.hh @@ -251,11 +251,10 @@ public: * * @param self - The JSArrayProxy * @param args - arguments to the sort method (not used) - * @param nargs - number of arguments to the sort method - * @param kwnames - keyword arguments to the sort method (reverse=True|False, key=keyfunction) + * @param kwargs - keyword arguments to the sort method (reverse=True|False, key=keyfunction) * @return PyObject* NULL on exception, None otherwise */ - static PyObject *JSArrayProxy_sort(JSArrayProxy *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames); + static PyObject *JSArrayProxy_sort(JSArrayProxy *self, PyObject *args, PyObject *kwargs); /** * @brief tp_traverse @@ -404,7 +403,7 @@ static PyMethodDef JSArrayProxy_methods[] = { {"index", (PyCFunction)JSArrayProxyMethodDefinitions::JSArrayProxy_index, METH_FASTCALL, list_index__doc__}, {"count", (PyCFunction)JSArrayProxyMethodDefinitions::JSArrayProxy_count, METH_O, list_count__doc__}, {"reverse", (PyCFunction)JSArrayProxyMethodDefinitions::JSArrayProxy_reverse, METH_NOARGS, list_reverse__doc__}, - {"sort", (PyCFunction)JSArrayProxyMethodDefinitions::JSArrayProxy_sort, METH_FASTCALL|METH_KEYWORDS, list_sort__doc__}, + {"sort", (PyCFunction)JSArrayProxyMethodDefinitions::JSArrayProxy_sort, METH_VARARGS|METH_KEYWORDS, list_sort__doc__}, {NULL, NULL} /* sentinel */ }; diff --git a/src/JSArrayProxy.cc b/src/JSArrayProxy.cc index 15e83377..d7adc776 100644 --- a/src/JSArrayProxy.cc +++ b/src/JSArrayProxy.cc @@ -1180,43 +1180,15 @@ static bool sort_compare_default(JSContext *cx, unsigned argc, JS::Value *vp) { return true; } -PyObject *JSArrayProxyMethodDefinitions::JSArrayProxy_sort(JSArrayProxy *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { +PyObject *JSArrayProxyMethodDefinitions::JSArrayProxy_sort(JSArrayProxy *self, PyObject *args, PyObject *kwargs) { static const char *const _keywords[] = {"key", "reverse", NULL}; - static _PyArg_Parser _parser = { - .keywords = _keywords, - .fname = "sort", - .kwtuple = NULL, - }; - - PyObject *argsbuf[2]; - Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + PyObject *keyfunc = Py_None; int reverse = 0; - - // args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 0, 0, argsbuf); - Py_RETURN_NONE; - - if (!args) { - return NULL; - } - - if (!noptargs) { - goto skip_optional_kwonly; - } - - if (args[0]) { - keyfunc = args[0]; - if (!--noptargs) { - goto skip_optional_kwonly; - } - } - - reverse = PyObject_IsTrue(args[1]); - if (reverse < 0) { + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|$Op:sort", _keywords, &keyfunc, &reverse)) { return NULL; } -skip_optional_kwonly: if (JSArrayProxy_length(self) > 1) { JS::RootedValue jReturnedArray(GLOBAL_CX); if (keyfunc != Py_None) { From 3706a476dfcf81f8c853fa857ced611362b75502 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Fri, 20 Sep 2024 08:04:33 +0000 Subject: [PATCH 295/428] fix: `_PyArg_UnpackKeywords` API is removed, use `PyArg_ParseTupleAndKeywords` instead --- src/JSArrayProxy.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/JSArrayProxy.cc b/src/JSArrayProxy.cc index d7adc776..89a988e5 100644 --- a/src/JSArrayProxy.cc +++ b/src/JSArrayProxy.cc @@ -1181,7 +1181,7 @@ static bool sort_compare_default(JSContext *cx, unsigned argc, JS::Value *vp) { } PyObject *JSArrayProxyMethodDefinitions::JSArrayProxy_sort(JSArrayProxy *self, PyObject *args, PyObject *kwargs) { - static const char *const _keywords[] = {"key", "reverse", NULL}; + static char *_keywords[] = {"key", "reverse", NULL}; PyObject *keyfunc = Py_None; int reverse = 0; From 92798a8fb337065824f0a840b4d2d24eb786924f Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Fri, 20 Sep 2024 08:20:51 +0000 Subject: [PATCH 296/428] fix: `_PyThreadState_GetDict(tstate)` API gets removed in Python 3.13 --- src/PyEventLoop.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/PyEventLoop.cc b/src/PyEventLoop.cc index 14ed2084..d0815f44 100644 --- a/src/PyEventLoop.cc +++ b/src/PyEventLoop.cc @@ -143,9 +143,13 @@ PyEventLoop PyEventLoop::_getLoopOnThread(PyThreadState *tstate) { #if PY_VERSION_HEX >= 0x030d0000 // Python version is greater than 3.13 // The private `_PyThreadState_GetDict(tstate)` API gets removed in Python 3.13. - // However, the fix below cannot be a perfect replacement since the public `PyThreadState_GetDict()` API can only get from the current thread. + // However, simply replacing it with `PyThreadState_GetDict()` does not work, + // since the public `PyThreadState_GetDict()` API can only get from the current thread. // We need to somehow get the thread dictionary on the main thread instead of the current thread. - PyObject *ts_dict = PyThreadState_GetDict(); + if (tstate == NULL) { + return _loopNotFound(); + } + PyObject *ts_dict = tstate->dict; #elif PY_VERSION_HEX >= 0x03090000 // Python version is greater than 3.9 PyObject *ts_dict = _PyThreadState_GetDict(tstate); // borrowed reference #else // Python 3.8 From ec20bdf79139392049e1dedba37ebbd48638b4c2 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Fri, 20 Sep 2024 08:42:41 +0000 Subject: [PATCH 297/428] fix: replacement for the `_PyThreadState_GetDict(tstate)` API in Python 3.13 --- src/PyEventLoop.cc | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/PyEventLoop.cc b/src/PyEventLoop.cc index d0815f44..7e2f1728 100644 --- a/src/PyEventLoop.cc +++ b/src/PyEventLoop.cc @@ -146,8 +146,15 @@ PyEventLoop PyEventLoop::_getLoopOnThread(PyThreadState *tstate) { // However, simply replacing it with `PyThreadState_GetDict()` does not work, // since the public `PyThreadState_GetDict()` API can only get from the current thread. // We need to somehow get the thread dictionary on the main thread instead of the current thread. - if (tstate == NULL) { - return _loopNotFound(); + if (!tstate->dict) { + // Modified from https://github.com/python/cpython/blob/v3.13.0rc1/Python/pystate.c#L1934-L1951 + tstate->dict = PyDict_New(); + if (tstate->dict == NULL) { // when it's still null, no per-thread state is available, and an exception should not be raised + PyObject *old_exc = tstate->current_exception; + tstate->current_exception = NULL; // _PyErr_Clear(tstate) + Py_XDECREF(old_exc); + return _loopNotFound(); + } } PyObject *ts_dict = tstate->dict; #elif PY_VERSION_HEX >= 0x03090000 // Python version is greater than 3.9 From aea53bd1da9bcef9ce73319b5d1234556430477d Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Fri, 20 Sep 2024 08:55:19 +0000 Subject: [PATCH 298/428] get rid of the build warnings --- src/JSArrayProxy.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/JSArrayProxy.cc b/src/JSArrayProxy.cc index 89a988e5..869e1503 100644 --- a/src/JSArrayProxy.cc +++ b/src/JSArrayProxy.cc @@ -1181,11 +1181,11 @@ static bool sort_compare_default(JSContext *cx, unsigned argc, JS::Value *vp) { } PyObject *JSArrayProxyMethodDefinitions::JSArrayProxy_sort(JSArrayProxy *self, PyObject *args, PyObject *kwargs) { - static char *_keywords[] = {"key", "reverse", NULL}; + static const char *const _keywords[] = {"key", "reverse", NULL}; PyObject *keyfunc = Py_None; int reverse = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|$Op:sort", _keywords, &keyfunc, &reverse)) { + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|$Op:sort", (char **)_keywords, &keyfunc, &reverse)) { return NULL; } From b2fb169588059a5275acfb581e560701568285cf Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Fri, 20 Sep 2024 09:13:03 +0000 Subject: [PATCH 299/428] refactor: `_getLoopOnThread` getting thread dict --- src/PyEventLoop.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/PyEventLoop.cc b/src/PyEventLoop.cc index 7e2f1728..c17cc86c 100644 --- a/src/PyEventLoop.cc +++ b/src/PyEventLoop.cc @@ -141,6 +141,7 @@ PyEventLoop PyEventLoop::_loopNotFound() { PyEventLoop PyEventLoop::_getLoopOnThread(PyThreadState *tstate) { // Modified from Python 3.9 `get_running_loop` https://github.com/python/cpython/blob/7cb3a44/Modules/_asynciomodule.c#L241-L278 + PyObject *ts_dict; #if PY_VERSION_HEX >= 0x030d0000 // Python version is greater than 3.13 // The private `_PyThreadState_GetDict(tstate)` API gets removed in Python 3.13. // However, simply replacing it with `PyThreadState_GetDict()` does not work, @@ -156,11 +157,11 @@ PyEventLoop PyEventLoop::_getLoopOnThread(PyThreadState *tstate) { return _loopNotFound(); } } - PyObject *ts_dict = tstate->dict; + ts_dict = tstate->dict; #elif PY_VERSION_HEX >= 0x03090000 // Python version is greater than 3.9 - PyObject *ts_dict = _PyThreadState_GetDict(tstate); // borrowed reference + ts_dict = _PyThreadState_GetDict(tstate); // borrowed reference #else // Python 3.8 - PyObject *ts_dict = tstate->dict; // see https://github.com/python/cpython/blob/v3.8.17/Modules/_asynciomodule.c#L244-L245 + ts_dict = tstate->dict; // see https://github.com/python/cpython/blob/v3.8.17/Modules/_asynciomodule.c#L244-L245 #endif if (ts_dict == NULL) { return _loopNotFound(); From a5fbef8019b5c586a4e02b8fed12ecf426e8253c Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Fri, 20 Sep 2024 09:29:41 +0000 Subject: [PATCH 300/428] feat: to get the running event-loop in Python 3.13 is as simple as `thread_state->asyncio_running_loop` --- src/PyEventLoop.cc | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/PyEventLoop.cc b/src/PyEventLoop.cc index c17cc86c..3e51eabb 100644 --- a/src/PyEventLoop.cc +++ b/src/PyEventLoop.cc @@ -147,17 +147,26 @@ PyEventLoop PyEventLoop::_getLoopOnThread(PyThreadState *tstate) { // However, simply replacing it with `PyThreadState_GetDict()` does not work, // since the public `PyThreadState_GetDict()` API can only get from the current thread. // We need to somehow get the thread dictionary on the main thread instead of the current thread. - if (!tstate->dict) { - // Modified from https://github.com/python/cpython/blob/v3.13.0rc1/Python/pystate.c#L1934-L1951 - tstate->dict = PyDict_New(); - if (tstate->dict == NULL) { // when it's still null, no per-thread state is available, and an exception should not be raised - PyObject *old_exc = tstate->current_exception; - tstate->current_exception = NULL; // _PyErr_Clear(tstate) - Py_XDECREF(old_exc); + // + // UPDATE: We don't need the thread dictionary anymore. + // To get the thread's running event-loop in Python 3.13 is as simple as `thread_state->asyncio_running_loop` + { + // Every `PyThreadState` is actually allocated with extra fields as a `_PyThreadStateImpl` struct + // See https://github.com/python/cpython/blob/v3.13.0rc1/Include/internal/pycore_tstate.h#L17-L24 + using PyThreadStateHolder = struct { // _PyThreadStateImpl + PyThreadState base; + PyObject *asyncio_running_loop; // we only need the first field of `_PyThreadStateImpl` + }; + + // Modified from https://github.com/python/cpython/blob/v3.13.0rc1/Modules/_asynciomodule.c#L3205-L3210 + PyObject *loop = ((PyThreadStateHolder *)tstate)->asyncio_running_loop; + if (loop == NULL) { return _loopNotFound(); } + + Py_INCREF(loop); + return PyEventLoop(loop); } - ts_dict = tstate->dict; #elif PY_VERSION_HEX >= 0x03090000 // Python version is greater than 3.9 ts_dict = _PyThreadState_GetDict(tstate); // borrowed reference #else // Python 3.8 From 29b6baeb204cb9d93b7a31ce546f72ab6c8b0d38 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Fri, 20 Sep 2024 10:19:45 +0000 Subject: [PATCH 301/428] feat: keep track of the local variables inside Python `eval`/`exec` to a dict Python 3.13 dramatically changed how the namespace in `exec`/`eval` works. See https://docs.python.org/3.13/whatsnew/3.13.html#defined-mutation-semantics-for-locals --- python/pythonmonkey/require.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/python/pythonmonkey/require.py b/python/pythonmonkey/require.py index 39043796..09025c49 100644 --- a/python/pythonmonkey/require.py +++ b/python/pythonmonkey/require.py @@ -82,8 +82,11 @@ globalThis.python.stderr.write = lambda s: sys.stderr.write(s) globalThis.python.stdout.read = lambda n: sys.stdout.read(n) globalThis.python.stderr.read = lambda n: sys.stderr.read(n) -globalThis.python.eval = eval -globalThis.python.exec = exec +# Python 3.13 dramatically changed how the namespace in `exec`/`eval` works +# See https://docs.python.org/3.13/whatsnew/3.13.html#defined-mutation-semantics-for-locals +_locals = {} # keep the local variables inside `eval`/`exec` to a dict +globalThis.python.eval = lambda x: eval(x, None, _locals) +globalThis.python.exec = lambda x: exec(x, None, _locals) globalThis.python.getenv = os.getenv globalThis.python.paths = sys.path From 7f02431815f2f45c8a2c6716898124c47ca8c23f Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Mon, 23 Sep 2024 20:59:25 +0000 Subject: [PATCH 302/428] fix: `_PyArg_CheckPositional` may also be when unpacking a tuple --- include/pyshim.hh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/pyshim.hh b/include/pyshim.hh index a1758064..5d33dd2f 100644 --- a/include/pyshim.hh +++ b/include/pyshim.hh @@ -45,6 +45,10 @@ typedef struct { */ #if PY_VERSION_HEX >= 0x030d0000 // Python version is greater than 3.13 inline int _PyArg_CheckPositional(const char *name, Py_ssize_t nargs, Py_ssize_t min, Py_ssize_t max) { + if (!name) { // _PyArg_CheckPositional may also be when unpacking a tuple + name = "unpacked tuple"; // https://github.com/python/cpython/blob/v3.13.0rc1/Python/getargs.c#L2746 + } + if (nargs < min) { PyErr_Format( PyExc_TypeError, From a2d9ce837cd50cae67f395b214bc2aa88e3d0345 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Mon, 23 Sep 2024 21:05:17 +0000 Subject: [PATCH 303/428] refactor: use the `_PyDictView_New` function in Python < 3.13 --- include/pyshim.hh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/pyshim.hh b/include/pyshim.hh index 5d33dd2f..bc47ce52 100644 --- a/include/pyshim.hh +++ b/include/pyshim.hh @@ -79,6 +79,9 @@ inline int _PyArg_CheckPositional(const char *name, Py_ssize_t nargs, Py_ssize_t * @see Modified from https://github.com/python/cpython/blob/v3.13.0rc1/Objects/dictobject.c#L5806-L5827 */ inline PyObject *PyDictViewObject_new(PyObject *dict, PyTypeObject *type) { +#if PY_VERSION_HEX < 0x030d0000 // Python version is lower than 3.13 + return _PyDictView_New(dict, type); +#else _PyDictViewObject *dv; dv = PyObject_GC_New(_PyDictViewObject, type); if (dv == NULL) @@ -87,6 +90,7 @@ inline PyObject *PyDictViewObject_new(PyObject *dict, PyTypeObject *type) { dv->dv_dict = (PyDictObject *)dict; PyObject_GC_Track(dv); return (PyObject *)dv; +#endif } #endif // #ifndef PythonMonkey_py_version_shim_ From 623d83e7d949da390fa41b982c0e8222e4ad22d0 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Mon, 23 Sep 2024 21:49:22 +0000 Subject: [PATCH 304/428] refactor: keep using `_PyErr_SetKeyError` in Python < 3.13 --- src/JSObjectProxy.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/JSObjectProxy.cc b/src/JSObjectProxy.cc index 9f34436a..b6b6ee7d 100644 --- a/src/JSObjectProxy.cc +++ b/src/JSObjectProxy.cc @@ -702,7 +702,11 @@ PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_pop_method(JSObjectProxy Py_INCREF(default_value); return default_value; } + #if PY_VERSION_HEX >= 0x030d0000 // Python version is greater than 3.13 PyErr_SetObject(PyExc_KeyError, key); + #else + _PyErr_SetKeyError(key); + #endif return NULL; } else { From a1cdfb3cd778b06ea127e126a3f6f0720fc256f3 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Mon, 23 Sep 2024 22:38:35 +0000 Subject: [PATCH 305/428] refactor: move `_PyErr_SetKeyError` shim to pyshim.hh `_PyErr_SetKeyError` is more complex than originally thought, use the provided API when possible See also https://github.com/python/cpython/issues/101578 --- include/pyshim.hh | 14 ++++++++++++++ src/JSObjectProxy.cc | 6 +----- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/include/pyshim.hh b/include/pyshim.hh index bc47ce52..48151f23 100644 --- a/include/pyshim.hh +++ b/include/pyshim.hh @@ -93,4 +93,18 @@ inline PyObject *PyDictViewObject_new(PyObject *dict, PyTypeObject *type) { #endif } +/** + * @brief Shim for `_PyErr_SetKeyError`. + * Since Python 3.13, `_PyErr_SetKeyError` function became an internal API. + */ +inline void PyErr_SetKeyError(PyObject *key) { + // Use the provided API when possible, as `PyErr_SetObject`'s behaviour is more complex than originally thought + // see also: https://github.com/python/cpython/issues/101578 +#if PY_VERSION_HEX < 0x030d0000 // Python version is lower than 3.13 + return _PyErr_SetKeyError(key); +#else + return PyErr_SetObject(PyExc_KeyError, key); +#endif +} + #endif // #ifndef PythonMonkey_py_version_shim_ diff --git a/src/JSObjectProxy.cc b/src/JSObjectProxy.cc index b6b6ee7d..4ae14af0 100644 --- a/src/JSObjectProxy.cc +++ b/src/JSObjectProxy.cc @@ -702,11 +702,7 @@ PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_pop_method(JSObjectProxy Py_INCREF(default_value); return default_value; } - #if PY_VERSION_HEX >= 0x030d0000 // Python version is greater than 3.13 - PyErr_SetObject(PyExc_KeyError, key); - #else - _PyErr_SetKeyError(key); - #endif + PyErr_SetKeyError(key); return NULL; } else { From 7ea7a4c66fc49488b4b030eb320cd5b127cb3a6c Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 24 Sep 2024 05:42:36 +0000 Subject: [PATCH 306/428] fix: `Py_XDECREF` requires the GIL to be held, but it's unavailable after Python finalization --- src/modules/pythonmonkey/pythonmonkey.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/modules/pythonmonkey/pythonmonkey.cc b/src/modules/pythonmonkey/pythonmonkey.cc index 597f937b..992a0439 100644 --- a/src/modules/pythonmonkey/pythonmonkey.cc +++ b/src/modules/pythonmonkey/pythonmonkey.cc @@ -303,8 +303,6 @@ PyTypeObject JSObjectItemsProxyType = { }; static void cleanup() { - Py_XDECREF(PythonMonkey_Null); - Py_XDECREF(PythonMonkey_BigInt); delete autoRealm; delete global; if (GLOBAL_CX) JS_DestroyContext(GLOBAL_CX); From 345369637dca9c9e0768c7a669647f7d781a8350 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 24 Sep 2024 07:10:32 +0000 Subject: [PATCH 307/428] fix: accessing a non-existent property on a Python `bytes` in JS land should return `undefined` instead of throwing a Python error --- src/PyBytesProxyHandler.cc | 3 +++ src/PyDictProxyHandler.cc | 2 +- src/PyIterableProxyHandler.cc | 13 ++++++++----- src/PyObjectProxyHandler.cc | 4 ++-- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/PyBytesProxyHandler.cc b/src/PyBytesProxyHandler.cc index 525b0068..304c37c9 100644 --- a/src/PyBytesProxyHandler.cc +++ b/src/PyBytesProxyHandler.cc @@ -415,6 +415,9 @@ bool PyBytesProxyHandler::getOwnPropertyDescriptor( PyObject *attrName = idToKey(cx, id); PyObject *self = JS::GetMaybePtrFromReservedSlot(proxy, PyObjectSlot); PyObject *item = PyObject_GetAttr(self, attrName); + if (!item && PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyErr_Clear(); // clear error, we will be returning undefined in this case + } return handleGetOwnPropertyDescriptor(cx, id, desc, item); } diff --git a/src/PyDictProxyHandler.cc b/src/PyDictProxyHandler.cc index 72d2decf..4295d2c4 100644 --- a/src/PyDictProxyHandler.cc +++ b/src/PyDictProxyHandler.cc @@ -56,7 +56,7 @@ bool PyDictProxyHandler::getOwnPropertyDescriptor( ) const { PyObject *attrName = idToKey(cx, id); PyObject *self = JS::GetMaybePtrFromReservedSlot(proxy, PyObjectSlot); - PyObject *item = PyDict_GetItemWithError(self, attrName); + PyObject *item = PyDict_GetItemWithError(self, attrName); // returns NULL without an exception set if the key wasn’t present. return handleGetOwnPropertyDescriptor(cx, id, desc, item); } diff --git a/src/PyIterableProxyHandler.cc b/src/PyIterableProxyHandler.cc index 5de9ec3a..0a95603f 100644 --- a/src/PyIterableProxyHandler.cc +++ b/src/PyIterableProxyHandler.cc @@ -79,7 +79,7 @@ static bool toPrimitive(JSContext *cx, unsigned argc, JS::Value *vp) { _PyUnicodeWriter writer; _PyUnicodeWriter_Init(&writer); - + PyObject *s = PyObject_Repr(self); if (s == nullptr) { @@ -95,8 +95,8 @@ static bool toPrimitive(JSContext *cx, unsigned argc, JS::Value *vp) { return true; } - PyObject* repr = _PyUnicodeWriter_Finish(&writer); - + PyObject *repr = _PyUnicodeWriter_Finish(&writer); + args.rval().set(jsTypeFactory(cx, repr)); return true; } @@ -262,7 +262,7 @@ bool PyIterableProxyHandler::getOwnPropertyDescriptor( // symbol property if (id.isSymbol()) { JS::RootedSymbol rootedSymbol(cx, id.toSymbol()); - JS::SymbolCode symbolCode = JS::GetSymbolCode(rootedSymbol); + JS::SymbolCode symbolCode = JS::GetSymbolCode(rootedSymbol); if (symbolCode == JS::SymbolCode::iterator) { JSFunction *newFunction = JS_NewFunction(cx, iterable_values, 0, 0, NULL); @@ -275,7 +275,7 @@ bool PyIterableProxyHandler::getOwnPropertyDescriptor( ) )); return true; - } + } else if (symbolCode == JS::SymbolCode::toPrimitive) { JSFunction *newFunction = JS_NewFunction(cx, toPrimitive, 0, 0, nullptr); if (!newFunction) return false; @@ -293,6 +293,9 @@ bool PyIterableProxyHandler::getOwnPropertyDescriptor( PyObject *attrName = idToKey(cx, id); PyObject *self = JS::GetMaybePtrFromReservedSlot(proxy, PyObjectSlot); PyObject *item = PyObject_GetAttr(self, attrName); + if (!item && PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyErr_Clear(); // clear error, we will be returning undefined in this case + } return handleGetOwnPropertyDescriptor(cx, id, desc, item); } \ No newline at end of file diff --git a/src/PyObjectProxyHandler.cc b/src/PyObjectProxyHandler.cc index 7f5e4b70..0671774c 100644 --- a/src/PyObjectProxyHandler.cc +++ b/src/PyObjectProxyHandler.cc @@ -143,8 +143,8 @@ bool PyObjectProxyHandler::getOwnPropertyDescriptor( PyObject *attrName = idToKey(cx, id); PyObject *self = JS::GetMaybePtrFromReservedSlot(proxy, PyObjectSlot); PyObject *item = PyObject_GetAttr(self, attrName); - if (!item) { // clear error, we will be returning undefined in this case - PyErr_Clear(); + if (!item && PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyErr_Clear(); // clear error, we will be returning undefined in this case } return handleGetOwnPropertyDescriptor(cx, id, desc, item); From dd0aaed14450ddae7044a1d29c393b8b11b32d70 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 24 Sep 2024 07:55:02 +0000 Subject: [PATCH 308/428] fix: clean up SpiderMonkey when the PythonMonkey module gets destroyed We cannot use `Py_AtExit(cleanup);` because the GIL is unavailable after Python finalization, no more Python APIs can be called. --- src/modules/pythonmonkey/pythonmonkey.cc | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/modules/pythonmonkey/pythonmonkey.cc b/src/modules/pythonmonkey/pythonmonkey.cc index 992a0439..a9645a27 100644 --- a/src/modules/pythonmonkey/pythonmonkey.cc +++ b/src/modules/pythonmonkey/pythonmonkey.cc @@ -303,12 +303,20 @@ PyTypeObject JSObjectItemsProxyType = { }; static void cleanup() { + // Clean up the PythonMonkey module + Py_XDECREF(PythonMonkey_Null); + Py_XDECREF(PythonMonkey_BigInt); + + // Clean up SpiderMonkey delete autoRealm; delete global; if (GLOBAL_CX) JS_DestroyContext(GLOBAL_CX); delete JOB_QUEUE; JS_ShutDown(); } +static void cleanup(PyObject *) { + cleanup(); +} static PyObject *collect(PyObject *self, PyObject *args) { JS_GC(GLOBAL_CX); @@ -550,7 +558,6 @@ PyMODINIT_FUNC PyInit_pythonmonkey(void) PyErr_SetString(SpiderMonkeyError, "Spidermonkey could not be initialized."); return NULL; } - Py_AtExit(cleanup); GLOBAL_CX = JS_NewContext(JS::DefaultHeapMaxBytes); if (!GLOBAL_CX) { @@ -643,6 +650,16 @@ PyMODINIT_FUNC PyInit_pythonmonkey(void) if (pyModule == NULL) return NULL; + // Clean up SpiderMonkey when the PythonMonkey module gets destroyed (module.___cleanup is GCed) + // The `cleanup` function will be called automatically when this PyCapsule gets GCed + // We cannot use `Py_AtExit(cleanup);` because the GIL is unavailable after Python finalization, no more Python APIs can be called. + PyObject *autoDestructor = PyCapsule_New(&pythonmonkey, NULL, cleanup); + if (PyModule_AddObject(pyModule, "___cleanup", autoDestructor) < 0) { + Py_DECREF(autoDestructor); + Py_DECREF(pyModule); + return NULL; + } + Py_INCREF(&NullType); if (PyModule_AddObject(pyModule, "null", (PyObject *)&NullType) < 0) { Py_DECREF(&NullType); From a0e3b0599496b5173145fbb868c7d1a2b7628803 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 24 Sep 2024 09:24:18 +0000 Subject: [PATCH 309/428] fix: to fix memory corruption, use `PyUnicode_AsUTF8AndSize` with the string size when possible --- src/JSObjectProxy.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/JSObjectProxy.cc b/src/JSObjectProxy.cc index 4ae14af0..de2f933c 100644 --- a/src/JSObjectProxy.cc +++ b/src/JSObjectProxy.cc @@ -36,9 +36,10 @@ JSContext *GLOBAL_CX; /**< pointer to PythonMonkey's JSContext */ bool keyToId(PyObject *key, JS::MutableHandleId idp) { if (PyUnicode_Check(key)) { // key is str type JS::RootedString idString(GLOBAL_CX); - const char *keyStr = PyUnicode_AsUTF8(key); - JS::ConstUTF8CharsZ utf8Chars(keyStr, strlen(keyStr)); - idString.set(JS_NewStringCopyUTF8Z(GLOBAL_CX, utf8Chars)); + Py_ssize_t length; + const char *keyStr = PyUnicode_AsUTF8AndSize(key, &length); + JS::UTF8Chars utf8Chars(keyStr, length); + idString.set(JS_NewStringCopyUTF8N(GLOBAL_CX, utf8Chars)); return JS_StringToId(GLOBAL_CX, idString, idp); } else if (PyLong_Check(key)) { // key is int type uint32_t keyAsInt = PyLong_AsUnsignedLong(key); // TODO raise OverflowError if the value of pylong is out of range for a unsigned long From 667abc301db9f7c5e28e65511cea2f5cf812134e Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 24 Sep 2024 10:15:12 +0000 Subject: [PATCH 310/428] fix: `PyUnicode_AsUTF8` needs a strict Python str object (not a subtype) --- src/modules/pythonmonkey/pythonmonkey.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/modules/pythonmonkey/pythonmonkey.cc b/src/modules/pythonmonkey/pythonmonkey.cc index a9645a27..5d8c424b 100644 --- a/src/modules/pythonmonkey/pythonmonkey.cc +++ b/src/modules/pythonmonkey/pythonmonkey.cc @@ -331,7 +331,7 @@ static bool getEvalOption(PyObject *evalOptions, const char *optionName, const c value = PyDict_GetItemString(evalOptions, optionName); } if (value && value != Py_None) { - *s_p = PyUnicode_AsUTF8(value); + *s_p = PyUnicode_AsUTF8(PyUnicode_FromObject(value)); } return value != NULL && value != Py_None; } @@ -449,7 +449,8 @@ static PyObject *eval(PyObject *self, PyObject *args) { #endif if (!getEvalOption(evalOptions, "filename", &s)) { if (filename && PyUnicode_Check(filename)) { - options.setFile(PyUnicode_AsUTF8(filename)); + PyObject *filenameStr = PyUnicode_FromObject(filename); // needs a strict Python str object (not a subtype) + options.setFile(PyUnicode_AsUTF8(filenameStr)); } } /* filename */ } /* fromPythonFrame */ From c804ca920512a9f9f5a7d6c3efc36d26a91df47e Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 24 Sep 2024 10:17:12 +0000 Subject: [PATCH 311/428] fix: to fix memory corruption, use `PyUnicode_AsUTF8AndSize` with the string size when possible --- src/modules/pythonmonkey/pythonmonkey.cc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/modules/pythonmonkey/pythonmonkey.cc b/src/modules/pythonmonkey/pythonmonkey.cc index 5d8c424b..b0cfb09a 100644 --- a/src/modules/pythonmonkey/pythonmonkey.cc +++ b/src/modules/pythonmonkey/pythonmonkey.cc @@ -461,8 +461,9 @@ static PyObject *eval(PyObject *self, PyObject *args) { JS::Rooted rval(GLOBAL_CX); if (code) { JS::SourceText source; - const char *codeChars = PyUnicode_AsUTF8(code); - if (!source.init(GLOBAL_CX, codeChars, strlen(codeChars), JS::SourceOwnership::Borrowed)) { + Py_ssize_t codeLength; + const char *codeChars = PyUnicode_AsUTF8AndSize(code, &codeLength); + if (!source.init(GLOBAL_CX, codeChars, codeLength, JS::SourceOwnership::Borrowed)) { setSpiderMonkeyException(GLOBAL_CX); return NULL; } @@ -521,9 +522,10 @@ static PyObject *isCompilableUnit(PyObject *self, PyObject *args) { return NULL; } - const char *bufferUtf8 = PyUnicode_AsUTF8(item); + Py_ssize_t bufferLength; + const char *bufferUtf8 = PyUnicode_AsUTF8AndSize(item, &bufferLength); - if (JS_Utf8BufferIsCompilableUnit(GLOBAL_CX, *global, bufferUtf8, strlen(bufferUtf8))) { + if (JS_Utf8BufferIsCompilableUnit(GLOBAL_CX, *global, bufferUtf8, bufferLength)) { Py_RETURN_TRUE; } else { Py_RETURN_FALSE; From 7c7427410280d6124a965e9dd4fc12b807e1e70f Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 24 Sep 2024 10:30:19 +0000 Subject: [PATCH 312/428] fix: `PyEventLoop`'s destructor should not use any Python API, after the GIL is already handed over to another thread --- src/JobQueue.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/JobQueue.cc b/src/JobQueue.cc index 0ee33b39..6dcb548f 100644 --- a/src/JobQueue.cc +++ b/src/JobQueue.cc @@ -121,6 +121,7 @@ bool sendJobToMainLoop(PyObject *pyFunc) { } loop.enqueue(pyFunc); + loop._loop = nullptr; // the `Py_XDECREF` Python API call in `PyEventLoop`'s destructor will not be accessible once we hand over the GIL by `PyGILState_Release` PyGILState_Release(gstate); return true; } From 73957c02ef459ca28739059c3847bbc698998283 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 24 Sep 2024 10:43:12 +0000 Subject: [PATCH 313/428] fix: `PyUnicodeObject` needs to be well-formed in a debug build of CPython Otherwise a `_PyObject_AssertFailed` error will be raised See: `_PyUnicode_CheckConsistency` https://github.com/python/cpython/blob/v3.11.3/Objects/unicodeobject.c#L594-L600, #L552-L553 --- src/StrType.cc | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/StrType.cc b/src/StrType.cc index 714bed7d..c849072e 100644 --- a/src/StrType.cc +++ b/src/StrType.cc @@ -53,6 +53,16 @@ static bool containsSurrogatePair(const char16_t *chars, size_t length) { return false; } +/** + * @brief check if the Latin-1 encoded `chars` only contain ascii characters + */ +static bool containsOnlyAscii(const JS::Latin1Char *chars, size_t length) { + for (size_t i = 0; i < length; i++) { + if (chars[i] >= 128) return false; + } + return true; +} + /** * @brief creates new UCS4-encoded pyObject string. This must be called by the user if the original JSString contains any surrogate pairs * @@ -134,6 +144,16 @@ PyObject *StrType::proxifyString(JSContext *cx, JS::HandleValue strVal) { PY_UNICODE_OBJECT_WSTR_LENGTH(pyString) = 0; PY_UNICODE_OBJECT_READY(pyString) = 1; #endif + + #ifdef Py_DEBUG + // In a debug build of CPython, it needs to be a well-formed PyUnicodeObject, otherwise a `_PyObject_AssertFailed` error will be raised. + // See: `_PyUnicode_CheckConsistency` https://github.com/python/cpython/blob/v3.11.3/Objects/unicodeobject.c#L594-L600, #L552-L553 + if (containsOnlyAscii(chars, length)) { + PY_UNICODE_OBJECT_STATE(pyString).ascii = 1; + PY_UNICODE_OBJECT_UTF8(pyString) = (char *)chars; // XXX: most APIs (e.g. PyUnicode_AsUTF8) assume this is a \0 terminated string + PY_UNICODE_OBJECT_UTF8_LENGTH(pyString) = length; + } + #endif } else { // utf16 spidermonkey, ucs2 python const char16_t *chars = JS::GetTwoByteLinearStringChars(nogc, lstr); @@ -195,7 +215,7 @@ PyObject *StrType::getPyObject(JSContext *cx, JS::HandleValue str) { const char *StrType::getValue(JSContext *cx, JS::HandleValue str) { PyObject *pyString = proxifyString(cx, str); - const char *value = PyUnicode_AsUTF8(pyString); + const char *value = PyUnicode_AsUTF8(PyUnicode_FromObject(pyString)); Py_DECREF(pyString); return value; } \ No newline at end of file From 5a1390147ceeec00f1052dcd7377318fd4b35c95 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 24 Sep 2024 10:45:25 +0000 Subject: [PATCH 314/428] fix: the code argument to `python.exec`/`eval` needs to be a well-formed string --- python/pythonmonkey/require.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/pythonmonkey/require.py b/python/pythonmonkey/require.py index 09025c49..0326669a 100644 --- a/python/pythonmonkey/require.py +++ b/python/pythonmonkey/require.py @@ -85,8 +85,8 @@ # Python 3.13 dramatically changed how the namespace in `exec`/`eval` works # See https://docs.python.org/3.13/whatsnew/3.13.html#defined-mutation-semantics-for-locals _locals = {} # keep the local variables inside `eval`/`exec` to a dict -globalThis.python.eval = lambda x: eval(x, None, _locals) -globalThis.python.exec = lambda x: exec(x, None, _locals) +globalThis.python.eval = lambda x: eval(str(x)[:], None, _locals) +globalThis.python.exec = lambda x: exec(str(x)[:], None, _locals) globalThis.python.getenv = os.getenv globalThis.python.paths = sys.path From 8e365a7f503977845a9e020e5f7ac922139f0d6e Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 24 Sep 2024 10:58:00 +0000 Subject: [PATCH 315/428] refactor: replace the use of our own roundtrip `StrType::getValue` method with the simpler `JS_EncodeStringToUTF8` SpiderMonkey API --- include/StrType.hh | 2 -- src/ExceptionType.cc | 4 ++-- src/StrType.cc | 7 ------- src/setSpiderMonkeyException.cc | 4 ++-- 4 files changed, 4 insertions(+), 13 deletions(-) diff --git a/include/StrType.hh b/include/StrType.hh index 5e1954c1..d8199bc4 100644 --- a/include/StrType.hh +++ b/include/StrType.hh @@ -36,8 +36,6 @@ public: */ static PyObject *getPyObject(JSContext *cx, JS::HandleValue str); - static const char *getValue(JSContext *cx, JS::HandleValue str); - static PyObject *proxifyString(JSContext *cx, JS::HandleValue str); }; diff --git a/src/ExceptionType.cc b/src/ExceptionType.cc index 46b3743c..e2d69691 100644 --- a/src/ExceptionType.cc +++ b/src/ExceptionType.cc @@ -107,8 +107,8 @@ JSObject *ExceptionType::toJsError(JSContext *cx, PyObject *exceptionValue, PyOb if (stackObj.get()) { JS::RootedString stackStr(cx); JS::BuildStackString(cx, nullptr, stackObj, &stackStr, 2, js::StackFormat::SpiderMonkey); - JS::RootedValue stackStrVal(cx, JS::StringValue(stackStr)); - stackStream << "\nJS Stack Trace:\n" << StrType::getValue(cx, stackStrVal); + JS::UniqueChars stackStrUtf8 = JS_EncodeStringToUTF8(cx, stackStr); + stackStream << "\nJS Stack Trace:\n" << stackStrUtf8.get(); } diff --git a/src/StrType.cc b/src/StrType.cc index c849072e..7df301bd 100644 --- a/src/StrType.cc +++ b/src/StrType.cc @@ -212,10 +212,3 @@ PyObject *StrType::getPyObject(JSContext *cx, JS::HandleValue str) { return proxifyString(cx, str); } - -const char *StrType::getValue(JSContext *cx, JS::HandleValue str) { - PyObject *pyString = proxifyString(cx, str); - const char *value = PyUnicode_AsUTF8(PyUnicode_FromObject(pyString)); - Py_DECREF(pyString); - return value; -} \ No newline at end of file diff --git a/src/setSpiderMonkeyException.cc b/src/setSpiderMonkeyException.cc index d380d87c..6d9d10fa 100644 --- a/src/setSpiderMonkeyException.cc +++ b/src/setSpiderMonkeyException.cc @@ -66,8 +66,8 @@ PyObject *getExceptionString(JSContext *cx, const JS::ExceptionStack &exceptionS if (stackObj.get()) { JS::RootedString stackStr(cx); BuildStackString(cx, nullptr, stackObj, &stackStr, 2, js::StackFormat::SpiderMonkey); - JS::RootedValue stackStrVal(cx, JS::StringValue(stackStr)); - outStrStream << "Stack Trace:\n" << StrType::getValue(cx, stackStrVal); + JS::UniqueChars stackStrUtf8 = JS_EncodeStringToUTF8(cx, stackStr); + outStrStream << "Stack Trace:\n" << stackStrUtf8.get(); } } From 0eeda3535ad96a38e60191be0bbf3c0d9a4ca790 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 24 Sep 2024 11:20:13 +0000 Subject: [PATCH 316/428] fix: properly handle the reference count when doing `list.concat()` `PyList_SetItem` steals the reference, so we must increase the reference count by 1 --- src/PyListProxyHandler.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/PyListProxyHandler.cc b/src/PyListProxyHandler.cc index f03fb67d..e6f17f7f 100644 --- a/src/PyListProxyHandler.cc +++ b/src/PyListProxyHandler.cc @@ -553,8 +553,11 @@ static bool array_concat(JSContext *cx, unsigned argc, JS::Value *vp) { PyObject *result = PyList_New(selfSize); + // Copy items to the new list for (Py_ssize_t index = 0; index < selfSize; index++) { - PyList_SetItem(result, index, PyList_GetItem(self, index)); + PyObject *item = PyList_GetItem(self, index); + Py_INCREF(item); // `PyList_SetItem` steals the reference, so we must increase the reference count by 1 + PyList_SetItem(result, index, item); } unsigned numArgs = args.length(); From c63b60902d18c59232292ab2c49910ce2dbb7ce2 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 24 Sep 2024 11:28:36 +0000 Subject: [PATCH 317/428] perf: simply do a pythonic `result = list[:]` to get a copy of all items to the new list --- src/PyListProxyHandler.cc | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/PyListProxyHandler.cc b/src/PyListProxyHandler.cc index e6f17f7f..4a5cd9dc 100644 --- a/src/PyListProxyHandler.cc +++ b/src/PyListProxyHandler.cc @@ -550,15 +550,7 @@ static bool array_concat(JSContext *cx, unsigned argc, JS::Value *vp) { PyObject *self = JS::GetMaybePtrFromReservedSlot(proxy, PyObjectSlot); Py_ssize_t selfSize = PyList_GET_SIZE(self); - - PyObject *result = PyList_New(selfSize); - - // Copy items to the new list - for (Py_ssize_t index = 0; index < selfSize; index++) { - PyObject *item = PyList_GetItem(self, index); - Py_INCREF(item); // `PyList_SetItem` steals the reference, so we must increase the reference count by 1 - PyList_SetItem(result, index, item); - } + PyObject *result = PyList_GetSlice(self, 0, selfSize); unsigned numArgs = args.length(); JS::RootedValue elementVal(cx); From 9474990cf8c993d804647a69dde230802c453628 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 24 Sep 2024 11:37:00 +0000 Subject: [PATCH 318/428] fix the reference count WIP: I don't know exactly why... --- src/PyListProxyHandler.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/PyListProxyHandler.cc b/src/PyListProxyHandler.cc index 4a5cd9dc..33cb619b 100644 --- a/src/PyListProxyHandler.cc +++ b/src/PyListProxyHandler.cc @@ -436,8 +436,9 @@ static bool array_fill(JSContext *cx, unsigned argc, JS::Value *vp) { } } - if (!setItemCalled) { - Py_DECREF(fillValueItem); + Py_INCREF(fillValueItem); + if (setItemCalled) { + Py_INCREF(fillValueItem); } // return ref to self From 56b6409787ed83756c5c429b40546cce306718df Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 25 Sep 2024 17:41:25 +0000 Subject: [PATCH 319/428] refactor: rename the `PyDictViewObject_new` shim to `PyDictView_New` --- include/pyshim.hh | 2 +- src/JSObjectProxy.cc | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/pyshim.hh b/include/pyshim.hh index 48151f23..05c9e482 100644 --- a/include/pyshim.hh +++ b/include/pyshim.hh @@ -78,7 +78,7 @@ inline int _PyArg_CheckPositional(const char *name, Py_ssize_t nargs, Py_ssize_t * Since Python 3.13, `_PyDictView_New` function became an internal API. * @see Modified from https://github.com/python/cpython/blob/v3.13.0rc1/Objects/dictobject.c#L5806-L5827 */ -inline PyObject *PyDictViewObject_new(PyObject *dict, PyTypeObject *type) { +inline PyObject *PyDictView_New(PyObject *dict, PyTypeObject *type) { #if PY_VERSION_HEX < 0x030d0000 // Python version is lower than 3.13 return _PyDictView_New(dict, type); #else diff --git a/src/JSObjectProxy.cc b/src/JSObjectProxy.cc index 4ae14af0..eff28ee4 100644 --- a/src/JSObjectProxy.cc +++ b/src/JSObjectProxy.cc @@ -781,13 +781,13 @@ PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_update_method(JSObjectPr } PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_keys_method(JSObjectProxy *self) { - return PyDictViewObject_new((PyObject *)self, &JSObjectKeysProxyType); + return PyDictView_New((PyObject *)self, &JSObjectKeysProxyType); } PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_values_method(JSObjectProxy *self) { - return PyDictViewObject_new((PyObject *)self, &JSObjectValuesProxyType); + return PyDictView_New((PyObject *)self, &JSObjectValuesProxyType); } PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_items_method(JSObjectProxy *self) { - return PyDictViewObject_new((PyObject *)self, &JSObjectItemsProxyType); + return PyDictView_New((PyObject *)self, &JSObjectItemsProxyType); } \ No newline at end of file From 3f7f72296c89097a4649f63922310b4281e19482 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 25 Sep 2024 17:53:08 +0000 Subject: [PATCH 320/428] refactor: add shim for `Py_SET_SIZE` --- include/pyshim.hh | 11 +++++++++++ src/IntType.cc | 4 ---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/include/pyshim.hh b/include/pyshim.hh index 05c9e482..d9dfe72c 100644 --- a/include/pyshim.hh +++ b/include/pyshim.hh @@ -107,4 +107,15 @@ inline void PyErr_SetKeyError(PyObject *key) { #endif } +/** + * @brief Shim for `Py_SET_SIZE`. + * `Py_SET_SIZE` is not available in Python < 3.9 + */ +#ifndef Py_SET_SIZE +static inline void _Py_SET_SIZE(PyVarObject *ob, Py_ssize_t size) { + ob->ob_size = size; +} +#define Py_SET_SIZE(ob, size) _Py_SET_SIZE((PyVarObject *)(ob), size) +#endif + #endif // #ifndef PythonMonkey_py_version_shim_ diff --git a/src/IntType.cc b/src/IntType.cc index 30e974bf..c2d2494b 100644 --- a/src/IntType.cc +++ b/src/IntType.cc @@ -44,11 +44,7 @@ static inline void PythonLong_SetSign(PyLongObject *op, int sign) { #else // Python version is less than 3.12 // see https://github.com/python/cpython/blob/v3.9.16/Objects/longobject.c#L956 Py_ssize_t pyDigitCount = Py_SIZE(op); - #if PY_VERSION_HEX >= 0x03090000 Py_SET_SIZE(op, sign * std::abs(pyDigitCount)); - #else - ((PyVarObject *)op)->ob_size = sign * std::abs(pyDigitCount); // Py_SET_SIZE is not available in Python < 3.9 - #endif #endif } From bcfcbf35ce5ae10bb3542052cdccadf48e95cdca Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 1 Oct 2024 16:52:18 +0000 Subject: [PATCH 321/428] refactor: add shim for `PyObject_CallOneArg` --- include/pyshim.hh | 10 ++++++++++ src/ExceptionType.cc | 6 ++---- src/IntType.cc | 7 +++---- src/PromiseType.cc | 7 +++---- 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/include/pyshim.hh b/include/pyshim.hh index d9dfe72c..ffba8ccc 100644 --- a/include/pyshim.hh +++ b/include/pyshim.hh @@ -118,4 +118,14 @@ static inline void _Py_SET_SIZE(PyVarObject *ob, Py_ssize_t size) { #define Py_SET_SIZE(ob, size) _Py_SET_SIZE((PyVarObject *)(ob), size) #endif +/** + * @brief Shim for `PyObject_CallOneArg`. + * `PyObject_CallOneArg` is not available in Python < 3.9 + */ +#if PY_VERSION_HEX < 0x03090000 // Python version is less than 3.9 +inline PyObject *PyObject_CallOneArg(PyObject *func, PyObject *arg) { + return PyObject_CallFunction(func, "O", arg); +} +#endif + #endif // #ifndef PythonMonkey_py_version_shim_ diff --git a/src/ExceptionType.cc b/src/ExceptionType.cc index 46b3743c..053f18e1 100644 --- a/src/ExceptionType.cc +++ b/src/ExceptionType.cc @@ -19,7 +19,9 @@ #include #include +#include #include +#include "include/pyshim.hh" PyObject *ExceptionType::getPyObject(JSContext *cx, JS::HandleObject error) { @@ -29,11 +31,7 @@ PyObject *ExceptionType::getPyObject(JSContext *cx, JS::HandleObject error) { PyObject *errStr = getExceptionString(cx, JS::ExceptionStack(cx, errValue, errStack), true); // Construct a new SpiderMonkeyError python object - #if PY_VERSION_HEX >= 0x03090000 PyObject *pyObject = PyObject_CallOneArg(SpiderMonkeyError, errStr); // _PyErr_CreateException, https://github.com/python/cpython/blob/3.9/Python/errors.c#L100 - #else - PyObject *pyObject = PyObject_CallFunction(SpiderMonkeyError, "O", errStr); // PyObject_CallOneArg is not available in Python < 3.9 - #endif Py_XDECREF(errStr); // Preserve the original JS Error object as the Python Exception's `jsError` attribute for lossless two-way conversion diff --git a/src/IntType.cc b/src/IntType.cc index c2d2494b..4d7f2cd2 100644 --- a/src/IntType.cc +++ b/src/IntType.cc @@ -14,6 +14,9 @@ #include #include +#include +#include "include/pyshim.hh" + #include #define SIGN_BIT_MASK 0b1000 // https://hg.mozilla.org/releases/mozilla-esr102/file/tip/js/src/vm/BigIntType.h#l40 @@ -98,11 +101,7 @@ PyObject *IntType::getPyObject(JSContext *cx, JS::BigInt *bigint) { // Cast to a pythonmonkey.bigint to differentiate it from a normal Python int, // allowing Py<->JS two-way BigInt conversion. // We don't do `Py_SET_TYPE` because `_PyLong_FromByteArray` may cache and reuse objects for small ints - #if PY_VERSION_HEX >= 0x03090000 PyObject *pyObject = PyObject_CallOneArg(getPythonMonkeyBigInt(), pyIntObj); // pyObject = pythonmonkey.bigint(pyIntObj) - #else - PyObject *pyObject = PyObject_CallFunction(getPythonMonkeyBigInt(), "O", pyIntObj); // PyObject_CallOneArg is not available in Python < 3.9 - #endif Py_DECREF(pyIntObj); // Set the sign bit diff --git a/src/PromiseType.cc b/src/PromiseType.cc index 4983e8db..5a3f94b3 100644 --- a/src/PromiseType.cc +++ b/src/PromiseType.cc @@ -19,6 +19,9 @@ #include #include +#include +#include "include/pyshim.hh" + // slot ids to access the python object in JS callbacks #define PY_FUTURE_OBJ_SLOT 0 #define PROMISE_OBJ_SLOT 1 @@ -38,11 +41,7 @@ static bool onResolvedCb(JSContext *cx, unsigned argc, JS::Value *vp) { if (state == JS::PromiseState::Rejected && !PyExceptionInstance_Check(result)) { // Wrap the result object into a SpiderMonkeyError object // because only *Exception objects can be thrown in Python `raise` statement and alike - #if PY_VERSION_HEX >= 0x03090000 PyObject *wrapped = PyObject_CallOneArg(SpiderMonkeyError, result); // wrapped = SpiderMonkeyError(result) - #else - PyObject *wrapped = PyObject_CallFunction(SpiderMonkeyError, "O", result); // PyObject_CallOneArg is not available in Python < 3.9 - #endif // Preserve the original JS value as the `jsError` attribute for lossless conversion back PyObject *originalJsErrCapsule = DictType::getPyObject(cx, resultArg); PyObject_SetAttrString(wrapped, "jsError", originalJsErrCapsule); From 68c288eadaf6fe37f62b09b2107e2363eedc46b1 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 1 Oct 2024 17:18:36 +0000 Subject: [PATCH 322/428] refactor: `_PyObject_CallOneArg` is already an alias for `PyObject_CallOneArg` in all Python versions we support, so no need to do a shim on our own This commit reverts `bcfcbf35ce5ae10bb3542052cdccadf48e95cdca` --- include/pyshim.hh | 10 ---------- src/ExceptionType.cc | 3 +-- src/IntType.cc | 3 +-- src/PromiseType.cc | 3 +-- 4 files changed, 3 insertions(+), 16 deletions(-) diff --git a/include/pyshim.hh b/include/pyshim.hh index ffba8ccc..d9dfe72c 100644 --- a/include/pyshim.hh +++ b/include/pyshim.hh @@ -118,14 +118,4 @@ static inline void _Py_SET_SIZE(PyVarObject *ob, Py_ssize_t size) { #define Py_SET_SIZE(ob, size) _Py_SET_SIZE((PyVarObject *)(ob), size) #endif -/** - * @brief Shim for `PyObject_CallOneArg`. - * `PyObject_CallOneArg` is not available in Python < 3.9 - */ -#if PY_VERSION_HEX < 0x03090000 // Python version is less than 3.9 -inline PyObject *PyObject_CallOneArg(PyObject *func, PyObject *arg) { - return PyObject_CallFunction(func, "O", arg); -} -#endif - #endif // #ifndef PythonMonkey_py_version_shim_ diff --git a/src/ExceptionType.cc b/src/ExceptionType.cc index 053f18e1..4e3f96d8 100644 --- a/src/ExceptionType.cc +++ b/src/ExceptionType.cc @@ -21,7 +21,6 @@ #include #include -#include "include/pyshim.hh" PyObject *ExceptionType::getPyObject(JSContext *cx, JS::HandleObject error) { @@ -31,7 +30,7 @@ PyObject *ExceptionType::getPyObject(JSContext *cx, JS::HandleObject error) { PyObject *errStr = getExceptionString(cx, JS::ExceptionStack(cx, errValue, errStack), true); // Construct a new SpiderMonkeyError python object - PyObject *pyObject = PyObject_CallOneArg(SpiderMonkeyError, errStr); // _PyErr_CreateException, https://github.com/python/cpython/blob/3.9/Python/errors.c#L100 + PyObject *pyObject = _PyObject_CallOneArg(SpiderMonkeyError, errStr); // _PyErr_CreateException, https://github.com/python/cpython/blob/3.9/Python/errors.c#L100 Py_XDECREF(errStr); // Preserve the original JS Error object as the Python Exception's `jsError` attribute for lossless two-way conversion diff --git a/src/IntType.cc b/src/IntType.cc index 4d7f2cd2..de159259 100644 --- a/src/IntType.cc +++ b/src/IntType.cc @@ -15,7 +15,6 @@ #include #include -#include "include/pyshim.hh" #include @@ -101,7 +100,7 @@ PyObject *IntType::getPyObject(JSContext *cx, JS::BigInt *bigint) { // Cast to a pythonmonkey.bigint to differentiate it from a normal Python int, // allowing Py<->JS two-way BigInt conversion. // We don't do `Py_SET_TYPE` because `_PyLong_FromByteArray` may cache and reuse objects for small ints - PyObject *pyObject = PyObject_CallOneArg(getPythonMonkeyBigInt(), pyIntObj); // pyObject = pythonmonkey.bigint(pyIntObj) + PyObject *pyObject = _PyObject_CallOneArg(getPythonMonkeyBigInt(), pyIntObj); // pyObject = pythonmonkey.bigint(pyIntObj) Py_DECREF(pyIntObj); // Set the sign bit diff --git a/src/PromiseType.cc b/src/PromiseType.cc index 5a3f94b3..fc9ab02e 100644 --- a/src/PromiseType.cc +++ b/src/PromiseType.cc @@ -20,7 +20,6 @@ #include #include -#include "include/pyshim.hh" // slot ids to access the python object in JS callbacks #define PY_FUTURE_OBJ_SLOT 0 @@ -41,7 +40,7 @@ static bool onResolvedCb(JSContext *cx, unsigned argc, JS::Value *vp) { if (state == JS::PromiseState::Rejected && !PyExceptionInstance_Check(result)) { // Wrap the result object into a SpiderMonkeyError object // because only *Exception objects can be thrown in Python `raise` statement and alike - PyObject *wrapped = PyObject_CallOneArg(SpiderMonkeyError, result); // wrapped = SpiderMonkeyError(result) + PyObject *wrapped = _PyObject_CallOneArg(SpiderMonkeyError, result); // wrapped = SpiderMonkeyError(result) // Preserve the original JS value as the `jsError` attribute for lossless conversion back PyObject *originalJsErrCapsule = DictType::getPyObject(cx, resultArg); PyObject_SetAttrString(wrapped, "jsError", originalJsErrCapsule); From 23d0576fd4837d9048a0fa75145d284c717fd1e9 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 1 Oct 2024 17:26:40 +0000 Subject: [PATCH 323/428] revert commit 68c288eadaf6fe37f62b09b2107e2363eedc46b1. --- include/pyshim.hh | 10 ++++++++++ src/ExceptionType.cc | 3 ++- src/IntType.cc | 3 ++- src/PromiseType.cc | 3 ++- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/include/pyshim.hh b/include/pyshim.hh index d9dfe72c..ffba8ccc 100644 --- a/include/pyshim.hh +++ b/include/pyshim.hh @@ -118,4 +118,14 @@ static inline void _Py_SET_SIZE(PyVarObject *ob, Py_ssize_t size) { #define Py_SET_SIZE(ob, size) _Py_SET_SIZE((PyVarObject *)(ob), size) #endif +/** + * @brief Shim for `PyObject_CallOneArg`. + * `PyObject_CallOneArg` is not available in Python < 3.9 + */ +#if PY_VERSION_HEX < 0x03090000 // Python version is less than 3.9 +inline PyObject *PyObject_CallOneArg(PyObject *func, PyObject *arg) { + return PyObject_CallFunction(func, "O", arg); +} +#endif + #endif // #ifndef PythonMonkey_py_version_shim_ diff --git a/src/ExceptionType.cc b/src/ExceptionType.cc index 4e3f96d8..053f18e1 100644 --- a/src/ExceptionType.cc +++ b/src/ExceptionType.cc @@ -21,6 +21,7 @@ #include #include +#include "include/pyshim.hh" PyObject *ExceptionType::getPyObject(JSContext *cx, JS::HandleObject error) { @@ -30,7 +31,7 @@ PyObject *ExceptionType::getPyObject(JSContext *cx, JS::HandleObject error) { PyObject *errStr = getExceptionString(cx, JS::ExceptionStack(cx, errValue, errStack), true); // Construct a new SpiderMonkeyError python object - PyObject *pyObject = _PyObject_CallOneArg(SpiderMonkeyError, errStr); // _PyErr_CreateException, https://github.com/python/cpython/blob/3.9/Python/errors.c#L100 + PyObject *pyObject = PyObject_CallOneArg(SpiderMonkeyError, errStr); // _PyErr_CreateException, https://github.com/python/cpython/blob/3.9/Python/errors.c#L100 Py_XDECREF(errStr); // Preserve the original JS Error object as the Python Exception's `jsError` attribute for lossless two-way conversion diff --git a/src/IntType.cc b/src/IntType.cc index de159259..4d7f2cd2 100644 --- a/src/IntType.cc +++ b/src/IntType.cc @@ -15,6 +15,7 @@ #include #include +#include "include/pyshim.hh" #include @@ -100,7 +101,7 @@ PyObject *IntType::getPyObject(JSContext *cx, JS::BigInt *bigint) { // Cast to a pythonmonkey.bigint to differentiate it from a normal Python int, // allowing Py<->JS two-way BigInt conversion. // We don't do `Py_SET_TYPE` because `_PyLong_FromByteArray` may cache and reuse objects for small ints - PyObject *pyObject = _PyObject_CallOneArg(getPythonMonkeyBigInt(), pyIntObj); // pyObject = pythonmonkey.bigint(pyIntObj) + PyObject *pyObject = PyObject_CallOneArg(getPythonMonkeyBigInt(), pyIntObj); // pyObject = pythonmonkey.bigint(pyIntObj) Py_DECREF(pyIntObj); // Set the sign bit diff --git a/src/PromiseType.cc b/src/PromiseType.cc index fc9ab02e..5a3f94b3 100644 --- a/src/PromiseType.cc +++ b/src/PromiseType.cc @@ -20,6 +20,7 @@ #include #include +#include "include/pyshim.hh" // slot ids to access the python object in JS callbacks #define PY_FUTURE_OBJ_SLOT 0 @@ -40,7 +41,7 @@ static bool onResolvedCb(JSContext *cx, unsigned argc, JS::Value *vp) { if (state == JS::PromiseState::Rejected && !PyExceptionInstance_Check(result)) { // Wrap the result object into a SpiderMonkeyError object // because only *Exception objects can be thrown in Python `raise` statement and alike - PyObject *wrapped = _PyObject_CallOneArg(SpiderMonkeyError, result); // wrapped = SpiderMonkeyError(result) + PyObject *wrapped = PyObject_CallOneArg(SpiderMonkeyError, result); // wrapped = SpiderMonkeyError(result) // Preserve the original JS value as the `jsError` attribute for lossless conversion back PyObject *originalJsErrCapsule = DictType::getPyObject(cx, resultArg); PyObject_SetAttrString(wrapped, "jsError", originalJsErrCapsule); From 6bf3d705872ea8ec7a1f1be7a7414c8160b80eaa Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 1 Oct 2024 17:40:42 +0000 Subject: [PATCH 324/428] refactor: replace `PyObject_CallNoArgs(func)` calls with `PyObject_CallObject(func, NULL)`, which is available in all Python versions --- src/jsTypeFactory.cc | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/jsTypeFactory.cc b/src/jsTypeFactory.cc index 36139c09..d1fcfb60 100644 --- a/src/jsTypeFactory.cc +++ b/src/jsTypeFactory.cc @@ -394,11 +394,7 @@ bool callPyFunc(JSContext *cx, unsigned int argc, JS::Value *vp) { // use faster calling if no arguments are needed if (((nNormalArgs + nDefaultArgs) <= 0 && !varargs)) { - #if PY_VERSION_HEX >= 0x03090000 - pyRval = PyObject_CallNoArgs(pyFunc); - #else - pyRval = _PyObject_CallNoArg(pyFunc); // in Python 3.8, the API is only available under the name with a leading underscore - #endif + pyRval = PyObject_CallObject(pyFunc, NULL); if (PyErr_Occurred() && setPyException(cx)) { // Check if an exception has already been set in Python error stack goto failure; } From c4d94057dd5d9519333ba60293aacbc602bc0b1d Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 1 Oct 2024 18:18:17 +0000 Subject: [PATCH 325/428] refactor: add shim for `PyLong_AsByteArray` to work with different function signatures --- include/pyshim.hh | 14 ++++++++++++++ src/IntType.cc | 6 +----- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/include/pyshim.hh b/include/pyshim.hh index ffba8ccc..1e43d86f 100644 --- a/include/pyshim.hh +++ b/include/pyshim.hh @@ -128,4 +128,18 @@ inline PyObject *PyObject_CallOneArg(PyObject *func, PyObject *arg) { } #endif +/** + * @brief Shim for `_PyLong_AsByteArray`. + * Python 3.13.0a4 added a new public API `PyLong_AsNativeBytes()` to replace the private `_PyLong_AsByteArray()`. + * But this change also modified the function signature of `_PyLong_AsByteArray()`. + * @see https://github.com/python/cpython/issues/111140 + */ +inline int PyLong_AsByteArray(PyLongObject *v, unsigned char *bytes, size_t n, bool little_endian, bool is_signed) { +#if PY_VERSION_HEX >= 0x030d0000 // Python version is 3.13 or higher + return _PyLong_AsByteArray(v, bytes, n, little_endian, is_signed, /*with_exceptions*/ false); +#else + return _PyLong_AsByteArray(v, bytes, n, little_endian, is_signed); +#endif +} + #endif // #ifndef PythonMonkey_py_version_shim_ diff --git a/src/IntType.cc b/src/IntType.cc index 4d7f2cd2..26a7ea1e 100644 --- a/src/IntType.cc +++ b/src/IntType.cc @@ -134,11 +134,7 @@ JS::BigInt *IntType::toJsBigInt(JSContext *cx, PyObject *pyObject) { // Convert to bytes of 8-bit "digits" in **big-endian** order size_t byteCount = (size_t)JS_DIGIT_BYTE * jsDigitCount; uint8_t *bytes = (uint8_t *)PyMem_Malloc(byteCount); - #if PY_VERSION_HEX >= 0x030d0000 // Python version is greater than 3.13 - _PyLong_AsByteArray((PyLongObject *)pyObject, bytes, byteCount, /*is_little_endian*/ false, false, false); - #else - _PyLong_AsByteArray((PyLongObject *)pyObject, bytes, byteCount, /*is_little_endian*/ false, false); - #endif + PyLong_AsByteArray((PyLongObject *)pyObject, bytes, byteCount, /*is_little_endian*/ false, false); // Convert pm.bigint to JS::BigInt through hex strings (no public API to convert directly through bytes) // TODO (Tom Tang): We could manually allocate the memory, https://hg.mozilla.org/releases/mozilla-esr102/file/tip/js/src/vm/BigIntType.cpp#l162, but still no public API From 3e2aad2d9dc0167dabc06c45ac91c7ffd911c97a Mon Sep 17 00:00:00 2001 From: Tom Wenzheng Tang Date: Tue, 1 Oct 2024 14:26:05 -0400 Subject: [PATCH 326/428] feat: add back the ability to mutate parent scope variables with `pm.exec`/`eval` Co-authored-by: Caleb Aikens --- python/pythonmonkey/require.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/python/pythonmonkey/require.py b/python/pythonmonkey/require.py index 09025c49..0022e9c2 100644 --- a/python/pythonmonkey/require.py +++ b/python/pythonmonkey/require.py @@ -84,10 +84,8 @@ globalThis.python.stderr.read = lambda n: sys.stderr.read(n) # Python 3.13 dramatically changed how the namespace in `exec`/`eval` works # See https://docs.python.org/3.13/whatsnew/3.13.html#defined-mutation-semantics-for-locals -_locals = {} # keep the local variables inside `eval`/`exec` to a dict -globalThis.python.eval = lambda x: eval(x, None, _locals) -globalThis.python.exec = lambda x: exec(x, None, _locals) -globalThis.python.getenv = os.getenv +globalThis.python.eval = lambda x: eval(x, None, sys._getframe(1).f_locals) +globalThis.python.exec = lambda x: exec(x, None, sys._getframe(1).f_locals) globalThis.python.paths = sys.path globalThis.python.exit = pm.eval("""'use strict'; From 7ebe1498fdee6f0054d5db2eb178f235aefbfcbf Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 1 Oct 2024 18:31:31 +0000 Subject: [PATCH 327/428] fix: add back `python.getenv` that was accidentally deleted in `3e2aad2` --- python/pythonmonkey/require.py | 1 + 1 file changed, 1 insertion(+) diff --git a/python/pythonmonkey/require.py b/python/pythonmonkey/require.py index 0022e9c2..bbb4661f 100644 --- a/python/pythonmonkey/require.py +++ b/python/pythonmonkey/require.py @@ -86,6 +86,7 @@ # See https://docs.python.org/3.13/whatsnew/3.13.html#defined-mutation-semantics-for-locals globalThis.python.eval = lambda x: eval(x, None, sys._getframe(1).f_locals) globalThis.python.exec = lambda x: exec(x, None, sys._getframe(1).f_locals) +globalThis.python.getenv = os.getenv globalThis.python.paths = sys.path globalThis.python.exit = pm.eval("""'use strict'; From dda291633d059d846114376db64eecfc2e2e0f1d Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 1 Oct 2024 19:13:11 +0000 Subject: [PATCH 328/428] fix: reference count for `array_fill` Since each call of `PyList_SetItem` steals a reference (even if its to the same object), we need multiple references to it for it to steal Co-authored-by: Caleb Aikens --- src/PyListProxyHandler.cc | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/PyListProxyHandler.cc b/src/PyListProxyHandler.cc index 33cb619b..72da8d4e 100644 --- a/src/PyListProxyHandler.cc +++ b/src/PyListProxyHandler.cc @@ -428,18 +428,16 @@ static bool array_fill(JSContext *cx, unsigned argc, JS::Value *vp) { JS::RootedValue fillValue(cx, args[0].get()); PyObject *fillValueItem = pyTypeFactory(cx, fillValue); - bool setItemCalled = false; for (int index = actualStart; index < actualEnd; index++) { - setItemCalled = true; + // Since each call of `PyList_SetItem` steals a reference (even if its to the same object), + // We need multiple references to it for it to steal. + Py_INCREF(fillValueItem); if (PyList_SetItem(self, index, fillValueItem) < 0) { return false; } } - Py_INCREF(fillValueItem); - if (setItemCalled) { - Py_INCREF(fillValueItem); - } + Py_DECREF(fillValueItem); // return ref to self args.rval().set(jsTypeFactory(cx, self)); From 5b9deec8ec071d5c86749b99cb413fa6ea5d8ab1 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 1 Oct 2024 19:28:33 +0000 Subject: [PATCH 329/428] set `GLOBAL_CX = null` in the final cleanup function since it's no longer usable/useful after the context is destroyed --- src/modules/pythonmonkey/pythonmonkey.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/modules/pythonmonkey/pythonmonkey.cc b/src/modules/pythonmonkey/pythonmonkey.cc index b0cfb09a..8408b594 100644 --- a/src/modules/pythonmonkey/pythonmonkey.cc +++ b/src/modules/pythonmonkey/pythonmonkey.cc @@ -310,7 +310,10 @@ static void cleanup() { // Clean up SpiderMonkey delete autoRealm; delete global; - if (GLOBAL_CX) JS_DestroyContext(GLOBAL_CX); + if (GLOBAL_CX) { + JS_DestroyContext(GLOBAL_CX); + GLOBAL_CX = nullptr; + } delete JOB_QUEUE; JS_ShutDown(); } From a4762ae50096a777495a40d2228e82e315844654 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 1 Oct 2024 21:00:20 +0000 Subject: [PATCH 330/428] fix the reference count for dicts `test_get_default_not_found` in Python 3.11 Something is double-free-ed during the final finalization: in a debug build of Python, `./Include/object.h:602: _Py_NegativeRefcount: Assertion failed: object has negative ref count` In non-debug build of Python, it simply segfaults at the end during finalization. --- src/JSObjectProxy.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/JSObjectProxy.cc b/src/JSObjectProxy.cc index 29512974..e983335b 100644 --- a/src/JSObjectProxy.cc +++ b/src/JSObjectProxy.cc @@ -638,6 +638,7 @@ PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_get_method(JSObjectProxy PyObject *value = JSObjectProxy_get(self, key); if (value == Py_None) { + Py_INCREF(default_value); value = default_value; } From db0fae5a4b7cfe214c4683f08952ff07d25e048e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2024 14:14:32 +0000 Subject: [PATCH 331/428] chore(deps): upgrade SpiderMonkey to `4bdfb2c22e6e4b5600f66612c6d6121fe99769a1` --- mozcentral.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mozcentral.version b/mozcentral.version index 9f4b8194..1b304b54 100644 --- a/mozcentral.version +++ b/mozcentral.version @@ -1 +1 @@ -a283127a5d0aa005c54d339e8ca27414b55f079b \ No newline at end of file +4bdfb2c22e6e4b5600f66612c6d6121fe99769a1 \ No newline at end of file From bb78bbd2c46a92957316e73d794787723f637d96 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 8 Oct 2024 20:21:52 +0000 Subject: [PATCH 332/428] CI: use the release version of Python 3.13 Python 3.13 was finally released on October 7, 2024. GitHub Actions' `actions/setup-python` already added support for the final release version. See https://raw.githubusercontent.com/actions/python-versions/main/versions-manifest.json --- .github/workflows/test-and-publish.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 3b41d93e..c066d4f9 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -30,7 +30,7 @@ on: - '3.10' - '3.11' - '3.12' - - '3.13-dev' + - '3.13' build_type: type: choice description: 'Choose the build type to use' @@ -133,7 +133,7 @@ jobs: fail-fast: false matrix: os: [ 'ubuntu-20.04', 'macos-12', 'macos-14', 'windows-2022', 'pi' ] - python_version: [ '3.8', '3.9', '3.10', '3.11', '3.12', '3.13-dev' ] + python_version: [ '3.8', '3.9', '3.10', '3.11', '3.12', '3.13' ] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 From 1a98043951b0fb2e001367d3677ef8e3de9fee8b Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 1 Oct 2024 21:00:20 +0000 Subject: [PATCH 333/428] fix the reference count for dicts `test_get_default_not_found` Something is double-free-ed during the final finalization: in a debug build of Python, `./Include/object.h:602: _Py_NegativeRefcount: Assertion failed: object has negative ref count` In non-debug build of Python, it simply segfaults at the end during finalization. --- src/JSObjectProxy.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/JSObjectProxy.cc b/src/JSObjectProxy.cc index eff28ee4..9e755a17 100644 --- a/src/JSObjectProxy.cc +++ b/src/JSObjectProxy.cc @@ -637,6 +637,7 @@ PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_get_method(JSObjectProxy PyObject *value = JSObjectProxy_get(self, key); if (value == Py_None) { + Py_INCREF(default_value); value = default_value; } From ff21692f6003b67984328dc9c7eb54bd91023ede Mon Sep 17 00:00:00 2001 From: Tom Wenzheng Tang Date: Fri, 29 Nov 2024 15:11:52 -0500 Subject: [PATCH 334/428] fix(CI): remove the XCode version setup step There's a recent change in GitHub hosted runners that only one major version of Xcode will be available per macOS version. See https://github.com/actions/runner-images/issues/10703 --- .github/workflows/test-and-publish.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index c066d4f9..cccd0aa0 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -85,7 +85,7 @@ jobs: key: spidermonkey-${{ env.MOZCENTRAL_VERSION }}-${{ runner.os }}-${{ runner.arch }} lookup-only: true # skip download - name: Setup XCode - if: ${{ (matrix.os == 'macos-13' || matrix.os == 'macos-14') && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} + if: ${{ matrix.os == 'macos-13' && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} # SpiderMonkey requires XCode SDK version at least 13.3 run: sudo xcode-select -switch /Applications/Xcode_14.3.app - name: Build spidermonkey From a5cdd79815895d3e90768f8fd847d87139a7bc1c Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Fri, 29 Nov 2024 20:25:56 +0000 Subject: [PATCH 335/428] fix: failed to parse `pyproject.toml` file Python `toml` version 0.10.0 (the older version pip 20 uses) doesn't support homogeneous arrays See https://github.com/Distributive-Network/PythonMonkey/issues/455#issuecomment-2460479160 --- pyproject.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 10385d80..f6aa2f53 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,12 +9,12 @@ packages = [ ] include = [ # Linux and macOS - "python/pythonmonkey/pythonmonkey.so", - "python/pythonmonkey/libmozjs*", + { path = "python/pythonmonkey/pythonmonkey.so", format = ["sdist", "wheel"] }, + { path = "python/pythonmonkey/libmozjs*", format = ["sdist", "wheel"] }, # Windows - "python/pythonmonkey/pythonmonkey.pyd", - "python/pythonmonkey/mozjs-*.dll", + { path = "python/pythonmonkey/pythonmonkey.pyd", format = ["sdist", "wheel"] }, + { path = "python/pythonmonkey/mozjs-*.dll", format = ["sdist", "wheel"] }, # include all files for source distribution { path = "src", format = "sdist" }, From 800747b7648c005636f4ca30c7538ca9aa4796dd Mon Sep 17 00:00:00 2001 From: Tom Wenzheng Tang Date: Mon, 2 Dec 2024 06:57:39 -0500 Subject: [PATCH 336/428] Fix the macOS 14 CI (#458) fix(CI): failed to find an adequate linker on macOS 14 * Always use `ld64` for the linker on macOS because `lld` is not available in the CI machine See also: https://searchfox.org/mozilla-central/rev/e741c34/build/moz.configure/toolchain.configure#1889 * The patch for using `install_name_tool` instead of `install-name-tool` is no longer needed --- .github/workflows/test-and-publish.yaml | 7 +++++++ setup.sh | 13 ++++++------- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index cccd0aa0..0fcad267 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -88,6 +88,13 @@ jobs: if: ${{ matrix.os == 'macos-13' && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} # SpiderMonkey requires XCode SDK version at least 13.3 run: sudo xcode-select -switch /Applications/Xcode_14.3.app + - name: Setup LLVM + if: ${{ (matrix.os == 'macos-13' || matrix.os == 'macos-14') && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} + run: | + brew install llvm@15 + ln -s $(brew --prefix llvm@15)/bin/lld /usr/local/bin/lld + ln -s $(brew --prefix llvm@15)/bin/ld64.lld /usr/local/bin/ld64.lld + ld64.lld --version - name: Build spidermonkey if: ${{ steps.cache-spidermonkey.outputs.cache-hit != 'true' }} run: ./setup.sh diff --git a/setup.sh b/setup.sh index bbe1b272..fc3f38d8 100755 --- a/setup.sh +++ b/setup.sh @@ -49,11 +49,12 @@ echo "Done downloading spidermonkey source code" echo "Building spidermonkey" cd firefox-source + +# Apply patching # making it work for both GNU and BSD (macOS) versions of sed sed -i'' -e 's/os not in ("WINNT", "OSX", "Android")/os not in ("WINNT", "Android")/' ./build/moz.configure/pkg.configure # use pkg-config on macOS sed -i'' -e '/"WindowsDllMain.cpp"/d' ./mozglue/misc/moz.build # https://discourse.mozilla.org/t/105671, https://bugzilla.mozilla.org/show_bug.cgi?id=1751561 sed -i'' -e '/"winheap.cpp"/d' ./memory/mozalloc/moz.build # https://bugzilla.mozilla.org/show_bug.cgi?id=1802675 -sed -i'' -e 's/"install-name-tool"/"install_name_tool"/' ./moz.configure # `install-name-tool` does not exist, but we have `install_name_tool` sed -i'' -e 's/bool Unbox/JS_PUBLIC_API bool Unbox/g' ./js/public/Class.h # need to manually add JS_PUBLIC_API to js::Unbox until it gets fixed in Spidermonkey sed -i'' -e 's/bool js::Unbox/JS_PUBLIC_API bool js::Unbox/g' ./js/src/vm/JSObject.cpp # same here sed -i'' -e 's/shared_lib = self._pretty_path(libdef.output_path, backend_file)/shared_lib = libdef.lib_name/' ./python/mozbuild/mozbuild/backend/recursivemake.py # would generate a Makefile to install the binary files from an invalid path prefix @@ -63,6 +64,9 @@ sed -i'' -e 's/return JS::GetWeakRefsEnabled() == JS::WeakRefSpecifier::Disabled sed -i'' -e 's/return !IsIteratorHelpersEnabled()/return false/' ./js/src/vm/GlobalObject.cpp # forcibly enable iterator helpers sed -i'' -e '/MOZ_CRASH_UNSAFE_PRINTF/,/__PRETTY_FUNCTION__);/d' ./mfbt/LinkedList.h # would crash in Debug Build: in `~LinkedList()` it should have removed all this list's elements before the list's destruction sed -i'' -e '/MOZ_ASSERT(stackRootPtr == nullptr);/d' ./js/src/vm/JSContext.cpp # would assert false in Debug Build since we extensively use `new JS::Rooted` +sed -i'' -e 's|-id $(abspath $(libdir)|-id $(abspath @rpath|' ./js/src/build/Makefile.in # Set the `install_name` field of libmozjs dylib to use the RPATH instead of an absolute path +sed -i'' -e 's/"-fuse-ld=ld"/"-ld64" if c_compiler.version > "14.0.0" else "-fuse-ld=ld"/' ./build/moz.configure/toolchain.configure # XCode 15 changed the linker behaviour. See https://developer.apple.com/documentation/xcode-release-notes/xcode-15-release-notes#Linking + cd js/src mkdir -p _build cd _build @@ -74,6 +78,7 @@ mkdir -p ../../../../_spidermonkey_install/ --disable-debug-symbols \ --disable-jemalloc \ --disable-tests \ + $(if [[ "$OSTYPE" == "darwin"* ]]; then echo "--enable-linker=ld64"; fi) \ --enable-optimize make -j$CPUS echo "Done building spidermonkey" @@ -81,12 +86,6 @@ echo "Done building spidermonkey" echo "Installing spidermonkey" # install to ../../../../_spidermonkey_install/ make install -if [[ "$OSTYPE" == "darwin"* ]]; then # macOS - cd ../../../../_spidermonkey_install/lib/ - # Set the `install_name` field to use RPATH instead of an absolute path - # overrides https://hg.mozilla.org/releases/mozilla-esr102/file/89d799cb/js/src/build/Makefile.in#l83 - install_name_tool -id @rpath/$(basename ./libmozjs*) ./libmozjs* # making it work for whatever name the libmozjs dylib is called -fi echo "Done installing spidermonkey" # if this is being ran in the root directory of the PythonMonkey repo, then include dev configurations From 9878b9fb5b6e32e6b0f63d869a533eed7fe7ae31 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Mon, 2 Dec 2024 12:01:28 +0000 Subject: [PATCH 337/428] fix(CI): `lld` needs to be installed on macOS the host linker requires to be `lld`, as the `--enable-linker=ld64` option for `../configure` is only for specifying the target linker --- .github/workflows/test-and-publish.yaml | 7 ------- setup.sh | 1 + 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 0fcad267..cccd0aa0 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -88,13 +88,6 @@ jobs: if: ${{ matrix.os == 'macos-13' && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} # SpiderMonkey requires XCode SDK version at least 13.3 run: sudo xcode-select -switch /Applications/Xcode_14.3.app - - name: Setup LLVM - if: ${{ (matrix.os == 'macos-13' || matrix.os == 'macos-14') && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} - run: | - brew install llvm@15 - ln -s $(brew --prefix llvm@15)/bin/lld /usr/local/bin/lld - ln -s $(brew --prefix llvm@15)/bin/ld64.lld /usr/local/bin/ld64.lld - ld64.lld --version - name: Build spidermonkey if: ${{ steps.cache-spidermonkey.outputs.cache-hit != 'true' }} run: ./setup.sh diff --git a/setup.sh b/setup.sh index fc3f38d8..37908200 100755 --- a/setup.sh +++ b/setup.sh @@ -18,6 +18,7 @@ if [[ "$OSTYPE" == "linux-gnu"* ]]; then # Linux elif [[ "$OSTYPE" == "darwin"* ]]; then # macOS brew update || true # allow failure brew install cmake pkg-config wget unzip coreutils # `coreutils` installs the `realpath` command + brew install lld elif [[ "$OSTYPE" == "msys"* ]]; then # Windows echo "Dependencies are not going to be installed automatically on Windows." else From 8eade682535a0d2c1a22f473081619294e25a9ce Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Mon, 2 Dec 2024 12:02:53 +0000 Subject: [PATCH 338/428] fixup: set the `install_name` field of libmozjs dylib to use the RPATH instead of an absolute path --- setup.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/setup.sh b/setup.sh index 37908200..a10d7b66 100755 --- a/setup.sh +++ b/setup.sh @@ -65,7 +65,6 @@ sed -i'' -e 's/return JS::GetWeakRefsEnabled() == JS::WeakRefSpecifier::Disabled sed -i'' -e 's/return !IsIteratorHelpersEnabled()/return false/' ./js/src/vm/GlobalObject.cpp # forcibly enable iterator helpers sed -i'' -e '/MOZ_CRASH_UNSAFE_PRINTF/,/__PRETTY_FUNCTION__);/d' ./mfbt/LinkedList.h # would crash in Debug Build: in `~LinkedList()` it should have removed all this list's elements before the list's destruction sed -i'' -e '/MOZ_ASSERT(stackRootPtr == nullptr);/d' ./js/src/vm/JSContext.cpp # would assert false in Debug Build since we extensively use `new JS::Rooted` -sed -i'' -e 's|-id $(abspath $(libdir)|-id $(abspath @rpath|' ./js/src/build/Makefile.in # Set the `install_name` field of libmozjs dylib to use the RPATH instead of an absolute path sed -i'' -e 's/"-fuse-ld=ld"/"-ld64" if c_compiler.version > "14.0.0" else "-fuse-ld=ld"/' ./build/moz.configure/toolchain.configure # XCode 15 changed the linker behaviour. See https://developer.apple.com/documentation/xcode-release-notes/xcode-15-release-notes#Linking cd js/src @@ -87,6 +86,12 @@ echo "Done building spidermonkey" echo "Installing spidermonkey" # install to ../../../../_spidermonkey_install/ make install +if [[ "$OSTYPE" == "darwin"* ]]; then # macOS + cd ../../../../_spidermonkey_install/lib/ + # Set the `install_name` field to use RPATH instead of an absolute path + # overrides https://hg.mozilla.org/releases/mozilla-esr102/file/89d799cb/js/src/build/Makefile.in#l83 + install_name_tool -id @rpath/$(basename ./libmozjs*) ./libmozjs* # making it work for whatever name the libmozjs dylib is called +fi echo "Done installing spidermonkey" # if this is being ran in the root directory of the PythonMonkey repo, then include dev configurations From 81e9ff2f130a24262d7c88bbb7d441432292932c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 2 Dec 2024 14:15:26 +0000 Subject: [PATCH 339/428] chore(deps): upgrade SpiderMonkey to `250be4ca3c669db9a397456402f68249aa15d8d5` --- mozcentral.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mozcentral.version b/mozcentral.version index 9f4b8194..edb1ac10 100644 --- a/mozcentral.version +++ b/mozcentral.version @@ -1 +1 @@ -a283127a5d0aa005c54d339e8ca27414b55f079b \ No newline at end of file +250be4ca3c669db9a397456402f68249aa15d8d5 \ No newline at end of file From a3c349479824e4b4e5fdd58df05b348d2d0c709b Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 3 Dec 2024 17:53:25 +0000 Subject: [PATCH 340/428] fix(JobQueue): the `JobQueue::getIncumbentGlobal` method has been removed from the definition in new SpiderMonkey version --- include/JobQueue.hh | 9 --------- src/JobQueue.cc | 4 ---- 2 files changed, 13 deletions(-) diff --git a/include/JobQueue.hh b/include/JobQueue.hh index 36a6d810..a4ad4ecb 100644 --- a/include/JobQueue.hh +++ b/include/JobQueue.hh @@ -34,15 +34,6 @@ explicit JobQueue(JSContext *cx); */ bool init(JSContext *cx); -/** - * @brief Ask the embedding for the incumbent global. - * - * SpiderMonkey doesn't itself have a notion of incumbent globals as defined - * by the HTML spec, so we need the embedding to provide this. See - * dom/script/ScriptSettings.h for details. - */ -JSObject *getIncumbentGlobal(JSContext *cx) override; - /** * @brief Enqueue a reaction job `job` for `promise`, which was allocated at * `allocationSite`. Provide `incumbentGlobal` as the incumbent global for diff --git a/src/JobQueue.cc b/src/JobQueue.cc index 6dcb548f..a4ddaa61 100644 --- a/src/JobQueue.cc +++ b/src/JobQueue.cc @@ -26,10 +26,6 @@ JobQueue::JobQueue(JSContext *cx) { finalizationRegistryCallbacks = new JS::PersistentRooted(cx); // Leaks but it's OK since freed at process exit } -JSObject *JobQueue::getIncumbentGlobal(JSContext *cx) { - return JS::CurrentGlobalOrNull(cx); -} - bool JobQueue::enqueuePromiseJob(JSContext *cx, [[maybe_unused]] JS::HandleObject promise, JS::HandleObject job, From b832fa87de4751a68761d74a795703b9cc026672 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 3 Dec 2024 18:03:21 +0000 Subject: [PATCH 341/428] feat(JobQueue): implement the new `JobQueue::getHostDefinedData` method on `JobQueue` for the new SpiderMonkey version --- include/JobQueue.hh | 17 +++++++++++++++++ src/JobQueue.cc | 5 +++++ 2 files changed, 22 insertions(+) diff --git a/include/JobQueue.hh b/include/JobQueue.hh index a4ad4ecb..36734f92 100644 --- a/include/JobQueue.hh +++ b/include/JobQueue.hh @@ -34,6 +34,23 @@ explicit JobQueue(JSContext *cx); */ bool init(JSContext *cx); +/** + * @brief Ask the embedding for the host defined data. + * + * SpiderMonkey doesn't itself have a notion of host defined data as defined + * by the HTML spec, so we need the embedding to provide this. See + * dom/script/ScriptSettings.h for details. + * + * If the embedding has the host defined data, this method should return the + * host defined data via the `data` out parameter and return `true`. + * The object in the `data` out parameter can belong to any compartment. + * If the embedding doesn't need the host defined data, this method should + * set the `data` out parameter to `nullptr` and return `true`. + * If any error happens while generating the host defined data, this method + * should set a pending exception to `cx` and return `false`. + */ +bool getHostDefinedData(JSContext *cx, JS::MutableHandle data) const override; + /** * @brief Enqueue a reaction job `job` for `promise`, which was allocated at * `allocationSite`. Provide `incumbentGlobal` as the incumbent global for diff --git a/src/JobQueue.cc b/src/JobQueue.cc index a4ddaa61..928746fd 100644 --- a/src/JobQueue.cc +++ b/src/JobQueue.cc @@ -26,6 +26,11 @@ JobQueue::JobQueue(JSContext *cx) { finalizationRegistryCallbacks = new JS::PersistentRooted(cx); // Leaks but it's OK since freed at process exit } +bool JobQueue::getHostDefinedData(JSContext *cx, JS::MutableHandle data) const { + data.set(nullptr); // We don't need the host defined data + return true; // `true` indicates no error +} + bool JobQueue::enqueuePromiseJob(JSContext *cx, [[maybe_unused]] JS::HandleObject promise, JS::HandleObject job, From b36bbdfe87666a3eada0520cd9f7bd6e05530d63 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 3 Dec 2024 18:31:30 +0000 Subject: [PATCH 342/428] fix(CI): the macOS-12 environment is deprecated and removed from GitHub hosted runners --- .github/workflows/test-and-publish.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index cccd0aa0..92b2c750 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -16,7 +16,7 @@ on: options: - '' - 'ubuntu-20.04' - - 'macos-12' + - 'macos-13' - 'macos-14' - 'windows-2022' debug_enabled_python: @@ -132,7 +132,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ 'ubuntu-20.04', 'macos-12', 'macos-14', 'windows-2022', 'pi' ] + os: [ 'ubuntu-20.04', 'macos-13', 'macos-14', 'windows-2022', 'pi' ] python_version: [ '3.8', '3.9', '3.10', '3.11', '3.12', '3.13' ] runs-on: ${{ matrix.os }} steps: @@ -207,7 +207,7 @@ jobs: BUILD_TYPE=${WORKFLOW_BUILD_TYPE:-"Debug"} poetry build --format=wheel ls -lah ./dist/ - name: Make the wheels we build also support lower versions of macOS - if: ${{ matrix.os == 'macos-12' || matrix.os == 'macos-14' }} + if: ${{ matrix.os == 'macos-13' || matrix.os == 'macos-14' }} # Change the platform tag part of the wheel filename to `macosx_11_0_xxx` (means to support macOS 11.0 and above) # See https://packaging.python.org/en/latest/specifications/binary-distribution-format/#file-format # A wheel package file will only be selected by pip to install if the platform tag satisfies, regardless of whether the binary compatibility actually is. From 6ac7fcffa4706daa841a34b581b4ceafe64b87e0 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 4 Dec 2024 17:44:01 +0000 Subject: [PATCH 343/428] chore: update package information Update the PKG-INFO `pip show pythonmonkey` would give. * Change the authors field to `Distributive Corp.` * Add project description * Add the MIT license * Add links to our homepage and GitHub repo etc. --- pyproject.toml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index f6aa2f53..d69bc902 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,8 +1,12 @@ [tool.poetry] name = "pythonmonkey" version = "0" # automatically set by poetry-dynamic-versioning -description = "" -authors = ["Caleb Aikens ", "Tom Tang ", "Wes Garland ", "Hamada Gasmallah ", "Philippe Laporte "] +description = "Seamless interop between Python and JavaScript." +authors = ["Distributive Corp. "] +license = "MIT" +homepage = "https://pythonmonkey.io/" +documentation = "https://docs.pythonmonkey.io/" +repository = "https://github.com/Distributive-Network/PythonMonkey" readme = "README.md" packages = [ { include = "pythonmonkey", from = "python" }, From 4e302aa90b4012d659b0f873d17d69910902a9fe Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 4 Dec 2024 17:53:20 +0000 Subject: [PATCH 344/428] chore: update package information --- python/pminit/pyproject.toml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/python/pminit/pyproject.toml b/python/pminit/pyproject.toml index 9910cc72..09d28174 100644 --- a/python/pminit/pyproject.toml +++ b/python/pminit/pyproject.toml @@ -3,11 +3,13 @@ name = "pminit" version = "0" description = "Post-install hook for PythonMonkey" authors = [ - "Tom Tang ", - "Caleb Aikens ", - "Wes Garland ", - "Hamada Gasmallah " + "Distributive Corp. " ] +license = "MIT" +homepage = "https://pythonmonkey.io/" +documentation = "https://docs.pythonmonkey.io/" +repository = "https://github.com/Distributive-Network/PythonMonkey" + include = [ # Install extra files into the pythonmonkey package "pythonmonkey/package*.json", From d5e6285c559e93fb093e77b0a26f57c47815743f Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 3 Dec 2024 18:31:30 +0000 Subject: [PATCH 345/428] fix(CI): the macOS-12 environment is deprecated and removed from GitHub hosted runners --- .github/workflows/test-and-publish.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index cccd0aa0..92b2c750 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -16,7 +16,7 @@ on: options: - '' - 'ubuntu-20.04' - - 'macos-12' + - 'macos-13' - 'macos-14' - 'windows-2022' debug_enabled_python: @@ -132,7 +132,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ 'ubuntu-20.04', 'macos-12', 'macos-14', 'windows-2022', 'pi' ] + os: [ 'ubuntu-20.04', 'macos-13', 'macos-14', 'windows-2022', 'pi' ] python_version: [ '3.8', '3.9', '3.10', '3.11', '3.12', '3.13' ] runs-on: ${{ matrix.os }} steps: @@ -207,7 +207,7 @@ jobs: BUILD_TYPE=${WORKFLOW_BUILD_TYPE:-"Debug"} poetry build --format=wheel ls -lah ./dist/ - name: Make the wheels we build also support lower versions of macOS - if: ${{ matrix.os == 'macos-12' || matrix.os == 'macos-14' }} + if: ${{ matrix.os == 'macos-13' || matrix.os == 'macos-14' }} # Change the platform tag part of the wheel filename to `macosx_11_0_xxx` (means to support macOS 11.0 and above) # See https://packaging.python.org/en/latest/specifications/binary-distribution-format/#file-format # A wheel package file will only be selected by pip to install if the platform tag satisfies, regardless of whether the binary compatibility actually is. From 65e852f3eae08cf9684b52c4d2b656b27ee30b1e Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Sat, 21 Dec 2024 08:34:19 +0000 Subject: [PATCH 346/428] fix: class prototypes cannot be properly set test_bytes_instanceof: Python bytes instanceof JS Uint8Array assert False test_keys_iterator: TypeError iterator is not iterable If `explicit-resource-management` is enabled, the lib .so will be compiled differently to the header files when there's a `IF_EXPLICIT_RESOURCE_MANAGEMENT` macro used. The `enum JSProtoKey` index is off by 1 (header `JSProto_Uint8Array` 27 will be interpreted as `JSProto_Int8Array` in lib as lib has an extra element) --- setup.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/setup.sh b/setup.sh index a10d7b66..dd5a6f50 100755 --- a/setup.sh +++ b/setup.sh @@ -79,7 +79,10 @@ mkdir -p ../../../../_spidermonkey_install/ --disable-jemalloc \ --disable-tests \ $(if [[ "$OSTYPE" == "darwin"* ]]; then echo "--enable-linker=ld64"; fi) \ - --enable-optimize + --enable-optimize \ + --disable-explicit-resource-management +# disable-explicit-resource-management: Disable the `using` syntax that is enabled by default in SpiderMonkey nightly, otherwise the header files will disagree with the compiled lib .so file +# when it's using a `IF_EXPLICIT_RESOURCE_MANAGEMENT` macro, e.g., the `enum JSProtoKey` index would be off by 1 (header `JSProto_Uint8Array` 27 will be interpreted as `JSProto_Int8Array` in lib as lib has an extra element) make -j$CPUS echo "Done building spidermonkey" From 44189968ff3a0c1a0f684a39393ad1604ccb5f1d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 6 Jan 2025 14:14:23 +0000 Subject: [PATCH 347/428] chore(deps): upgrade SpiderMonkey to `dd8b1488a379ee395592f636d084cf81117f3b4c` --- mozcentral.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mozcentral.version b/mozcentral.version index 1b304b54..05c524ed 100644 --- a/mozcentral.version +++ b/mozcentral.version @@ -1 +1 @@ -4bdfb2c22e6e4b5600f66612c6d6121fe99769a1 \ No newline at end of file +dd8b1488a379ee395592f636d084cf81117f3b4c \ No newline at end of file From a3ea199e706b652cafc1a588ea32ff0abdb6f457 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Thu, 9 Jan 2025 08:11:19 +0000 Subject: [PATCH 348/428] chore: patches for Windows linking issues are no longer needed, as they were fixed in upstream SpiderMonkey See https://bugzilla.mozilla.org/show_bug.cgi?id=1751561 and https://bugzilla.mozilla.org/show_bug.cgi?id=1802675 See also: https://discourse.mozilla.org/t/problem-building-102-3-0esr-on-windows/105671 --- setup.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/setup.sh b/setup.sh index dd5a6f50..fedc944d 100755 --- a/setup.sh +++ b/setup.sh @@ -54,8 +54,6 @@ cd firefox-source # Apply patching # making it work for both GNU and BSD (macOS) versions of sed sed -i'' -e 's/os not in ("WINNT", "OSX", "Android")/os not in ("WINNT", "Android")/' ./build/moz.configure/pkg.configure # use pkg-config on macOS -sed -i'' -e '/"WindowsDllMain.cpp"/d' ./mozglue/misc/moz.build # https://discourse.mozilla.org/t/105671, https://bugzilla.mozilla.org/show_bug.cgi?id=1751561 -sed -i'' -e '/"winheap.cpp"/d' ./memory/mozalloc/moz.build # https://bugzilla.mozilla.org/show_bug.cgi?id=1802675 sed -i'' -e 's/bool Unbox/JS_PUBLIC_API bool Unbox/g' ./js/public/Class.h # need to manually add JS_PUBLIC_API to js::Unbox until it gets fixed in Spidermonkey sed -i'' -e 's/bool js::Unbox/JS_PUBLIC_API bool js::Unbox/g' ./js/src/vm/JSObject.cpp # same here sed -i'' -e 's/shared_lib = self._pretty_path(libdef.output_path, backend_file)/shared_lib = libdef.lib_name/' ./python/mozbuild/mozbuild/backend/recursivemake.py # would generate a Makefile to install the binary files from an invalid path prefix From aaa7e4d5db276c3c650a36afaf335ab78e92ef0c Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Thu, 9 Jan 2025 08:47:55 +0000 Subject: [PATCH 349/428] fix: error 'unistd.h' file not found on Windows On https://searchfox.org/mozilla-central/rev/ead020d/mozglue/baseprofiler/public/BaseProfilerUtils.h#22, it detects Windows platform by seeing if the `XP_WIN` macro is defined, if not then assumes it's on POSIX and includes the `` header to use `getpid()`. The `mozilla/BaseProfilerUtils.h` header file is introduced to `js/Debug.h` in https://phabricator.services.mozilla.com/D221102 (https://bugzilla.mozilla.org/show_bug.cgi?id=1911021), but it would be compiled without `XP_WIN` in our building configuration --- setup.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/setup.sh b/setup.sh index fedc944d..5a2a2eb2 100755 --- a/setup.sh +++ b/setup.sh @@ -64,6 +64,7 @@ sed -i'' -e 's/return !IsIteratorHelpersEnabled()/return false/' ./js/src/vm/Glo sed -i'' -e '/MOZ_CRASH_UNSAFE_PRINTF/,/__PRETTY_FUNCTION__);/d' ./mfbt/LinkedList.h # would crash in Debug Build: in `~LinkedList()` it should have removed all this list's elements before the list's destruction sed -i'' -e '/MOZ_ASSERT(stackRootPtr == nullptr);/d' ./js/src/vm/JSContext.cpp # would assert false in Debug Build since we extensively use `new JS::Rooted` sed -i'' -e 's/"-fuse-ld=ld"/"-ld64" if c_compiler.version > "14.0.0" else "-fuse-ld=ld"/' ./build/moz.configure/toolchain.configure # XCode 15 changed the linker behaviour. See https://developer.apple.com/documentation/xcode-release-notes/xcode-15-release-notes#Linking +sed -i'' -e 's/defined(XP_WIN)/defined(_WIN32)/' ./mozglue/baseprofiler/public/BaseProfilerUtils.h # this header file is introduced to js/Debug.h in https://phabricator.services.mozilla.com/D221102, but it would be compiled without XP_WIN in this building configuration cd js/src mkdir -p _build @@ -81,6 +82,7 @@ mkdir -p ../../../../_spidermonkey_install/ --disable-explicit-resource-management # disable-explicit-resource-management: Disable the `using` syntax that is enabled by default in SpiderMonkey nightly, otherwise the header files will disagree with the compiled lib .so file # when it's using a `IF_EXPLICIT_RESOURCE_MANAGEMENT` macro, e.g., the `enum JSProtoKey` index would be off by 1 (header `JSProto_Uint8Array` 27 will be interpreted as `JSProto_Int8Array` in lib as lib has an extra element) +# https://bugzilla.mozilla.org/show_bug.cgi?id=1940342 make -j$CPUS echo "Done building spidermonkey" From 7f8e45d3c2ef33999eacb1b16e93cc154ef09d08 Mon Sep 17 00:00:00 2001 From: Ryu Juheon Date: Sat, 11 Jan 2025 13:11:24 +0900 Subject: [PATCH 350/428] chore: addition of marker file according to pep561 --- pyproject.toml | 2 ++ python/pythonmonkey/py.typed | 1 + 2 files changed, 3 insertions(+) create mode 100644 python/pythonmonkey/py.typed diff --git a/pyproject.toml b/pyproject.toml index d69bc902..066ff5d4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,6 +28,8 @@ include = [ { path = "CMakeLists.txt", format = "sdist" }, { path = "*.sh", format = "sdist" }, { path = "mozcentral.version", format = "sdist" }, + # Add marker file for pep561 + "python/pythonmonkey/py.typed", ] diff --git a/python/pythonmonkey/py.typed b/python/pythonmonkey/py.typed new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/python/pythonmonkey/py.typed @@ -0,0 +1 @@ + From aae5725e3d22425bc2b9f60322bb53587bf304bb Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 3 Feb 2025 14:14:13 +0000 Subject: [PATCH 351/428] chore(deps): upgrade SpiderMonkey to `e571552c235724fbce9b1ceaedf4bff73093eaa7` --- mozcentral.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mozcentral.version b/mozcentral.version index 6463d215..59c645f8 100644 --- a/mozcentral.version +++ b/mozcentral.version @@ -1 +1 @@ -dd8b1488a379ee395592f636d084cf81117f3b4c +e571552c235724fbce9b1ceaedf4bff73093eaa7 \ No newline at end of file From b100d235035d6d940111a739e7bd7324a8b486c2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Feb 2025 03:29:28 +0000 Subject: [PATCH 352/428] chore(deps): bump ctx-module in /python/pminit/pythonmonkey Bumps [ctx-module](https://github.com/wesgarland/ctx-module) from 1.0.14 to 1.0.15. - [Commits](https://github.com/wesgarland/ctx-module/compare/v1.0.14...v1.0.15) --- updated-dependencies: - dependency-name: ctx-module dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- python/pminit/pythonmonkey/package-lock.json | 317 +++++++++++++------ python/pminit/pythonmonkey/package.json | 2 +- 2 files changed, 214 insertions(+), 105 deletions(-) diff --git a/python/pminit/pythonmonkey/package-lock.json b/python/pminit/pythonmonkey/package-lock.json index 81a5aac6..6533b355 100644 --- a/python/pminit/pythonmonkey/package-lock.json +++ b/python/pminit/pythonmonkey/package-lock.json @@ -10,24 +10,26 @@ "license": "MIT", "dependencies": { "core-js": "^3.35.1", - "ctx-module": "^1.0.14" + "ctx-module": "^1.0.15", + "events": "^3.3.0" } }, "node_modules/asn1.js": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", - "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", + "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", + "license": "MIT", "dependencies": { "bn.js": "^4.0.0", "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "safer-buffer": "^2.1.0" + "minimalistic-assert": "^1.0.0" } }, "node_modules/asn1.js/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", + "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", + "license": "MIT" }, "node_modules/base64-js": { "version": "1.5.1", @@ -51,17 +53,20 @@ "node_modules/bn.js": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", - "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==" + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", + "license": "MIT" }, "node_modules/brorand": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", + "license": "MIT" }, "node_modules/browserify-aes": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "license": "MIT", "dependencies": { "buffer-xor": "^1.0.3", "cipher-base": "^1.0.0", @@ -75,6 +80,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "license": "MIT", "dependencies": { "browserify-aes": "^1.0.4", "browserify-des": "^1.0.0", @@ -85,6 +91,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "license": "MIT", "dependencies": { "cipher-base": "^1.0.1", "des.js": "^1.0.0", @@ -93,31 +100,38 @@ } }, "node_modules/browserify-rsa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", - "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.1.tgz", + "integrity": "sha512-YBjSAiTqM04ZVei6sXighu679a3SqWORA3qZTEqZImnlkDIFtKc6pNutpjyZ8RJTjQtuYfeetkxM11GwoYXMIQ==", + "license": "MIT", "dependencies": { - "bn.js": "^5.0.0", - "randombytes": "^2.0.1" + "bn.js": "^5.2.1", + "randombytes": "^2.1.0", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" } }, "node_modules/browserify-sign": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.2.tgz", - "integrity": "sha512-1rudGyeYY42Dk6texmv7c4VcQ0EsvVbLwZkA+AQB7SxvXxmcD93jcHie8bzecJ+ChDlmAm2Qyu0+Ccg5uhZXCg==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.3.tgz", + "integrity": "sha512-JWCZW6SKhfhjJxO8Tyiiy+XYB7cqd2S5/+WeYHsKdNKFlCBhKbblba1A/HN/90YwtxKc8tCErjffZl++UNmGiw==", + "license": "ISC", "dependencies": { "bn.js": "^5.2.1", "browserify-rsa": "^4.1.0", "create-hash": "^1.2.0", "create-hmac": "^1.1.7", - "elliptic": "^6.5.4", + "elliptic": "^6.5.5", + "hash-base": "~3.0", "inherits": "^2.0.4", - "parse-asn1": "^5.1.6", - "readable-stream": "^3.6.2", + "parse-asn1": "^5.1.7", + "readable-stream": "^2.3.8", "safe-buffer": "^5.2.1" }, "engines": { - "node": ">= 4" + "node": ">= 0.12" } }, "node_modules/buffer": { @@ -146,15 +160,20 @@ "node_modules/buffer-xor": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==" + "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", + "license": "MIT" }, "node_modules/cipher-base": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", - "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.6.tgz", + "integrity": "sha512-3Ek9H3X6pj5TgenXYtNWdaBon1tgYCaebd+XPg0keyjEbEfkD4KkmAxkQ/i1vYvxdcT5nscLBfq9VJRmCBcFSw==", + "license": "MIT", "dependencies": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" } }, "node_modules/core-js": { @@ -167,24 +186,33 @@ "url": "https://opencollective.com/core-js" } }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT" + }, "node_modules/create-ecdh": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", + "license": "MIT", "dependencies": { "bn.js": "^4.1.0", "elliptic": "^6.5.3" } }, "node_modules/create-ecdh/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", + "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", + "license": "MIT" }, "node_modules/create-hash": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "license": "MIT", "dependencies": { "cipher-base": "^1.0.1", "inherits": "^2.0.1", @@ -197,6 +225,7 @@ "version": "1.1.7", "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "license": "MIT", "dependencies": { "cipher-base": "^1.0.3", "create-hash": "^1.1.0", @@ -207,39 +236,64 @@ } }, "node_modules/crypto-browserify": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", - "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.1.tgz", + "integrity": "sha512-r4ESw/IlusD17lgQi1O20Fa3qNnsckR126TdUuBgAu7GBYSIPvdNyONd3Zrxh0xCwA4+6w/TDArBPsMvhur+KQ==", + "license": "MIT", "dependencies": { - "browserify-cipher": "^1.0.0", - "browserify-sign": "^4.0.0", - "create-ecdh": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.0", - "diffie-hellman": "^5.0.0", - "inherits": "^2.0.1", - "pbkdf2": "^3.0.3", - "public-encrypt": "^4.0.0", - "randombytes": "^2.0.0", - "randomfill": "^1.0.3" + "browserify-cipher": "^1.0.1", + "browserify-sign": "^4.2.3", + "create-ecdh": "^4.0.4", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "diffie-hellman": "^5.0.3", + "hash-base": "~3.0.4", + "inherits": "^2.0.4", + "pbkdf2": "^3.1.2", + "public-encrypt": "^4.0.3", + "randombytes": "^2.1.0", + "randomfill": "^1.0.4" }, "engines": { - "node": "*" + "node": ">= 0.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/ctx-module": { - "version": "1.0.14", - "resolved": "https://registry.npmjs.org/ctx-module/-/ctx-module-1.0.14.tgz", - "integrity": "sha512-eH4h/bv64YuzCHMUZs93j57/4zNJHyQWOIz5CPAs1gJ/4yznPD9HoCLCXjQlST2AxOLOKNvV67n+A8dALtLA+Q==", + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/ctx-module/-/ctx-module-1.0.15.tgz", + "integrity": "sha512-+/L9CMH/5cjNW+ddPmqGoxF4/xOns3jdTZFbvi683zjxB/FEACGKpBLfVVWvLsyJsdQCKLVibUlM7Ui/BtMS/A==", + "license": "MIT", "dependencies": { "buffer": "^6.0.3", - "crypto-browserify": "^3.12.0" + "crypto-browserify": "^3.12.1", + "debug": "^4.3.4" + } + }, + "node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, "node_modules/des.js": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz", "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==", + "license": "MIT", "dependencies": { "inherits": "^2.0.1", "minimalistic-assert": "^1.0.0" @@ -249,6 +303,7 @@ "version": "5.0.3", "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "license": "MIT", "dependencies": { "bn.js": "^4.1.0", "miller-rabin": "^4.0.0", @@ -256,14 +311,16 @@ } }, "node_modules/diffie-hellman/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", + "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", + "license": "MIT" }, "node_modules/elliptic": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", - "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz", + "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==", + "license": "MIT", "dependencies": { "bn.js": "^4.11.9", "brorand": "^1.1.0", @@ -275,9 +332,10 @@ } }, "node_modules/elliptic/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", + "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", + "license": "MIT" }, "node_modules/events": { "version": "3.3.0", @@ -288,28 +346,30 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "license": "MIT", "dependencies": { "md5.js": "^1.3.4", "safe-buffer": "^5.1.1" } }, "node_modules/hash-base": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", - "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.5.tgz", + "integrity": "sha512-vXm0l45VbcHEVlTCzs8M+s0VeYsB2lnlAaThoLKGXr3bE/VWDOelNUnycUPEhKEaXARL2TEFjBOyUiM6+55KBg==", + "license": "MIT", "dependencies": { "inherits": "^2.0.4", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" + "safe-buffer": "^5.2.1" }, "engines": { - "node": ">=4" + "node": ">= 0.10" } }, "node_modules/hash.js": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "license": "MIT", "dependencies": { "inherits": "^2.0.3", "minimalistic-assert": "^1.0.1" @@ -319,6 +379,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "license": "MIT", "dependencies": { "hash.js": "^1.0.3", "minimalistic-assert": "^1.0.0", @@ -347,12 +408,20 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" }, "node_modules/md5.js": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "license": "MIT", "dependencies": { "hash-base": "^3.0.0", "inherits": "^2.0.1", @@ -363,6 +432,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "license": "MIT", "dependencies": { "bn.js": "^4.0.0", "brorand": "^1.0.1" @@ -372,36 +442,51 @@ } }, "node_modules/miller-rabin/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", + "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", + "license": "MIT" }, "node_modules/minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "license": "ISC" }, "node_modules/minimalistic-crypto-utils": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==" + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", + "license": "MIT" + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" }, "node_modules/parse-asn1": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", - "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", - "dependencies": { - "asn1.js": "^5.2.0", - "browserify-aes": "^1.0.0", - "evp_bytestokey": "^1.0.0", - "pbkdf2": "^3.0.3", - "safe-buffer": "^5.1.1" + "version": "5.1.7", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.7.tgz", + "integrity": "sha512-CTM5kuWR3sx9IFamcl5ErfPl6ea/N8IYwiJ+vpeB2g+1iknv7zBl5uPwbMbRVznRVbrNY6lGuDoE5b30grmbqg==", + "license": "ISC", + "dependencies": { + "asn1.js": "^4.10.1", + "browserify-aes": "^1.2.0", + "evp_bytestokey": "^1.0.3", + "hash-base": "~3.0", + "pbkdf2": "^3.1.2", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" } }, "node_modules/pbkdf2": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", + "license": "MIT", "dependencies": { "create-hash": "^1.1.2", "create-hmac": "^1.1.4", @@ -413,10 +498,17 @@ "node": ">=0.12" } }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" + }, "node_modules/public-encrypt": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "license": "MIT", "dependencies": { "bn.js": "^4.1.0", "browserify-rsa": "^4.0.0", @@ -427,14 +519,16 @@ } }, "node_modules/public-encrypt/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", + "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", + "license": "MIT" }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "license": "MIT", "dependencies": { "safe-buffer": "^5.1.0" } @@ -443,28 +537,38 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "license": "MIT", "dependencies": { "randombytes": "^2.0.5", "safe-buffer": "^5.1.0" } }, "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, + "node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, "node_modules/ripemd160": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "license": "MIT", "dependencies": { "hash-base": "^3.0.0", "inherits": "^2.0.1" @@ -487,17 +591,14 @@ "type": "consulting", "url": "https://feross.org/support" } - ] - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + ], + "license": "MIT" }, "node_modules/sha.js": { "version": "2.4.11", "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "license": "(MIT AND BSD-3-Clause)", "dependencies": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" @@ -507,17 +608,25 @@ } }, "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", "dependencies": { - "safe-buffer": "~5.2.0" + "safe-buffer": "~5.1.0" } }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" } } } diff --git a/python/pminit/pythonmonkey/package.json b/python/pminit/pythonmonkey/package.json index 5c921692..af323dd0 100644 --- a/python/pminit/pythonmonkey/package.json +++ b/python/pminit/pythonmonkey/package.json @@ -22,7 +22,7 @@ "homepage": "https://github.com/Distributive-Network/PythonMonkey#readme", "dependencies": { "core-js": "^3.35.1", - "ctx-module": "^1.0.14", + "ctx-module": "^1.0.15", "events": "^3.3.0" } } From e9b9818a0dd7ea678421a8b7fbd99ee28ec5be21 Mon Sep 17 00:00:00 2001 From: Tom Wenzheng Tang Date: Fri, 4 Apr 2025 10:40:03 -0400 Subject: [PATCH 353/428] fix(CI): `actions/upload-artifact@v3` is deprecated, migrate to v4 --- .github/workflows/test-and-publish.yaml | 33 ++++++++++++++----------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 92b2c750..95b91fe0 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -180,7 +180,7 @@ jobs: BUILD_DOCS=1 BUILD_TYPE=None poetry install - name: Upload Doxygen-generated docs as CI artifacts if: ${{ matrix.os == 'ubuntu-20.04' && matrix.python_version == '3.11' }} - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: docs-${{ github.run_id }}-${{ github.sha }} path: ./build/docs/html/ @@ -218,9 +218,9 @@ jobs: mv "$file" "$(echo "$file" | sed -E 's/macosx_[0-9]+_[0-9]+/macosx_11_0/')"; done - name: Upload wheel as CI artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: wheel-${{ github.run_id }}-${{ github.sha }} + name: wheel-${{ github.run_id }}-${{ github.sha }}-${{ matrix.os }} path: ./dist/ - name: Set cores to get stored in /cores if: ${{ matrix.os != 'windows-2022' }} @@ -282,9 +282,9 @@ jobs: poetry build --format=sdist ls -lah ./dist/ - name: Upload sdist as CI artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: wheel-${{ github.run_id }}-${{ github.sha }} + name: wheel-${{ github.run_id }}-${{ github.sha }}-sdist path: ./dist/ check-install-from-sdist: needs: sdist @@ -294,9 +294,9 @@ jobs: with: python-version: '3.10' - name: Download wheels built - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: - name: wheel-${{ github.run_id }}-${{ github.sha }} + name: wheel-${{ github.run_id }}-${{ github.sha }}-sdist path: ./dist/ - run: pip install ./dist/pythonmonkey-*.tar.gz publish: @@ -310,9 +310,10 @@ jobs: python-version: '3.9' - run: pip install twine - name: Download wheels built - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: - name: wheel-${{ github.run_id }}-${{ github.sha }} + pattern: wheel-${{ github.run_id }}-${{ github.sha }}-* + merge-multiple: true path: ./dist/ - run: ls -lah ./dist/ - name: Publish package @@ -335,12 +336,13 @@ jobs: steps: # don't checkout - name: Download wheels built - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: - name: wheel-${{ github.run_id }}-${{ github.sha }} + pattern: wheel-${{ github.run_id }}-${{ github.sha }}-* + merge-multiple: true path: ./dist/ - name: Download docs html generated by Doxygen - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: docs-${{ github.run_id }}-${{ github.sha }} path: ./docs/ @@ -391,12 +393,13 @@ jobs: steps: # no need to checkout - name: Download wheels built - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: - name: wheel-${{ github.run_id }}-${{ github.sha }} + pattern: wheel-${{ github.run_id }}-${{ github.sha }}-* + merge-multiple: true path: ./ - name: Download docs html generated by Doxygen - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: docs-${{ github.run_id }}-${{ github.sha }} path: ./docs/ From 552ac992dac61be44e27f65a988d4fdae75ec1be Mon Sep 17 00:00:00 2001 From: Tom Wenzheng Tang Date: Fri, 4 Apr 2025 10:45:42 -0400 Subject: [PATCH 354/428] fix(CI): `actions/upload-artifact@v3` is deprecated, migrate to v4 --- .github/workflows/test-and-publish.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 95b91fe0..833f5ba0 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -257,7 +257,7 @@ jobs: with: credentials: "admin:admin" - name: Upload core dumps as CI artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: ${{ matrix.os != 'windows-2022' && failure() }} # TODO (Caleb Aikens) figure out how to get Windows core dumps with: From 79c5d18e911510cfc2ecb0d8880d39423e1c4fdc Mon Sep 17 00:00:00 2001 From: Tom Wenzheng Tang Date: Fri, 4 Apr 2025 11:08:00 -0400 Subject: [PATCH 355/428] fix(CI): CI artifacts cannot reuse the same name --- .github/workflows/test-and-publish.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 833f5ba0..b7b92a85 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -220,7 +220,7 @@ jobs: - name: Upload wheel as CI artifacts uses: actions/upload-artifact@v4 with: - name: wheel-${{ github.run_id }}-${{ github.sha }}-${{ matrix.os }} + name: wheel-${{ github.run_id }}-${{ github.sha }}-{{ runner.os }}_${{ runner.arch }}_Python{{ matrix.python_version }} path: ./dist/ - name: Set cores to get stored in /cores if: ${{ matrix.os != 'windows-2022' }} From e240fff1183a857cb7561545da1566285c441ea4 Mon Sep 17 00:00:00 2001 From: Tom Wenzheng Tang Date: Fri, 4 Apr 2025 11:13:21 -0400 Subject: [PATCH 356/428] fix(CI): fix up --- .github/workflows/test-and-publish.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index b7b92a85..053bb1cf 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -220,7 +220,7 @@ jobs: - name: Upload wheel as CI artifacts uses: actions/upload-artifact@v4 with: - name: wheel-${{ github.run_id }}-${{ github.sha }}-{{ runner.os }}_${{ runner.arch }}_Python{{ matrix.python_version }} + name: wheel-${{ github.run_id }}-${{ github.sha }}-${{ runner.os }}_${{ runner.arch }}_Python${{ matrix.python_version }} path: ./dist/ - name: Set cores to get stored in /cores if: ${{ matrix.os != 'windows-2022' }} From 1790e4eac16b501df98267365e106eeb3e8eb653 Mon Sep 17 00:00:00 2001 From: Tom Wenzheng Tang Date: Fri, 4 Apr 2025 11:34:05 -0400 Subject: [PATCH 357/428] fix(CI): `actions/upload-pages-artifact` and `actions/deploy-pages` also need to be upgraded --- .github/workflows/test-and-publish.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 053bb1cf..66342fae 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -376,12 +376,12 @@ jobs: html+="
  • pminit
  • " html+="" echo "$html" > ./index.html - - uses: actions/upload-pages-artifact@v1 + - uses: actions/upload-pages-artifact@v3 with: path: ./ - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v2 + uses: actions/deploy-pages@v4 publish-archive: # Publish to ⊇istributive's archive server (https://archive.distributed.computer/releases/pythonmonkey/) needs: [build-and-test, sdist] From 76bf24ad5a83e0c668e834a503c1260cf1ed9718 Mon Sep 17 00:00:00 2001 From: Tom Wenzheng Tang Date: Mon, 7 Apr 2025 04:36:48 -0400 Subject: [PATCH 358/428] chore(CI): use GitHub-hosted runners for Linux arm64 So that we don't have to maintain a Ubuntu VM inside of the office M1 mac mini. And forkers can run the CI by themselves. --- .github/workflows/test-and-publish.yaml | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 66342fae..5e9b7981 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -65,8 +65,8 @@ jobs: fail-fast: false matrix: # Use Ubuntu 20.04 / macOS 13 x86_64 / macOS 14 arm64 + Python 3.10 to build SpiderMonkey - os: [ 'ubuntu-20.04', 'macos-13', 'macos-14', 'pi' ] # macOS 14 runner exclusively runs on M1 hardwares - # see https://github.blog/changelog/2024-01-30-github-actions-macos-14-sonoma-is-now-available + os: [ 'ubuntu-20.04', 'macos-13', 'macos-14', 'ubuntu-22.04-arm' ] # macOS 14 runner exclusively runs on M1 hardwares + # see https://github.blog/changelog/2024-01-30-github-actions-macos-14-sonoma-is-now-available python_version: [ '3.10' ] runs-on: ${{ matrix.os }} steps: @@ -132,7 +132,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ 'ubuntu-20.04', 'macos-13', 'macos-14', 'windows-2022', 'pi' ] + os: [ 'ubuntu-20.04', 'macos-13', 'macos-14', 'windows-2022', 'ubuntu-22.04-arm' ] python_version: [ '3.8', '3.9', '3.10', '3.11', '3.12', '3.13' ] runs-on: ${{ matrix.os }} steps: @@ -144,9 +144,6 @@ jobs: - uses: actions/setup-python@v5 with: python-version: ${{ matrix.python_version }} - - name: Remove old poetry cache - run: rm -rf ~/.cache/pypoetry - if: ${{ matrix.os == 'pi' }} - name: Setup Poetry uses: snok/install-poetry@v1 with: From d54b94939bced5018025a8942d6ad09783582de0 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Mon, 7 Apr 2025 19:33:29 +0000 Subject: [PATCH 359/428] chore: download firefox-source from git for the time being Until https://bugzilla.mozilla.org/show_bug.cgi?id=1958951 gets resolved. git https://github.com/mozilla/gecko-dev/commit/cdfe21b20eacfaa6712dd9821d6383859ce386c6 is equivalent to hg https://hg-edge.mozilla.org/mozilla-central/rev/dd8b1488a379ee395592f636d084cf81117f3b4c --- .github/workflows/update-mozcentral-version.yaml | 6 +++--- mozcentral.version | 2 +- setup.sh | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/update-mozcentral-version.yaml b/.github/workflows/update-mozcentral-version.yaml index 027720b8..ec3c6a41 100644 --- a/.github/workflows/update-mozcentral-version.yaml +++ b/.github/workflows/update-mozcentral-version.yaml @@ -1,8 +1,8 @@ name: 'Create pull requests to update mozilla-central version to the latest' on: - schedule: - - cron: "00 14 */100,1-7 * 1" # run on the first Monday of each month at 14:00 UTC (10:00 Eastern Daylight Time) + # schedule: + # - cron: "00 14 */100,1-7 * 1" # run on the first Monday of each month at 14:00 UTC (10:00 Eastern Daylight Time) # See https://blog.healthchecks.io/2022/09/schedule-cron-job-the-funky-way/ workflow_call: workflow_dispatch: # or you can run it manually @@ -21,7 +21,7 @@ jobs: # See https://mozilla-version-control-tools.readthedocs.io/en/latest/hgmo/pushlog.html#hgweb-commands run: | COMMIT_HASH=$( - curl -s "https://hg.mozilla.org/mozilla-central/json-pushes?tipsonly=1&version=2" |\ + curl -L -s "https://hg.mozilla.org/mozilla-central/json-pushes?tipsonly=1&version=2" |\ jq --join-output '(.lastpushid | tostring) as $pushid | empty, .pushes[$pushid].changesets[0]' ) echo "MOZCENTRAL_VERSION=$COMMIT_HASH" >> $GITHUB_ENV diff --git a/mozcentral.version b/mozcentral.version index 6463d215..c92edae9 100644 --- a/mozcentral.version +++ b/mozcentral.version @@ -1 +1 @@ -dd8b1488a379ee395592f636d084cf81117f3b4c +cdfe21b20eacfaa6712dd9821d6383859ce386c6 diff --git a/setup.sh b/setup.sh index 5a2a2eb2..a3b23f0b 100755 --- a/setup.sh +++ b/setup.sh @@ -44,8 +44,8 @@ echo "Done installing dependencies" echo "Downloading spidermonkey source code" # Read the commit hash for mozilla-central from the `mozcentral.version` file MOZCENTRAL_VERSION=$(cat mozcentral.version) -wget -c -q -O firefox-source-${MOZCENTRAL_VERSION}.zip https://hg.mozilla.org/mozilla-central/archive/${MOZCENTRAL_VERSION}.zip -unzip -q firefox-source-${MOZCENTRAL_VERSION}.zip && mv mozilla-central-${MOZCENTRAL_VERSION} firefox-source +wget -c -q -O firefox-source-${MOZCENTRAL_VERSION}.zip https://github.com/mozilla/gecko-dev/archive/${MOZCENTRAL_VERSION}.zip +unzip -q firefox-source-${MOZCENTRAL_VERSION}.zip && mv gecko-dev-${MOZCENTRAL_VERSION} firefox-source echo "Done downloading spidermonkey source code" echo "Building spidermonkey" From e5e338a73a7d075cc5bb51870cb06bf84e861215 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 4 Jun 2025 15:56:21 +0000 Subject: [PATCH 360/428] fix(CI): use Ubuntu 22.04 runner as Ubuntu 20.04 is deprecated by GitHub Actions --- .github/workflows/test-and-publish.yaml | 33 ++++++++----------------- 1 file changed, 10 insertions(+), 23 deletions(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 5e9b7981..ab83885a 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -15,7 +15,7 @@ on: required: false options: - '' - - 'ubuntu-20.04' + - 'ubuntu-22.04' - 'macos-13' - 'macos-14' - 'windows-2022' @@ -64,8 +64,8 @@ jobs: strategy: fail-fast: false matrix: - # Use Ubuntu 20.04 / macOS 13 x86_64 / macOS 14 arm64 + Python 3.10 to build SpiderMonkey - os: [ 'ubuntu-20.04', 'macos-13', 'macos-14', 'ubuntu-22.04-arm' ] # macOS 14 runner exclusively runs on M1 hardwares + # Use Ubuntu 22.04 / macOS 13 x86_64 / macOS 14 arm64 + Python 3.10 to build SpiderMonkey + os: [ 'ubuntu-22.04', 'macos-13', 'macos-14', 'ubuntu-22.04-arm' ] # macOS 14 runner exclusively runs on M1 hardwares # see https://github.blog/changelog/2024-01-30-github-actions-macos-14-sonoma-is-now-available python_version: [ '3.10' ] runs-on: ${{ matrix.os }} @@ -132,7 +132,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ 'ubuntu-20.04', 'macos-13', 'macos-14', 'windows-2022', 'ubuntu-22.04-arm' ] + os: [ 'ubuntu-22.04', 'macos-13', 'macos-14', 'windows-2022', 'ubuntu-22.04-arm' ] python_version: [ '3.8', '3.9', '3.10', '3.11', '3.12', '3.13' ] runs-on: ${{ matrix.os }} steps: @@ -166,7 +166,7 @@ jobs: env: PYTHON_VERSION: ${{ matrix.python_version }} - name: Build Docs # only build docs once - if: ${{ matrix.os == 'ubuntu-20.04' && matrix.python_version == '3.11' }} + if: ${{ matrix.os == 'ubuntu-22.04' && matrix.python_version == '3.11' }} run: | sudo apt-get install -y graphviz # the newest version in Ubuntu 20.04 repository is 1.8.17, but we need Doxygen 1.9 series @@ -176,7 +176,7 @@ jobs: rm -rf doxygen-1.9.7 doxygen-1.9.7.linux.bin.tar.gz BUILD_DOCS=1 BUILD_TYPE=None poetry install - name: Upload Doxygen-generated docs as CI artifacts - if: ${{ matrix.os == 'ubuntu-20.04' && matrix.python_version == '3.11' }} + if: ${{ matrix.os == 'ubuntu-22.04' && matrix.python_version == '3.11' }} uses: actions/upload-artifact@v4 with: name: docs-${{ github.run_id }}-${{ github.sha }} @@ -261,7 +261,7 @@ jobs: name: cores-${{ matrix.os }}-${{ matrix.python_version }} path: /cores sdist: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 with: @@ -283,22 +283,9 @@ jobs: with: name: wheel-${{ github.run_id }}-${{ github.sha }}-sdist path: ./dist/ - check-install-from-sdist: - needs: sdist - runs-on: ubuntu-24.04 - steps: - - uses: actions/setup-python@v5 - with: - python-version: '3.10' - - name: Download wheels built - uses: actions/download-artifact@v4 - with: - name: wheel-${{ github.run_id }}-${{ github.sha }}-sdist - path: ./dist/ - - run: pip install ./dist/pythonmonkey-*.tar.gz publish: needs: [build-and-test, sdist] - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 if: ${{ success() && github.event_name == 'push' && github.ref_type == 'tag' }} steps: # no need to checkout @@ -322,7 +309,7 @@ jobs: # Implement a very basic Python package repository (https://peps.python.org/pep-0503/) # and deploy the static files to GitHub Pages needs: [build-and-test, sdist] - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 if: ${{ (success() || failure()) && (github.ref_name == 'main' || github.ref_type == 'tag') }} # publish nightly builds regardless of tests failure permissions: # grant GITHUB_TOKEN the permissions required to make a Pages deployment pages: write @@ -382,7 +369,7 @@ jobs: publish-archive: # Publish to ⊇istributive's archive server (https://archive.distributed.computer/releases/pythonmonkey/) needs: [build-and-test, sdist] - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 if: ${{ (success() || failure()) && (github.ref_name == 'main' || github.ref_type == 'tag') }} environment: name: archive From 2a3a4477ec723af47388b1b27a30748a125c3e56 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 4 Jun 2025 16:30:18 +0000 Subject: [PATCH 361/428] feat(CI): use a Ubuntu 20.04 container to build --- .github/workflows/test-and-publish.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index ab83885a..05800aed 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -69,6 +69,7 @@ jobs: # see https://github.blog/changelog/2024-01-30-github-actions-macos-14-sonoma-is-now-available python_version: [ '3.10' ] runs-on: ${{ matrix.os }} + container: ${{ (matrix.os == 'ubuntu-22.04' && 'ubuntu:20.04') || null }} # Use the Ubuntu 20.04 container inside Ubuntu 22.04 runner to build steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 From 0002a6da558de059a4b840bd0fc7e994b2aaecb2 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 4 Jun 2025 16:34:10 +0000 Subject: [PATCH 362/428] fix(CI): run apt update in the container --- .github/workflows/test-and-publish.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 05800aed..173aa005 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -85,6 +85,8 @@ jobs: ./_spidermonkey_install/* key: spidermonkey-${{ env.MOZCENTRAL_VERSION }}-${{ runner.os }}-${{ runner.arch }} lookup-only: true # skip download + - if: ${{ matrix.os == 'ubuntu-22.04' }} + run: sudo apt-get update -y - name: Setup XCode if: ${{ matrix.os == 'macos-13' && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} # SpiderMonkey requires XCode SDK version at least 13.3 From 931a51e7115b209343799067e29a6dc62e52bd54 Mon Sep 17 00:00:00 2001 From: Tom Wenzheng Tang Date: Wed, 4 Jun 2025 12:39:29 -0400 Subject: [PATCH 363/428] fix(CI): conatiner apt update --- .github/workflows/test-and-publish.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 173aa005..8c4ed963 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -86,7 +86,7 @@ jobs: key: spidermonkey-${{ env.MOZCENTRAL_VERSION }}-${{ runner.os }}-${{ runner.arch }} lookup-only: true # skip download - if: ${{ matrix.os == 'ubuntu-22.04' }} - run: sudo apt-get update -y + run: apt-get update -y && apt-get install -y sudo - name: Setup XCode if: ${{ matrix.os == 'macos-13' && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} # SpiderMonkey requires XCode SDK version at least 13.3 From e4821ec39d10eeddc1254f17305749f5f269c2c5 Mon Sep 17 00:00:00 2001 From: Tom Wenzheng Tang Date: Wed, 4 Jun 2025 12:48:19 -0400 Subject: [PATCH 364/428] fix(CI): `apt-get` should run in noninteractive mode See https://stackoverflow.com/questions/44331836/apt-get-install-tzdata-noninteractive --- .github/workflows/test-and-publish.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 8c4ed963..4100476d 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -49,6 +49,8 @@ env: # don't upgrade outdated brew packages because the process is too slow HOMEBREW_NO_INSTALL_UPGRADE: 1 HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1 + # apt-get should run in noninteractive mode + DEBIAN_FRONTEND: noninteractive defaults: run: From ce0249ca9d18c4e1d77cb116e126bd57f447d970 Mon Sep 17 00:00:00 2001 From: Tom Wenzheng Tang Date: Wed, 4 Jun 2025 12:51:40 -0400 Subject: [PATCH 365/428] feat(CI): use the Ubuntu 20.04 container to build PythonMonkey itself --- .github/workflows/test-and-publish.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 4100476d..33f96714 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -140,6 +140,7 @@ jobs: os: [ 'ubuntu-22.04', 'macos-13', 'macos-14', 'windows-2022', 'ubuntu-22.04-arm' ] python_version: [ '3.8', '3.9', '3.10', '3.11', '3.12', '3.13' ] runs-on: ${{ matrix.os }} + container: ${{ (matrix.os == 'ubuntu-22.04' && 'ubuntu:20.04') || null }} steps: - uses: actions/checkout@v4 with: From 15ec0bf6fe35d0f4894301cb864792e73ed842c1 Mon Sep 17 00:00:00 2001 From: Tom Wenzheng Tang Date: Wed, 4 Jun 2025 12:53:14 -0400 Subject: [PATCH 366/428] fix(CI): setting up container --- .github/workflows/test-and-publish.yaml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 33f96714..e924adc9 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -87,8 +87,12 @@ jobs: ./_spidermonkey_install/* key: spidermonkey-${{ env.MOZCENTRAL_VERSION }}-${{ runner.os }}-${{ runner.arch }} lookup-only: true # skip download - - if: ${{ matrix.os == 'ubuntu-22.04' }} - run: apt-get update -y && apt-get install -y sudo + - name: Setup container + if: ${{ matrix.os == 'ubuntu-22.04' }} + run: | + apt-get update -y + apt-get install -y sudo + DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends tzdata - name: Setup XCode if: ${{ matrix.os == 'macos-13' && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} # SpiderMonkey requires XCode SDK version at least 13.3 From d3dba5bd9b171c01794edc85404b33dfa80fa851 Mon Sep 17 00:00:00 2001 From: Tom Wenzheng Tang Date: Wed, 4 Jun 2025 13:44:12 -0400 Subject: [PATCH 367/428] fix(CI): do not use the Python installation cached for Ubuntu 22.04 --- .github/workflows/test-and-publish.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index e924adc9..25a6402b 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -93,6 +93,7 @@ jobs: apt-get update -y apt-get install -y sudo DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends tzdata + rm -rf $RUNNER_TOOL_CACHE # do not use the Python installation cached for Ubuntu 22.04 - name: Setup XCode if: ${{ matrix.os == 'macos-13' && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} # SpiderMonkey requires XCode SDK version at least 13.3 From 4b72175a9734b3f09411c3dddf4147d1e62d38a3 Mon Sep 17 00:00:00 2001 From: Tom Wenzheng Tang Date: Wed, 4 Jun 2025 13:48:46 -0400 Subject: [PATCH 368/428] fix(CI): do not use the Python installation cached for Ubuntu 22.04 See also: https://github.com/actions/setup-python/issues/1087 --- .github/workflows/test-and-publish.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 25a6402b..cc997e6d 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -93,7 +93,7 @@ jobs: apt-get update -y apt-get install -y sudo DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends tzdata - rm -rf $RUNNER_TOOL_CACHE # do not use the Python installation cached for Ubuntu 22.04 + echo "RUNNER_TOOL_CACHE=/" >> $GITHUB_ENV # do not use the Python installation cached for Ubuntu 22.04 - name: Setup XCode if: ${{ matrix.os == 'macos-13' && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} # SpiderMonkey requires XCode SDK version at least 13.3 From 6b63f48a67391e1f6f0270d793a304ae32eb52e3 Mon Sep 17 00:00:00 2001 From: Tom Wenzheng Tang Date: Wed, 4 Jun 2025 13:52:06 -0400 Subject: [PATCH 369/428] fix(CI): setup Python --- .github/workflows/test-and-publish.yaml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index cc997e6d..978ee4b3 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -74,9 +74,6 @@ jobs: container: ${{ (matrix.os == 'ubuntu-22.04' && 'ubuntu:20.04') || null }} # Use the Ubuntu 20.04 container inside Ubuntu 22.04 runner to build steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 - with: - python-version: ${{ matrix.python_version }} - name: Read the mozilla-central commit hash to be used run: echo "MOZCENTRAL_VERSION=$(cat mozcentral.version)" >> $GITHUB_ENV - name: Cache spidermonkey build @@ -88,12 +85,16 @@ jobs: key: spidermonkey-${{ env.MOZCENTRAL_VERSION }}-${{ runner.os }}-${{ runner.arch }} lookup-only: true # skip download - name: Setup container - if: ${{ matrix.os == 'ubuntu-22.04' }} + if: ${{ matrix.os == 'ubuntu-22.04' && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} run: | apt-get update -y apt-get install -y sudo DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends tzdata echo "RUNNER_TOOL_CACHE=/" >> $GITHUB_ENV # do not use the Python installation cached for Ubuntu 22.04 + - uses: actions/setup-python@v5 + if: ${{ steps.cache-spidermonkey.outputs.cache-hit != 'true' }} + with: + python-version: ${{ matrix.python_version }} - name: Setup XCode if: ${{ matrix.os == 'macos-13' && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} # SpiderMonkey requires XCode SDK version at least 13.3 From b86d6dd326ad5c3135bbf2d1f864977f8bfbc3c9 Mon Sep 17 00:00:00 2001 From: Tom Wenzheng Tang Date: Wed, 4 Jun 2025 13:56:16 -0400 Subject: [PATCH 370/428] fix(CI): `actions/setup-python` do not use cache --- .github/workflows/test-and-publish.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 978ee4b3..9f810a43 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -90,7 +90,7 @@ jobs: apt-get update -y apt-get install -y sudo DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends tzdata - echo "RUNNER_TOOL_CACHE=/" >> $GITHUB_ENV # do not use the Python installation cached for Ubuntu 22.04 + echo "AGENT_TOOLSDIRECTORY=/" >> $GITHUB_ENV # do not use the Python installation cached for Ubuntu 22.04 - uses: actions/setup-python@v5 if: ${{ steps.cache-spidermonkey.outputs.cache-hit != 'true' }} with: From bb8845e1550757c5492cf68e6a0942ff96ea6fb5 Mon Sep 17 00:00:00 2001 From: Tom Wenzheng Tang Date: Wed, 4 Jun 2025 14:01:49 -0400 Subject: [PATCH 371/428] fix(CI): pip can't connect to HTTPS URL because the SSL module is not available --- .github/workflows/test-and-publish.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 9f810a43..f70e6f2a 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -88,7 +88,7 @@ jobs: if: ${{ matrix.os == 'ubuntu-22.04' && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} run: | apt-get update -y - apt-get install -y sudo + apt-get install -y sudo libnss3-dev libssl-dev DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends tzdata echo "AGENT_TOOLSDIRECTORY=/" >> $GITHUB_ENV # do not use the Python installation cached for Ubuntu 22.04 - uses: actions/setup-python@v5 From 33aacd9859c3f3b72c3b0fc7b0316ff1eeae6a72 Mon Sep 17 00:00:00 2001 From: Tom Wenzheng Tang Date: Wed, 4 Jun 2025 14:22:59 -0400 Subject: [PATCH 372/428] fix(CI): setup container --- .github/workflows/test-and-publish.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index f70e6f2a..2da6f7b8 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -148,6 +148,14 @@ jobs: runs-on: ${{ matrix.os }} container: ${{ (matrix.os == 'ubuntu-22.04' && 'ubuntu:20.04') || null }} steps: + - name: Setup container + if: ${{ matrix.os == 'ubuntu-22.04' }} + run: | + apt-get update -y + apt-get install -y sudo libnss3-dev libssl-dev + apt-get install -y git # required for `actions/checkout` + DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends tzdata # tzdata may ask for user interaction if not explicitly installed here + echo "AGENT_TOOLSDIRECTORY=/" >> $GITHUB_ENV # do not use the Python installation cached for Ubuntu 22.04 - uses: actions/checkout@v4 with: submodules: recursive From a4179e11e9494fa6f76078321e4d830102bc06bf Mon Sep 17 00:00:00 2001 From: Tom Wenzheng Tang Date: Wed, 4 Jun 2025 14:29:22 -0400 Subject: [PATCH 373/428] fix(CI): git failed because of dubious ownership See: https://stackoverflow.com/questions/72978485/git-submodule-update-failed-with-fatal-detected-dubious-ownership-in-reposit --- .github/workflows/test-and-publish.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 2da6f7b8..1f72fc45 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -156,6 +156,7 @@ jobs: apt-get install -y git # required for `actions/checkout` DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends tzdata # tzdata may ask for user interaction if not explicitly installed here echo "AGENT_TOOLSDIRECTORY=/" >> $GITHUB_ENV # do not use the Python installation cached for Ubuntu 22.04 + git config --global --add safe.directory '*' # silence "git failed because of dubious ownership" - uses: actions/checkout@v4 with: submodules: recursive From 9cafc6d27c76ebe4fd6de643dc9219d89809c254 Mon Sep 17 00:00:00 2001 From: Tom Wenzheng Tang Date: Wed, 4 Jun 2025 14:36:59 -0400 Subject: [PATCH 374/428] fix(CI): nodejs and npm are required for pminit to build --- .github/workflows/test-and-publish.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 1f72fc45..46413e52 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -154,6 +154,7 @@ jobs: apt-get update -y apt-get install -y sudo libnss3-dev libssl-dev apt-get install -y git # required for `actions/checkout` + apt-get install -y nodejs npm # required for pminit to build DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends tzdata # tzdata may ask for user interaction if not explicitly installed here echo "AGENT_TOOLSDIRECTORY=/" >> $GITHUB_ENV # do not use the Python installation cached for Ubuntu 22.04 git config --global --add safe.directory '*' # silence "git failed because of dubious ownership" From e77335165ca69dcbf82c389786e82a18064c5f13 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 4 Jun 2025 18:44:01 +0000 Subject: [PATCH 375/428] fix(CI): CMake 3.25 or higher is required --- .github/workflows/test-and-publish.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 46413e52..f7e1fb28 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -158,6 +158,12 @@ jobs: DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends tzdata # tzdata may ask for user interaction if not explicitly installed here echo "AGENT_TOOLSDIRECTORY=/" >> $GITHUB_ENV # do not use the Python installation cached for Ubuntu 22.04 git config --global --add safe.directory '*' # silence "git failed because of dubious ownership" + + # CMake 3.25 or higher is required + apt-get install -y ca-certificates gpg wget + wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | sudo tee /usr/share/keyrings/kitware-archive-keyring.gpg >/dev/null + echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ focal main' | sudo tee /etc/apt/sources.list.d/kitware.list >/dev/null + apt-get update -y && apt-get install -y cmake - uses: actions/checkout@v4 with: submodules: recursive From afdced24dd5d1679fddf014bc9c970a87eacfe35 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 4 Jun 2025 18:49:38 +0000 Subject: [PATCH 376/428] feat(CI): remove core dumps as CI artifacts --- .github/workflows/test-and-publish.yaml | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index f7e1fb28..73593436 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -247,18 +247,6 @@ jobs: with: name: wheel-${{ github.run_id }}-${{ github.sha }}-${{ runner.os }}_${{ runner.arch }}_Python${{ matrix.python_version }} path: ./dist/ - - name: Set cores to get stored in /cores - if: ${{ matrix.os != 'windows-2022' }} - # TODO (Caleb Aikens) figure out how to get Windows core dumps - run: | - sudo mkdir -p /cores - sudo chmod 777 /cores - # Core filenames will be of the form osname.pythonversion.executable.pid.timestamp: - if [[ "$OSTYPE" == "linux-gnu"* ]]; then - sudo bash -c 'echo "/cores/${OSTYPE}.$(poetry run python --version).%e.%p.%t" > /proc/sys/kernel/core_pattern' - else - sudo sysctl kern.corefile="/cores/${OSTYPE}.$(poetry run python --version).%e.%p.%y" - fi - name: Run Python tests (pytest) run: | if [[ "$OSTYPE" == "linux-gnu"* || "$OSTYPE" == "darwin"* ]]; then @@ -281,13 +269,6 @@ jobs: uses: fawazahmed0/action-debug@main with: credentials: "admin:admin" - - name: Upload core dumps as CI artifacts - uses: actions/upload-artifact@v4 - if: ${{ matrix.os != 'windows-2022' && failure() }} - # TODO (Caleb Aikens) figure out how to get Windows core dumps - with: - name: cores-${{ matrix.os }}-${{ matrix.python_version }} - path: /cores sdist: runs-on: ubuntu-22.04 steps: From b4a40c2f588d48c84cd5ba07f3038ec7bc75eaad Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 4 Jun 2025 18:56:09 +0000 Subject: [PATCH 377/428] fixup(CI): remove core dumps as CI artifacts core dumps cannot be read in a container --- .github/workflows/test-and-publish.yaml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 73593436..120500f9 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -249,20 +249,12 @@ jobs: path: ./dist/ - name: Run Python tests (pytest) run: | - if [[ "$OSTYPE" == "linux-gnu"* || "$OSTYPE" == "darwin"* ]]; then - # TODO (Caleb Aikens) figure out how to get Windows core dumps - ulimit -c unlimited - fi WORKFLOW_BUILD_TYPE=${{ inputs.build_type }} BUILD_TYPE=${WORKFLOW_BUILD_TYPE:-"Debug"} poetry run python -m pip install --force-reinstall --verbose ./dist/* poetry run python -m pytest tests/python - name: Run JS tests (peter-jr) if: ${{ (success() || failure()) }} run: | - if [[ "$OSTYPE" == "linux-gnu"* || "$OSTYPE" == "darwin"* ]]; then - # TODO (Caleb Aikens) figure out how to get Windows core dumps - ulimit -c unlimited - fi poetry run bash ./peter-jr ./tests/js/ - name: SSH debug session if: ${{ (success() || failure()) && github.event_name == 'workflow_dispatch' && inputs.debug_enabled_os == matrix.os && inputs.debug_enabled_python == matrix.python_version}} From 6a5401a14b1c67be9af73549c318ef980c4baf2a Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 4 Jun 2025 18:58:18 +0000 Subject: [PATCH 378/428] fix(CI): `strace` is required to run JS tests --- .github/workflows/test-and-publish.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 120500f9..86fc2f05 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -155,6 +155,7 @@ jobs: apt-get install -y sudo libnss3-dev libssl-dev apt-get install -y git # required for `actions/checkout` apt-get install -y nodejs npm # required for pminit to build + apt-get install -y strace # required to run JS tests DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends tzdata # tzdata may ask for user interaction if not explicitly installed here echo "AGENT_TOOLSDIRECTORY=/" >> $GITHUB_ENV # do not use the Python installation cached for Ubuntu 22.04 git config --global --add safe.directory '*' # silence "git failed because of dubious ownership" From 2727bc0a137b155f9afc98f63b24cf24f1d49b23 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 4 Jun 2025 19:01:53 +0000 Subject: [PATCH 379/428] feat(CI): nodejs shouldn't be required to build PythonMonkey --- .github/workflows/test-and-publish.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 86fc2f05..fb03fd06 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -154,7 +154,6 @@ jobs: apt-get update -y apt-get install -y sudo libnss3-dev libssl-dev apt-get install -y git # required for `actions/checkout` - apt-get install -y nodejs npm # required for pminit to build apt-get install -y strace # required to run JS tests DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends tzdata # tzdata may ask for user interaction if not explicitly installed here echo "AGENT_TOOLSDIRECTORY=/" >> $GITHUB_ENV # do not use the Python installation cached for Ubuntu 22.04 From 805996191732e270bd8a1153c2f594d0cbb4659e Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 4 Jun 2025 19:10:01 +0000 Subject: [PATCH 380/428] feat: clone SpiderMonkey source code from the official Firefox github repo --- setup.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.sh b/setup.sh index a3b23f0b..2001a374 100755 --- a/setup.sh +++ b/setup.sh @@ -44,8 +44,8 @@ echo "Done installing dependencies" echo "Downloading spidermonkey source code" # Read the commit hash for mozilla-central from the `mozcentral.version` file MOZCENTRAL_VERSION=$(cat mozcentral.version) -wget -c -q -O firefox-source-${MOZCENTRAL_VERSION}.zip https://github.com/mozilla/gecko-dev/archive/${MOZCENTRAL_VERSION}.zip -unzip -q firefox-source-${MOZCENTRAL_VERSION}.zip && mv gecko-dev-${MOZCENTRAL_VERSION} firefox-source +wget -c -q -O firefox-source-${MOZCENTRAL_VERSION}.zip https://github.com/mozilla-firefox/firefox/archive/${MOZCENTRAL_VERSION}.zip +unzip -q firefox-source-${MOZCENTRAL_VERSION}.zip && mv firefox-${MOZCENTRAL_VERSION} firefox-source echo "Done downloading spidermonkey source code" echo "Building spidermonkey" From 8a54b8433c0c710df61617719648f8830d593d08 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 4 Jun 2025 19:13:33 +0000 Subject: [PATCH 381/428] fix Firefox source git version https://github.com/mozilla-firefox/firefox/commit/6bca861985ba51920c1cacc21986af01c51bd690 is equivalent to https://github.com/mozilla/gecko-dev/commit/cdfe9f2e144a04618cb6e9ffd9e6202d6d85ed56 --- mozcentral.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mozcentral.version b/mozcentral.version index f72b9ef3..55aeecbf 100644 --- a/mozcentral.version +++ b/mozcentral.version @@ -1 +1 @@ -cdfe9f2e144a04618cb6e9ffd9e6202d6d85ed56 +6bca861985ba51920c1cacc21986af01c51bd690 From 16561c6a7e38dcae0320ceee9420bf8107db5f1d Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 4 Jun 2025 19:25:09 +0000 Subject: [PATCH 382/428] Revert "feat(CI): nodejs shouldn't be required to build PythonMonkey" This reverts commit 2727bc0a137b155f9afc98f63b24cf24f1d49b23. --- .github/workflows/test-and-publish.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index fb03fd06..bcb7a070 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -154,6 +154,7 @@ jobs: apt-get update -y apt-get install -y sudo libnss3-dev libssl-dev apt-get install -y git # required for `actions/checkout` + apt-get install -y nodejs npm apt-get install -y strace # required to run JS tests DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends tzdata # tzdata may ask for user interaction if not explicitly installed here echo "AGENT_TOOLSDIRECTORY=/" >> $GITHUB_ENV # do not use the Python installation cached for Ubuntu 22.04 From ba5c704e1b22549859ec6c6347eaf4f2c32425d6 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 4 Jun 2025 19:25:52 +0000 Subject: [PATCH 383/428] fix(CI): `build-essential` should be installed instead --- .github/workflows/test-and-publish.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index bcb7a070..337e85f6 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -154,7 +154,7 @@ jobs: apt-get update -y apt-get install -y sudo libnss3-dev libssl-dev apt-get install -y git # required for `actions/checkout` - apt-get install -y nodejs npm + apt-get install -y build-essential apt-get install -y strace # required to run JS tests DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends tzdata # tzdata may ask for user interaction if not explicitly installed here echo "AGENT_TOOLSDIRECTORY=/" >> $GITHUB_ENV # do not use the Python installation cached for Ubuntu 22.04 From 3879ce69673741ef52ca7c8a25d118e2e3075188 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 4 Jun 2025 19:34:13 +0000 Subject: [PATCH 384/428] we shouldn't be testing npm inside of pytests --- tests/python/test_dicts.py | 8 -------- tests/python/test_functions_this.py | 12 ++---------- 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/tests/python/test_dicts.py b/tests/python/test_dicts.py index 99959926..b3f481fa 100644 --- a/tests/python/test_dicts.py +++ b/tests/python/test_dicts.py @@ -367,14 +367,6 @@ def test_toLocaleString(): pm.eval("(result, obj) => {result[0] = obj.toLocaleString()}")(result, items) assert result[0] == '[object Object]' -# repr - - -def test_repr_max_recursion_depth(): - subprocess.check_call('npm install crypto-js', shell=True) - CryptoJS = pm.require('crypto-js') - assert str(CryptoJS).__contains__("{'lib': {'Base': {'extend':") - # __class__ def test___class__attribute(): diff --git a/tests/python/test_functions_this.py b/tests/python/test_functions_this.py index d9cbf528..52838781 100644 --- a/tests/python/test_functions_this.py +++ b/tests/python/test_functions_this.py @@ -126,14 +126,6 @@ class Class: # require -def test_require_correct_this(): - subprocess.check_call('npm install crypto-js', shell=True) - CryptoJS = pm.require('crypto-js') - cipher = CryptoJS.SHA256("Hello, World!").toString() - assert cipher == "dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986f" - subprocess.check_call('npm uninstall crypto-js', shell=True) - - def test_require_correct_this_old_style_class(): example = pm.eval(""" () => { @@ -207,7 +199,7 @@ def pyFunc(): def test_method_no_self(): class What: def some_method(): - return 3 + return 3 obj = What() @@ -215,4 +207,4 @@ def some_method(): pm.eval('x => x.some_method()')(obj) assert (False) except pm.SpiderMonkeyError as e: - assert 'takes 0 positional arguments but 1 was given' in str(e) \ No newline at end of file + assert 'takes 0 positional arguments but 1 was given' in str(e) From 42911524a6f27be220ddb4e8e656eaf2577fe80e Mon Sep 17 00:00:00 2001 From: Tom Wenzheng Tang Date: Tue, 17 Jun 2025 14:36:22 -0400 Subject: [PATCH 385/428] chore: fix mixed types in an array in pyproject.toml --- pyproject.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 066ff5d4..0cb6bdd8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,8 +28,9 @@ include = [ { path = "CMakeLists.txt", format = "sdist" }, { path = "*.sh", format = "sdist" }, { path = "mozcentral.version", format = "sdist" }, + # Add marker file for pep561 - "python/pythonmonkey/py.typed", + { path = "python/pythonmonkey/py.typed", format = ["sdist", "wheel"] }, ] From 1021684b944cba1770a073b1c3760c13f47d72c8 Mon Sep 17 00:00:00 2001 From: Tom Wenzheng Tang Date: Tue, 17 Jun 2025 15:18:49 -0400 Subject: [PATCH 386/428] Revert "Write our own minimum copy of npm in Python to remove dependency on Node.js during installation" --- README.md | 1 + python/pminit/pmpm.py | 67 ------------------------------ python/pminit/post-install-hook.py | 42 +++++++++++++++---- python/pminit/pyproject.toml | 1 - 4 files changed, 35 insertions(+), 76 deletions(-) delete mode 100644 python/pminit/pmpm.py diff --git a/README.md b/README.md index 343a73fe..1532ae6f 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,7 @@ Read this if you want to build a local version. - rust - python3.8 or later with header files (python3-dev) - spidermonkey latest from mozilla-central + - npm (nodejs) - [Poetry](https://python-poetry.org/docs/#installation) - [poetry-dynamic-versioning](https://github.com/mtkennerly/poetry-dynamic-versioning) diff --git a/python/pminit/pmpm.py b/python/pminit/pmpm.py deleted file mode 100644 index 59a78a14..00000000 --- a/python/pminit/pmpm.py +++ /dev/null @@ -1,67 +0,0 @@ -# @file pmpm.py -# A minimum copy of npm written in pure Python. -# Currently, this can only install dependencies specified by package-lock.json into node_modules. -# @author Tom Tang -# @date July 2023 - -import json -import io -import os, shutil -import tempfile -import tarfile -from dataclasses import dataclass -import urllib.request -from typing import List, Union - -@dataclass -class PackageItem: - installation_path: str - tarball_url: str - has_install_script: bool - -def parse_package_lock_json(json_data: Union[str, bytes]) -> List[PackageItem]: - # See https://docs.npmjs.com/cli/v9/configuring-npm/package-lock-json#packages - packages: dict = json.loads(json_data)["packages"] - items: List[PackageItem] = [] - for key, entry in packages.items(): - if key == "": - # Skip the root project (listed with a key of "") - continue - items.append( - PackageItem( - installation_path=key, # relative path from the root project folder - # The path is flattened for nested node_modules, e.g., "node_modules/create-ecdh/node_modules/bn.js" - tarball_url=entry["resolved"], # TODO: handle git dependencies - has_install_script=entry.get("hasInstallScript", False) # the package has a preinstall, install, or postinstall script - ) - ) - return items - -def download_package(tarball_url: str) -> bytes: - with urllib.request.urlopen(tarball_url) as response: - tarball_data: bytes = response.read() - return tarball_data - -def unpack_package(work_dir:str, installation_path: str, tarball_data: bytes): - installation_path = os.path.join(work_dir, installation_path) - shutil.rmtree(installation_path, ignore_errors=True) - - with tempfile.TemporaryDirectory(prefix="pmpm_cache-") as tmpdir: - with io.BytesIO(tarball_data) as tar_file: - with tarfile.open(fileobj=tar_file) as tar: - tar.extractall(tmpdir) - shutil.move( - os.path.join(tmpdir, "package"), # Strip the root folder - installation_path - ) - -def main(work_dir: str): - with open(os.path.join(work_dir, "package-lock.json"), encoding="utf-8") as f: - items = parse_package_lock_json(f.read()) - for i in items: - print("Installing " + i.installation_path) - tarball_data = download_package(i.tarball_url) - unpack_package(work_dir, i.installation_path, tarball_data) - -if __name__ == "__main__": - main(os.getcwd()) diff --git a/python/pminit/post-install-hook.py b/python/pminit/post-install-hook.py index 061492c1..1b2d26dd 100644 --- a/python/pminit/post-install-hook.py +++ b/python/pminit/post-install-hook.py @@ -1,13 +1,39 @@ -import os -import pmpm +import subprocess +import sys +import shutil -WORK_DIR = os.path.join( - os.path.realpath(os.path.dirname(__file__)), - "pythonmonkey" -) +def execute(cmd: str): + popen = subprocess.Popen(cmd, stdout = subprocess.PIPE, stderr = subprocess.STDOUT, + shell = True, text = True ) + for stdout_line in iter(popen.stdout.readline, ""): + sys.stdout.write(stdout_line) + sys.stdout.flush() + + popen.stdout.close() + return_code = popen.wait() + if return_code: + raise subprocess.CalledProcessError(return_code, cmd) def main(): - pmpm.main(WORK_DIR) # cd pythonmonkey && npm i + node_package_manager = 'npm' + # check if npm is installed on the system + if (shutil.which(node_package_manager) is None): + print(""" + +PythonMonkey Build Error: + + + * It appears npm is not installed on this system. + * npm is required for PythonMonkey to build. + * Please install NPM and Node.js before installing PythonMonkey. + * Refer to the documentation for installing NPM and Node.js here: https://nodejs.org/en/download + + + """) + raise Exception("PythonMonkey build error: Unable to find npm on the system.") + else: + execute(f"cd pythonmonkey && {node_package_manager} i --no-package-lock") # do not update package-lock.json if __name__ == "__main__": - main() + main() + diff --git a/python/pminit/pyproject.toml b/python/pminit/pyproject.toml index 7c7b84b6..09d28174 100644 --- a/python/pminit/pyproject.toml +++ b/python/pminit/pyproject.toml @@ -11,7 +11,6 @@ documentation = "https://docs.pythonmonkey.io/" repository = "https://github.com/Distributive-Network/PythonMonkey" include = [ - "pmpm.py", # Install extra files into the pythonmonkey package "pythonmonkey/package*.json", { path = "pythonmonkey/node_modules/**/*", format = "wheel" }, From 29e7b8559bb152abe45381a149bfb361cdc90a29 Mon Sep 17 00:00:00 2001 From: Tom Wenzheng Tang Date: Sat, 12 Jul 2025 09:13:01 -0400 Subject: [PATCH 387/428] feat(CI): nodejs is required to build pminit --- .github/workflows/test-and-publish.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 337e85f6..ad81d8bd 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -154,6 +154,7 @@ jobs: apt-get update -y apt-get install -y sudo libnss3-dev libssl-dev apt-get install -y git # required for `actions/checkout` + apt-get install -y nodejs npm # required for pminit to build apt-get install -y build-essential apt-get install -y strace # required to run JS tests DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends tzdata # tzdata may ask for user interaction if not explicitly installed here From c5b0ddaf17f055dcc4e860c43ddb98d621ef19f1 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Sat, 12 Jul 2025 13:57:10 +0000 Subject: [PATCH 388/428] feat(CI): upload spidermonkey build as CI artifacts --- .github/workflows/test-and-publish.yaml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index ad81d8bd..305d7a34 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -83,7 +83,6 @@ jobs: path: | ./_spidermonkey_install/* key: spidermonkey-${{ env.MOZCENTRAL_VERSION }}-${{ runner.os }}-${{ runner.arch }} - lookup-only: true # skip download - name: Setup container if: ${{ matrix.os == 'ubuntu-22.04' && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} run: | @@ -102,6 +101,11 @@ jobs: - name: Build spidermonkey if: ${{ steps.cache-spidermonkey.outputs.cache-hit != 'true' }} run: ./setup.sh + - name: Upload spidermonkey build as CI artifacts + uses: actions/upload-artifact@v4 + with: + name: spidermonkey-${{ env.MOZCENTRAL_VERSION }}-${{ runner.os }}-${{ runner.arch }} + path: ./_spidermonkey_install/ build-spidermonkey-win: runs-on: windows-2022 # SpiderMonkey requires Visual Studio 2022 or newer. @@ -117,7 +121,6 @@ jobs: path: | ./_spidermonkey_install/* key: spidermonkey-${{ env.MOZCENTRAL_VERSION }}-${{ runner.os }}-${{ runner.arch }} - lookup-only: true # skip download - name: Install dependencies if: ${{ steps.cache-spidermonkey.outputs.cache-hit != 'true' }} shell: powershell @@ -138,6 +141,11 @@ jobs: # see https://groups.google.com/u/1/a/mozilla.org/g/dev-platform/c/hF51Q3j6ca8 USE_MINTTY: 0 run: /c/mozilla-build/start-shell.bat -use-full-path -here ./setup.sh + - name: Upload spidermonkey build as CI artifacts + uses: actions/upload-artifact@v4 + with: + name: spidermonkey-${{ env.MOZCENTRAL_VERSION }}-${{ runner.os }}-${{ runner.arch }} + path: ./_spidermonkey_install/ build-and-test: needs: [build-spidermonkey-unix, build-spidermonkey-win] strategy: From 6849db8606e964610587e51346507a54ee5a480e Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Mon, 14 Jul 2025 09:26:01 -0400 Subject: [PATCH 389/428] fix the embedded null character issue SpiderMonkey doesn't store the extra null character while some Python APIs assume the string buffer is null-terminated. The issue hasn't been a problem before because it somehow didn't allocate the buffer that follows, making the string buffer null-terminated effectively. --- src/StrType.cc | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/StrType.cc b/src/StrType.cc index 7df301bd..1c9ac772 100644 --- a/src/StrType.cc +++ b/src/StrType.cc @@ -135,6 +135,12 @@ PyObject *StrType::proxifyString(JSContext *cx, JS::HandleValue strVal) { if (JS::LinearStringHasLatin1Chars(lstr)) { // latin1 spidermonkey, latin1 python const JS::Latin1Char *chars = JS::GetLatin1LinearStringChars(nogc, lstr); + if (chars[length] != 0) { // not a null-terminated string + // most Python C APIs assume the string buffer is null-terminated, so we need to create a copy + PyObject *copied = PyUnicode_FromObject(pyString); // create a copy when it's not a true Unicode object + Py_DECREF(pyString); + return copied; + } PY_UNICODE_OBJECT_DATA_ANY(pyString) = (void *)chars; PY_UNICODE_OBJECT_KIND(pyString) = PyUnicode_1BYTE_KIND; @@ -157,6 +163,11 @@ PyObject *StrType::proxifyString(JSContext *cx, JS::HandleValue strVal) { } else { // utf16 spidermonkey, ucs2 python const char16_t *chars = JS::GetTwoByteLinearStringChars(nogc, lstr); + if (chars[length] != 0) { // not a null-terminated string + PyObject *copied = PyUnicode_FromObject(pyString); + Py_DECREF(pyString); + return copied; + } PY_UNICODE_OBJECT_DATA_ANY(pyString) = (void *)chars; PY_UNICODE_OBJECT_KIND(pyString) = PyUnicode_2BYTE_KIND; From 79cd32b45538a17ef4320ab65f531a0723961dcc Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Mon, 14 Jul 2025 09:43:27 -0400 Subject: [PATCH 390/428] chore(CI): setup Python using pyenv --- .github/workflows/test-and-publish.yaml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 305d7a34..dd83c857 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -179,7 +179,20 @@ jobs: submodules: recursive fetch-depth: 0 # fetch all history for all branches and tags # poetry-dynamic-versioning needs git tags to produce the correct version number + - name: Setup Python + if: ${{ runner.os == 'Linux' }} + run: | + # Use pyenv to install Python version that is not available via `actions/setup-python` + curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash + echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc + echo '[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc + echo 'eval "$(pyenv init - bash)"' >> ~/.bashrc + pyenv install $PYTHON_VERSION + pyenv global $PYTHON_VERSION + env: + PYTHON_VERSION: ${{ matrix.python_version }} - uses: actions/setup-python@v5 + if: ${{ runner.os != 'Linux' }} with: python-version: ${{ matrix.python_version }} - name: Setup Poetry From f8efe5e824b9cda8b3ce330374152ffbd208e565 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Mon, 14 Jul 2025 09:50:40 -0400 Subject: [PATCH 391/428] fix ci --- .github/workflows/test-and-publish.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index dd83c857..2d3c8823 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -187,6 +187,7 @@ jobs: echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc echo '[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc echo 'eval "$(pyenv init - bash)"' >> ~/.bashrc + source ~/.bashrc pyenv install $PYTHON_VERSION pyenv global $PYTHON_VERSION env: From 1449faef9e6b29ef7be5c2fe9a8d48e9c98bbc22 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Mon, 14 Jul 2025 09:54:44 -0400 Subject: [PATCH 392/428] fix ci --- .github/workflows/test-and-publish.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 2d3c8823..42ed784f 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -183,11 +183,12 @@ jobs: if: ${{ runner.os == 'Linux' }} run: | # Use pyenv to install Python version that is not available via `actions/setup-python` + unset PYENV_ROOT curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc echo '[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc echo 'eval "$(pyenv init - bash)"' >> ~/.bashrc - source ~/.bashrc + export PATH="$HOME/.pyenv/bin:$PATH" pyenv install $PYTHON_VERSION pyenv global $PYTHON_VERSION env: From 36daa908d800804ed50580115c365f18d55e7923 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Mon, 14 Jul 2025 10:12:53 -0400 Subject: [PATCH 393/428] fix CI Setup container --- .github/workflows/test-and-publish.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 42ed784f..2780ea1e 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -160,7 +160,8 @@ jobs: if: ${{ matrix.os == 'ubuntu-22.04' }} run: | apt-get update -y - apt-get install -y sudo libnss3-dev libssl-dev + apt-get install -y sudo curl libnss3-dev libssl-dev + apt-get install -y zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev # required for pyenv apt-get install -y git # required for `actions/checkout` apt-get install -y nodejs npm # required for pminit to build apt-get install -y build-essential From 25ea0eac367729b404a0ca748eab4ad1585b8658 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Mon, 14 Jul 2025 10:28:10 -0400 Subject: [PATCH 394/428] fix ci --- .github/workflows/test-and-publish.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 2780ea1e..d2cda65e 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -160,8 +160,8 @@ jobs: if: ${{ matrix.os == 'ubuntu-22.04' }} run: | apt-get update -y - apt-get install -y sudo curl libnss3-dev libssl-dev - apt-get install -y zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev # required for pyenv + apt-get install -y sudo libnss3-dev libssl-dev + apt-get install -y curl python3 zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev # required for pyenv apt-get install -y git # required for `actions/checkout` apt-get install -y nodejs npm # required for pminit to build apt-get install -y build-essential From ed90f47975c35b8c334df77abc36904f598c48c7 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Mon, 14 Jul 2025 10:40:34 -0400 Subject: [PATCH 395/428] fix ci --- .github/workflows/test-and-publish.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index d2cda65e..8bb0a197 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -198,10 +198,15 @@ jobs: if: ${{ runner.os != 'Linux' }} with: python-version: ${{ matrix.python_version }} + - run: | + source ~/.bashrc || true # load pyenv into the current shell + python --version + python3 --version - name: Setup Poetry uses: snok/install-poetry@v1 with: version: 1.5.1 + virtualenvs-create: false - name: Install Dependencies run: | echo "Installing Dependencies" From 4858659582b1db8a33b9abd5c2af4ebacbe1ac62 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Mon, 14 Jul 2025 11:05:55 -0400 Subject: [PATCH 396/428] bashrc file is not read, so we need to add to GITHUB_PATH manually --- .github/workflows/test-and-publish.yaml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 8bb0a197..1ec1896d 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -161,7 +161,7 @@ jobs: run: | apt-get update -y apt-get install -y sudo libnss3-dev libssl-dev - apt-get install -y curl python3 zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev # required for pyenv + apt-get install -y curl zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev # required for pyenv apt-get install -y git # required for `actions/checkout` apt-get install -y nodejs npm # required for pminit to build apt-get install -y build-essential @@ -186,9 +186,9 @@ jobs: # Use pyenv to install Python version that is not available via `actions/setup-python` unset PYENV_ROOT curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash - echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc - echo '[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc - echo 'eval "$(pyenv init - bash)"' >> ~/.bashrc + echo "$HOME/.pyenv/bin" >> $GITHUB_PATH # ~/.bashrc file is not read, so we need to add to GITHUB_PATH manually + echo "$HOME/.pyenv/shims" >> $GITHUB_PATH + echo "PYENV_ROOT=$HOME/.pyenv" >> $GITHUB_ENV export PATH="$HOME/.pyenv/bin:$PATH" pyenv install $PYTHON_VERSION pyenv global $PYTHON_VERSION @@ -199,14 +199,12 @@ jobs: with: python-version: ${{ matrix.python_version }} - run: | - source ~/.bashrc || true # load pyenv into the current shell python --version python3 --version - name: Setup Poetry uses: snok/install-poetry@v1 with: version: 1.5.1 - virtualenvs-create: false - name: Install Dependencies run: | echo "Installing Dependencies" From 79e00fcbde4c41f4d5874f0a2503ce7005bf1b4b Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Mon, 14 Jul 2025 11:38:10 -0400 Subject: [PATCH 397/428] try running a Ubuntu 20.04 container on arm64 Linux --- .github/workflows/test-and-publish.yaml | 28 ++++++++++++++++++------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 1ec1896d..b97496c6 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -71,7 +71,7 @@ jobs: # see https://github.blog/changelog/2024-01-30-github-actions-macos-14-sonoma-is-now-available python_version: [ '3.10' ] runs-on: ${{ matrix.os }} - container: ${{ (matrix.os == 'ubuntu-22.04' && 'ubuntu:20.04') || null }} # Use the Ubuntu 20.04 container inside Ubuntu 22.04 runner to build + container: ${{ ( runner.os == 'Linux' && 'ubuntu:20.04') || null }} # Use the Ubuntu 20.04 container inside Ubuntu 22.04 runner to build steps: - uses: actions/checkout@v4 - name: Read the mozilla-central commit hash to be used @@ -84,14 +84,29 @@ jobs: ./_spidermonkey_install/* key: spidermonkey-${{ env.MOZCENTRAL_VERSION }}-${{ runner.os }}-${{ runner.arch }} - name: Setup container - if: ${{ matrix.os == 'ubuntu-22.04' && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} + if: ${{ runner.os == 'Linux' && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} run: | apt-get update -y apt-get install -y sudo libnss3-dev libssl-dev + apt-get install -y curl zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev # required for pyenv DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends tzdata echo "AGENT_TOOLSDIRECTORY=/" >> $GITHUB_ENV # do not use the Python installation cached for Ubuntu 22.04 + - name: Setup Python + if: ${{ runner.os == 'Linux' && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} + run: | + # Use pyenv to install Python version that is not available via `actions/setup-python` + unset PYENV_ROOT + curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash + echo "$HOME/.pyenv/bin" >> $GITHUB_PATH # ~/.bashrc file is not read, so we need to add to GITHUB_PATH manually + echo "$HOME/.pyenv/shims" >> $GITHUB_PATH + echo "PYENV_ROOT=$HOME/.pyenv" >> $GITHUB_ENV + export PATH="$HOME/.pyenv/bin:$PATH" + pyenv install $PYTHON_VERSION + pyenv global $PYTHON_VERSION + env: + PYTHON_VERSION: ${{ matrix.python_version }} - uses: actions/setup-python@v5 - if: ${{ steps.cache-spidermonkey.outputs.cache-hit != 'true' }} + if: ${{ runner.os != 'Linux' && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} with: python-version: ${{ matrix.python_version }} - name: Setup XCode @@ -154,10 +169,10 @@ jobs: os: [ 'ubuntu-22.04', 'macos-13', 'macos-14', 'windows-2022', 'ubuntu-22.04-arm' ] python_version: [ '3.8', '3.9', '3.10', '3.11', '3.12', '3.13' ] runs-on: ${{ matrix.os }} - container: ${{ (matrix.os == 'ubuntu-22.04' && 'ubuntu:20.04') || null }} + container: ${{ (runner.os == 'Linux' && 'ubuntu:20.04') || null }} steps: - name: Setup container - if: ${{ matrix.os == 'ubuntu-22.04' }} + if: ${{ runner.os == 'Linux' }} run: | apt-get update -y apt-get install -y sudo libnss3-dev libssl-dev @@ -198,9 +213,6 @@ jobs: if: ${{ runner.os != 'Linux' }} with: python-version: ${{ matrix.python_version }} - - run: | - python --version - python3 --version - name: Setup Poetry uses: snok/install-poetry@v1 with: From f2c84429f721e96f9b4f76e9f95f90ec0038ee73 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Mon, 14 Jul 2025 11:42:39 -0400 Subject: [PATCH 398/428] fix ci container --- .github/workflows/test-and-publish.yaml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index b97496c6..6705480a 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -71,7 +71,7 @@ jobs: # see https://github.blog/changelog/2024-01-30-github-actions-macos-14-sonoma-is-now-available python_version: [ '3.10' ] runs-on: ${{ matrix.os }} - container: ${{ ( runner.os == 'Linux' && 'ubuntu:20.04') || null }} # Use the Ubuntu 20.04 container inside Ubuntu 22.04 runner to build + container: ${{ (startsWith(matrix.os, 'ubuntu') && 'ubuntu:20.04') || null }} # Use the Ubuntu 20.04 container inside Ubuntu 22.04 runner to build steps: - uses: actions/checkout@v4 - name: Read the mozilla-central commit hash to be used @@ -84,7 +84,7 @@ jobs: ./_spidermonkey_install/* key: spidermonkey-${{ env.MOZCENTRAL_VERSION }}-${{ runner.os }}-${{ runner.arch }} - name: Setup container - if: ${{ runner.os == 'Linux' && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} + if: ${{ startsWith(matrix.os, 'ubuntu') && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} run: | apt-get update -y apt-get install -y sudo libnss3-dev libssl-dev @@ -92,7 +92,7 @@ jobs: DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends tzdata echo "AGENT_TOOLSDIRECTORY=/" >> $GITHUB_ENV # do not use the Python installation cached for Ubuntu 22.04 - name: Setup Python - if: ${{ runner.os == 'Linux' && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} + if: ${{ startsWith(matrix.os, 'ubuntu') && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} run: | # Use pyenv to install Python version that is not available via `actions/setup-python` unset PYENV_ROOT @@ -106,7 +106,7 @@ jobs: env: PYTHON_VERSION: ${{ matrix.python_version }} - uses: actions/setup-python@v5 - if: ${{ runner.os != 'Linux' && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} + if: ${{ !startsWith(matrix.os, 'ubuntu') && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} with: python-version: ${{ matrix.python_version }} - name: Setup XCode @@ -169,10 +169,10 @@ jobs: os: [ 'ubuntu-22.04', 'macos-13', 'macos-14', 'windows-2022', 'ubuntu-22.04-arm' ] python_version: [ '3.8', '3.9', '3.10', '3.11', '3.12', '3.13' ] runs-on: ${{ matrix.os }} - container: ${{ (runner.os == 'Linux' && 'ubuntu:20.04') || null }} + container: ${{ (startsWith(matrix.os, 'ubuntu') && 'ubuntu:20.04') || null }} steps: - name: Setup container - if: ${{ runner.os == 'Linux' }} + if: ${{ startsWith(matrix.os, 'ubuntu') }} run: | apt-get update -y apt-get install -y sudo libnss3-dev libssl-dev @@ -196,7 +196,7 @@ jobs: fetch-depth: 0 # fetch all history for all branches and tags # poetry-dynamic-versioning needs git tags to produce the correct version number - name: Setup Python - if: ${{ runner.os == 'Linux' }} + if: ${{ startsWith(matrix.os, 'ubuntu') }} run: | # Use pyenv to install Python version that is not available via `actions/setup-python` unset PYENV_ROOT @@ -210,7 +210,7 @@ jobs: env: PYTHON_VERSION: ${{ matrix.python_version }} - uses: actions/setup-python@v5 - if: ${{ runner.os != 'Linux' }} + if: ${{ !startsWith(matrix.os, 'ubuntu') }} with: python-version: ${{ matrix.python_version }} - name: Setup Poetry From 150eea21bd31ed194e54116c620575b4bc9f42b1 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Mon, 14 Jul 2025 11:46:50 -0400 Subject: [PATCH 399/428] fix ci --- .github/workflows/test-and-publish.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 6705480a..c7a8d27e 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -88,7 +88,8 @@ jobs: run: | apt-get update -y apt-get install -y sudo libnss3-dev libssl-dev - apt-get install -y curl zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev # required for pyenv + apt-get install -y curl make git build-essential + apt-get install -y zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev # required for pyenv DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends tzdata echo "AGENT_TOOLSDIRECTORY=/" >> $GITHUB_ENV # do not use the Python installation cached for Ubuntu 22.04 - name: Setup Python From 33b8765ccff6999dc34cbf7383553f85a6686959 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Mon, 14 Jul 2025 13:21:19 -0400 Subject: [PATCH 400/428] chore(CI): install LLVM 18 --- .github/workflows/test-and-publish.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index c7a8d27e..d9d726c5 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -92,6 +92,12 @@ jobs: apt-get install -y zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev # required for pyenv DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends tzdata echo "AGENT_TOOLSDIRECTORY=/" >> $GITHUB_ENV # do not use the Python installation cached for Ubuntu 22.04 + - name: Setup LLVM + if: ${{ startsWith(matrix.os, 'ubuntu') && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} + run: | + wget https://apt.llvm.org/llvm.sh + chmod +x llvm.sh + ./llvm.sh 18 # install LLVM version 18 - name: Setup Python if: ${{ startsWith(matrix.os, 'ubuntu') && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} run: | From 120288848facc53bd72be8d57b9286bce8719643 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Mon, 14 Jul 2025 13:27:21 -0400 Subject: [PATCH 401/428] fix ci --- .github/workflows/test-and-publish.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index d9d726c5..5669b64a 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -88,7 +88,7 @@ jobs: run: | apt-get update -y apt-get install -y sudo libnss3-dev libssl-dev - apt-get install -y curl make git build-essential + apt-get install -y curl wget make git build-essential apt-get install -y zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev # required for pyenv DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends tzdata echo "AGENT_TOOLSDIRECTORY=/" >> $GITHUB_ENV # do not use the Python installation cached for Ubuntu 22.04 From ed68856615fabf204d9c1e2e0528a443841750cf Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Mon, 14 Jul 2025 13:40:15 -0400 Subject: [PATCH 402/428] fix ci --- .github/workflows/test-and-publish.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 5669b64a..7fe65f59 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -88,13 +88,14 @@ jobs: run: | apt-get update -y apt-get install -y sudo libnss3-dev libssl-dev - apt-get install -y curl wget make git build-essential + apt-get install -y curl make git build-essential apt-get install -y zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev # required for pyenv DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends tzdata echo "AGENT_TOOLSDIRECTORY=/" >> $GITHUB_ENV # do not use the Python installation cached for Ubuntu 22.04 - name: Setup LLVM if: ${{ startsWith(matrix.os, 'ubuntu') && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} run: | + apt-get install -y lsb-release wget wget https://apt.llvm.org/llvm.sh chmod +x llvm.sh ./llvm.sh 18 # install LLVM version 18 From a030d747d0b5da6b105dcb4aee403251b2c76741 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Mon, 14 Jul 2025 13:43:26 -0400 Subject: [PATCH 403/428] fix ci --- .github/workflows/test-and-publish.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 7fe65f59..e173f71a 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -95,7 +95,7 @@ jobs: - name: Setup LLVM if: ${{ startsWith(matrix.os, 'ubuntu') && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} run: | - apt-get install -y lsb-release wget + apt-get install -y lsb-release wget software-properties-common gnupg wget https://apt.llvm.org/llvm.sh chmod +x llvm.sh ./llvm.sh 18 # install LLVM version 18 From d20db24a9dee8a1fca7bbf83aded07cb5fb9b29d Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Mon, 14 Jul 2025 14:06:00 -0400 Subject: [PATCH 404/428] fix ci --- .github/workflows/test-and-publish.yaml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index e173f71a..30997e80 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -96,9 +96,10 @@ jobs: if: ${{ startsWith(matrix.os, 'ubuntu') && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} run: | apt-get install -y lsb-release wget software-properties-common gnupg - wget https://apt.llvm.org/llvm.sh - chmod +x llvm.sh - ./llvm.sh 18 # install LLVM version 18 + echo "deb http://apt.llvm.org/$(lsb_release -cs)/ llvm-toolchain-$(lsb_release -cs) main" | tee -a /etc/apt/sources.list.d/llvm.list + echo "deb http://apt.llvm.org/$(lsb_release -cs)/ llvm-defaults main" | tee -a /etc/apt/sources.list.d/llvm.list + apt-get update -y + apt-get install -y llvm-defaults clang - name: Setup Python if: ${{ startsWith(matrix.os, 'ubuntu') && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} run: | From a6b7696657b1add720bca981701dcd9553e3490d Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Mon, 14 Jul 2025 14:43:42 -0400 Subject: [PATCH 405/428] fix ci --- .github/workflows/test-and-publish.yaml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 30997e80..89354836 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -96,10 +96,12 @@ jobs: if: ${{ startsWith(matrix.os, 'ubuntu') && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} run: | apt-get install -y lsb-release wget software-properties-common gnupg - echo "deb http://apt.llvm.org/$(lsb_release -cs)/ llvm-toolchain-$(lsb_release -cs) main" | tee -a /etc/apt/sources.list.d/llvm.list - echo "deb http://apt.llvm.org/$(lsb_release -cs)/ llvm-defaults main" | tee -a /etc/apt/sources.list.d/llvm.list - apt-get update -y - apt-get install -y llvm-defaults clang + wget https://apt.llvm.org/llvm.sh + chmod +x llvm.sh + ./llvm.sh 18 # install LLVM version 18 + update-alternatives --install /usr/bin/llvm-config llvm-config /usr/bin/llvm-config-18 18 + update-alternatives --install /usr/bin/clang clang /usr/bin/clang-18 18 + update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-18 18 - name: Setup Python if: ${{ startsWith(matrix.os, 'ubuntu') && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} run: | From acade44b8c6adb3931cae7017593b9fcb944f93e Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Mon, 14 Jul 2025 16:36:20 -0400 Subject: [PATCH 406/428] fix ci --- .github/workflows/test-and-publish.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 89354836..9ba24ba2 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -95,6 +95,7 @@ jobs: - name: Setup LLVM if: ${{ startsWith(matrix.os, 'ubuntu') && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} run: | + apt-get install -y clang clang++ apt-get install -y lsb-release wget software-properties-common gnupg wget https://apt.llvm.org/llvm.sh chmod +x llvm.sh @@ -102,6 +103,8 @@ jobs: update-alternatives --install /usr/bin/llvm-config llvm-config /usr/bin/llvm-config-18 18 update-alternatives --install /usr/bin/clang clang /usr/bin/clang-18 18 update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-18 18 + clang --version + clang++ --version - name: Setup Python if: ${{ startsWith(matrix.os, 'ubuntu') && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} run: | From a4987171706eedccf1020f51dd2ea57bbbb3e6e4 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Mon, 14 Jul 2025 17:04:22 -0400 Subject: [PATCH 407/428] fix ci --- .github/workflows/test-and-publish.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 9ba24ba2..109561f8 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -95,7 +95,7 @@ jobs: - name: Setup LLVM if: ${{ startsWith(matrix.os, 'ubuntu') && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} run: | - apt-get install -y clang clang++ + apt-get install -y llvm clang apt-get install -y lsb-release wget software-properties-common gnupg wget https://apt.llvm.org/llvm.sh chmod +x llvm.sh From d3ea2ecbbbfbd4b1c8171e734afb45332f89cdec Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Fri, 18 Jul 2025 11:29:39 -0400 Subject: [PATCH 408/428] fix(string): short path to fix the `embedded null character` issue with Python 3.13+ --- src/StrType.cc | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/StrType.cc b/src/StrType.cc index 1c9ac772..32323fba 100644 --- a/src/StrType.cc +++ b/src/StrType.cc @@ -135,9 +135,11 @@ PyObject *StrType::proxifyString(JSContext *cx, JS::HandleValue strVal) { if (JS::LinearStringHasLatin1Chars(lstr)) { // latin1 spidermonkey, latin1 python const JS::Latin1Char *chars = JS::GetLatin1LinearStringChars(nogc, lstr); - if (chars[length] != 0) { // not a null-terminated string - // most Python C APIs assume the string buffer is null-terminated, so we need to create a copy - PyObject *copied = PyUnicode_FromObject(pyString); // create a copy when it's not a true Unicode object + if (Py_Version >= 0x030d0000) { // Python version is greater than 3.13 + // Short path to temporarily fix the issue with Python 3.13+ compact unicode representation. + // It would error with `ValueError: embedded null character`, which is caused by the fact that + // most Python C APIs assume the string buffer is null-terminated, so we need to create a copy. + PyObject *copied = PyUnicode_FromObject((PyObject *)pyString); // create a copy when it's not a true Unicode object Py_DECREF(pyString); return copied; } @@ -163,8 +165,8 @@ PyObject *StrType::proxifyString(JSContext *cx, JS::HandleValue strVal) { } else { // utf16 spidermonkey, ucs2 python const char16_t *chars = JS::GetTwoByteLinearStringChars(nogc, lstr); - if (chars[length] != 0) { // not a null-terminated string - PyObject *copied = PyUnicode_FromObject(pyString); + if (Py_Version >= 0x030d0000) { // Python 3.13+, see above + PyObject *copied = PyUnicode_FromObject((PyObject *)pyString); // create a copy when it's not a true Unicode object Py_DECREF(pyString); return copied; } From bf049a7fed7c462b623738bb18907e3264af0d22 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Fri, 18 Jul 2025 11:40:53 -0400 Subject: [PATCH 409/428] fix(string): `Py_Version` is only available on Python 3.11+ --- src/StrType.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/StrType.cc b/src/StrType.cc index 32323fba..0c384d51 100644 --- a/src/StrType.cc +++ b/src/StrType.cc @@ -135,7 +135,7 @@ PyObject *StrType::proxifyString(JSContext *cx, JS::HandleValue strVal) { if (JS::LinearStringHasLatin1Chars(lstr)) { // latin1 spidermonkey, latin1 python const JS::Latin1Char *chars = JS::GetLatin1LinearStringChars(nogc, lstr); - if (Py_Version >= 0x030d0000) { // Python version is greater than 3.13 + if ((PY_VERSION_HEX) >= 0x030d0000) { // Python version is greater than 3.13 // Short path to temporarily fix the issue with Python 3.13+ compact unicode representation. // It would error with `ValueError: embedded null character`, which is caused by the fact that // most Python C APIs assume the string buffer is null-terminated, so we need to create a copy. @@ -165,7 +165,7 @@ PyObject *StrType::proxifyString(JSContext *cx, JS::HandleValue strVal) { } else { // utf16 spidermonkey, ucs2 python const char16_t *chars = JS::GetTwoByteLinearStringChars(nogc, lstr); - if (Py_Version >= 0x030d0000) { // Python 3.13+, see above + if ((PY_VERSION_HEX) >= 0x030d0000) { // Python 3.13+, see above PyObject *copied = PyUnicode_FromObject((PyObject *)pyString); // create a copy when it's not a true Unicode object Py_DECREF(pyString); return copied; From adb18fbce3dda1f54f70b84082cbd2be811ee029 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Sat, 19 Jul 2025 07:38:11 -0400 Subject: [PATCH 410/428] fix(string): short path to convert strings --- src/StrType.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/StrType.cc b/src/StrType.cc index 0c384d51..18ecce09 100644 --- a/src/StrType.cc +++ b/src/StrType.cc @@ -139,7 +139,7 @@ PyObject *StrType::proxifyString(JSContext *cx, JS::HandleValue strVal) { // Short path to temporarily fix the issue with Python 3.13+ compact unicode representation. // It would error with `ValueError: embedded null character`, which is caused by the fact that // most Python C APIs assume the string buffer is null-terminated, so we need to create a copy. - PyObject *copied = PyUnicode_FromObject((PyObject *)pyString); // create a copy when it's not a true Unicode object + PyObject *copied = PyUnicode_FromKindAndData(PyUnicode_1BYTE_KIND, chars, length); Py_DECREF(pyString); return copied; } @@ -166,7 +166,7 @@ PyObject *StrType::proxifyString(JSContext *cx, JS::HandleValue strVal) { else { // utf16 spidermonkey, ucs2 python const char16_t *chars = JS::GetTwoByteLinearStringChars(nogc, lstr); if ((PY_VERSION_HEX) >= 0x030d0000) { // Python 3.13+, see above - PyObject *copied = PyUnicode_FromObject((PyObject *)pyString); // create a copy when it's not a true Unicode object + PyObject *copied = PyUnicode_FromKindAndData(PyUnicode_2BYTE_KIND, chars, length); Py_DECREF(pyString); return copied; } From e3410eddd0e92a13ec0408d20e5a18c77851405b Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Sat, 19 Jul 2025 09:34:05 -0400 Subject: [PATCH 411/428] fix(string): fix utf16 strings that contain surrogate pairs --- src/StrType.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/StrType.cc b/src/StrType.cc index 18ecce09..a5c65788 100644 --- a/src/StrType.cc +++ b/src/StrType.cc @@ -165,11 +165,6 @@ PyObject *StrType::proxifyString(JSContext *cx, JS::HandleValue strVal) { } else { // utf16 spidermonkey, ucs2 python const char16_t *chars = JS::GetTwoByteLinearStringChars(nogc, lstr); - if ((PY_VERSION_HEX) >= 0x030d0000) { // Python 3.13+, see above - PyObject *copied = PyUnicode_FromKindAndData(PyUnicode_2BYTE_KIND, chars, length); - Py_DECREF(pyString); - return copied; - } PY_UNICODE_OBJECT_DATA_ANY(pyString) = (void *)chars; PY_UNICODE_OBJECT_KIND(pyString) = PyUnicode_2BYTE_KIND; @@ -202,6 +197,11 @@ PyObject *StrType::proxifyString(JSContext *cx, JS::HandleValue strVal) { Py_DECREF(pyString); return ucs4Obj; } + if ((PY_VERSION_HEX) >= 0x030d0000) { // Python 3.13+, fix `ValueError: embedded null character` + PyObject *copied = PyUnicode_FromKindAndData(PyUnicode_2BYTE_KIND, chars, length); // create a copy of the string buffer + Py_DECREF(pyString); + return copied; + } } return (PyObject *)pyString; From bf3f944ad7f89285e7f09d94d2479c5fa5b69d3d Mon Sep 17 00:00:00 2001 From: Dan <119429186+dan-distributive@users.noreply.github.com> Date: Tue, 19 Aug 2025 09:06:32 -0400 Subject: [PATCH 412/428] Update README.md changed [90%] to [done] regarding pythonmonkey's ability to run dcp-client.js (last item in the roadmap) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1532ae6f..31e6efac 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ js_eval("console.log")('hello, world') - [done] JS TypedArrays coerce to Python TypeArrays - [done] Python lists coerce to JS Arrays - [done] JS arrays coerce to Python lists -- [90%] PythonMonkey can run the dcp-client npm package from Distributive. +- [done] PythonMonkey can run the dcp-client npm package from Distributive. ## Build Instructions From 69be8e1aaf4b3f535fb7986687e6ff6c9cab8213 Mon Sep 17 00:00:00 2001 From: Tom Wenzheng Tang Date: Fri, 19 Sep 2025 04:07:23 +0800 Subject: [PATCH 413/428] Add Python version 3.14 to CI --- .github/workflows/test-and-publish.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 109561f8..f5edfef9 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -31,6 +31,7 @@ on: - '3.11' - '3.12' - '3.13' + - '3.14' build_type: type: choice description: 'Choose the build type to use' @@ -181,7 +182,7 @@ jobs: fail-fast: false matrix: os: [ 'ubuntu-22.04', 'macos-13', 'macos-14', 'windows-2022', 'ubuntu-22.04-arm' ] - python_version: [ '3.8', '3.9', '3.10', '3.11', '3.12', '3.13' ] + python_version: [ '3.8', '3.9', '3.10', '3.11', '3.12', '3.13', '3.14' ] runs-on: ${{ matrix.os }} container: ${{ (startsWith(matrix.os, 'ubuntu') && 'ubuntu:20.04') || null }} steps: From f8dbbecb634ca01d825c33551f8c2775af17e4c8 Mon Sep 17 00:00:00 2001 From: Tom Wenzheng Tang Date: Fri, 19 Sep 2025 04:32:40 +0800 Subject: [PATCH 414/428] `3.14-dev` flag is required to use Python 3.14 in CI as it's not released yet --- .github/workflows/test-and-publish.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index f5edfef9..a0c320e2 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -31,7 +31,7 @@ on: - '3.11' - '3.12' - '3.13' - - '3.14' + - '3.14-dev' build_type: type: choice description: 'Choose the build type to use' @@ -182,7 +182,7 @@ jobs: fail-fast: false matrix: os: [ 'ubuntu-22.04', 'macos-13', 'macos-14', 'windows-2022', 'ubuntu-22.04-arm' ] - python_version: [ '3.8', '3.9', '3.10', '3.11', '3.12', '3.13', '3.14' ] + python_version: [ '3.8', '3.9', '3.10', '3.11', '3.12', '3.13', '3.14-dev' ] runs-on: ${{ matrix.os }} container: ${{ (startsWith(matrix.os, 'ubuntu') && 'ubuntu:20.04') || null }} steps: From 32369f4fc70abf9bfb03da38e90a6fbaffdadd58 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Thu, 18 Sep 2025 20:48:59 +0000 Subject: [PATCH 415/428] chore: upgrade numpy for Python 3.14 --- poetry.lock | 1396 +++++++++++++++++++++++++++++------------------- pyproject.toml | 3 +- 2 files changed, 836 insertions(+), 563 deletions(-) diff --git a/poetry.lock b/poetry.lock index 29419286..6bf2a192 100644 --- a/poetry.lock +++ b/poetry.lock @@ -16,126 +16,126 @@ pycares = ">=4.0.0" [[package]] name = "aiohappyeyeballs" -version = "2.4.0" +version = "2.4.4" description = "Happy Eyeballs for asyncio" optional = false python-versions = ">=3.8" files = [ - {file = "aiohappyeyeballs-2.4.0-py3-none-any.whl", hash = "sha256:7ce92076e249169a13c2f49320d1967425eaf1f407522d707d59cac7628d62bd"}, - {file = "aiohappyeyeballs-2.4.0.tar.gz", hash = "sha256:55a1714f084e63d49639800f95716da97a1f173d46a16dfcfda0016abb93b6b2"}, + {file = "aiohappyeyeballs-2.4.4-py3-none-any.whl", hash = "sha256:a980909d50efcd44795c4afeca523296716d50cd756ddca6af8c65b996e27de8"}, + {file = "aiohappyeyeballs-2.4.4.tar.gz", hash = "sha256:5fdd7d87889c63183afc18ce9271f9b0a7d32c2303e394468dd45d514a757745"}, ] [[package]] name = "aiohttp" -version = "3.10.5" +version = "3.10.11" description = "Async http client/server framework (asyncio)" optional = false python-versions = ">=3.8" files = [ - {file = "aiohttp-3.10.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:18a01eba2574fb9edd5f6e5fb25f66e6ce061da5dab5db75e13fe1558142e0a3"}, - {file = "aiohttp-3.10.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:94fac7c6e77ccb1ca91e9eb4cb0ac0270b9fb9b289738654120ba8cebb1189c6"}, - {file = "aiohttp-3.10.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2f1f1c75c395991ce9c94d3e4aa96e5c59c8356a15b1c9231e783865e2772699"}, - {file = "aiohttp-3.10.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f7acae3cf1a2a2361ec4c8e787eaaa86a94171d2417aae53c0cca6ca3118ff6"}, - {file = "aiohttp-3.10.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:94c4381ffba9cc508b37d2e536b418d5ea9cfdc2848b9a7fea6aebad4ec6aac1"}, - {file = "aiohttp-3.10.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c31ad0c0c507894e3eaa843415841995bf8de4d6b2d24c6e33099f4bc9fc0d4f"}, - {file = "aiohttp-3.10.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0912b8a8fadeb32ff67a3ed44249448c20148397c1ed905d5dac185b4ca547bb"}, - {file = "aiohttp-3.10.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d93400c18596b7dc4794d48a63fb361b01a0d8eb39f28800dc900c8fbdaca91"}, - {file = "aiohttp-3.10.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d00f3c5e0d764a5c9aa5a62d99728c56d455310bcc288a79cab10157b3af426f"}, - {file = "aiohttp-3.10.5-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:d742c36ed44f2798c8d3f4bc511f479b9ceef2b93f348671184139e7d708042c"}, - {file = "aiohttp-3.10.5-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:814375093edae5f1cb31e3407997cf3eacefb9010f96df10d64829362ae2df69"}, - {file = "aiohttp-3.10.5-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8224f98be68a84b19f48e0bdc14224b5a71339aff3a27df69989fa47d01296f3"}, - {file = "aiohttp-3.10.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d9a487ef090aea982d748b1b0d74fe7c3950b109df967630a20584f9a99c0683"}, - {file = "aiohttp-3.10.5-cp310-cp310-win32.whl", hash = "sha256:d9ef084e3dc690ad50137cc05831c52b6ca428096e6deb3c43e95827f531d5ef"}, - {file = "aiohttp-3.10.5-cp310-cp310-win_amd64.whl", hash = "sha256:66bf9234e08fe561dccd62083bf67400bdbf1c67ba9efdc3dac03650e97c6088"}, - {file = "aiohttp-3.10.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8c6a4e5e40156d72a40241a25cc226051c0a8d816610097a8e8f517aeacd59a2"}, - {file = "aiohttp-3.10.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c634a3207a5445be65536d38c13791904fda0748b9eabf908d3fe86a52941cf"}, - {file = "aiohttp-3.10.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4aff049b5e629ef9b3e9e617fa6e2dfeda1bf87e01bcfecaf3949af9e210105e"}, - {file = "aiohttp-3.10.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1942244f00baaacaa8155eca94dbd9e8cc7017deb69b75ef67c78e89fdad3c77"}, - {file = "aiohttp-3.10.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e04a1f2a65ad2f93aa20f9ff9f1b672bf912413e5547f60749fa2ef8a644e061"}, - {file = "aiohttp-3.10.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7f2bfc0032a00405d4af2ba27f3c429e851d04fad1e5ceee4080a1c570476697"}, - {file = "aiohttp-3.10.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:424ae21498790e12eb759040bbb504e5e280cab64693d14775c54269fd1d2bb7"}, - {file = "aiohttp-3.10.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:975218eee0e6d24eb336d0328c768ebc5d617609affaca5dbbd6dd1984f16ed0"}, - {file = "aiohttp-3.10.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4120d7fefa1e2d8fb6f650b11489710091788de554e2b6f8347c7a20ceb003f5"}, - {file = "aiohttp-3.10.5-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:b90078989ef3fc45cf9221d3859acd1108af7560c52397ff4ace8ad7052a132e"}, - {file = "aiohttp-3.10.5-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:ba5a8b74c2a8af7d862399cdedce1533642fa727def0b8c3e3e02fcb52dca1b1"}, - {file = "aiohttp-3.10.5-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:02594361128f780eecc2a29939d9dfc870e17b45178a867bf61a11b2a4367277"}, - {file = "aiohttp-3.10.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8fb4fc029e135859f533025bc82047334e24b0d489e75513144f25408ecaf058"}, - {file = "aiohttp-3.10.5-cp311-cp311-win32.whl", hash = "sha256:e1ca1ef5ba129718a8fc827b0867f6aa4e893c56eb00003b7367f8a733a9b072"}, - {file = "aiohttp-3.10.5-cp311-cp311-win_amd64.whl", hash = "sha256:349ef8a73a7c5665cca65c88ab24abe75447e28aa3bc4c93ea5093474dfdf0ff"}, - {file = "aiohttp-3.10.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:305be5ff2081fa1d283a76113b8df7a14c10d75602a38d9f012935df20731487"}, - {file = "aiohttp-3.10.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3a1c32a19ee6bbde02f1cb189e13a71b321256cc1d431196a9f824050b160d5a"}, - {file = "aiohttp-3.10.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:61645818edd40cc6f455b851277a21bf420ce347baa0b86eaa41d51ef58ba23d"}, - {file = "aiohttp-3.10.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c225286f2b13bab5987425558baa5cbdb2bc925b2998038fa028245ef421e75"}, - {file = "aiohttp-3.10.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8ba01ebc6175e1e6b7275c907a3a36be48a2d487549b656aa90c8a910d9f3178"}, - {file = "aiohttp-3.10.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8eaf44ccbc4e35762683078b72bf293f476561d8b68ec8a64f98cf32811c323e"}, - {file = "aiohttp-3.10.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1c43eb1ab7cbf411b8e387dc169acb31f0ca0d8c09ba63f9eac67829585b44f"}, - {file = "aiohttp-3.10.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de7a5299827253023c55ea549444e058c0eb496931fa05d693b95140a947cb73"}, - {file = "aiohttp-3.10.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4790f0e15f00058f7599dab2b206d3049d7ac464dc2e5eae0e93fa18aee9e7bf"}, - {file = "aiohttp-3.10.5-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:44b324a6b8376a23e6ba25d368726ee3bc281e6ab306db80b5819999c737d820"}, - {file = "aiohttp-3.10.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:0d277cfb304118079e7044aad0b76685d30ecb86f83a0711fc5fb257ffe832ca"}, - {file = "aiohttp-3.10.5-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:54d9ddea424cd19d3ff6128601a4a4d23d54a421f9b4c0fff740505813739a91"}, - {file = "aiohttp-3.10.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4f1c9866ccf48a6df2b06823e6ae80573529f2af3a0992ec4fe75b1a510df8a6"}, - {file = "aiohttp-3.10.5-cp312-cp312-win32.whl", hash = "sha256:dc4826823121783dccc0871e3f405417ac116055bf184ac04c36f98b75aacd12"}, - {file = "aiohttp-3.10.5-cp312-cp312-win_amd64.whl", hash = "sha256:22c0a23a3b3138a6bf76fc553789cb1a703836da86b0f306b6f0dc1617398abc"}, - {file = "aiohttp-3.10.5-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7f6b639c36734eaa80a6c152a238242bedcee9b953f23bb887e9102976343092"}, - {file = "aiohttp-3.10.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f29930bc2921cef955ba39a3ff87d2c4398a0394ae217f41cb02d5c26c8b1b77"}, - {file = "aiohttp-3.10.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f489a2c9e6455d87eabf907ac0b7d230a9786be43fbe884ad184ddf9e9c1e385"}, - {file = "aiohttp-3.10.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:123dd5b16b75b2962d0fff566effb7a065e33cd4538c1692fb31c3bda2bfb972"}, - {file = "aiohttp-3.10.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b98e698dc34966e5976e10bbca6d26d6724e6bdea853c7c10162a3235aba6e16"}, - {file = "aiohttp-3.10.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c3b9162bab7e42f21243effc822652dc5bb5e8ff42a4eb62fe7782bcbcdfacf6"}, - {file = "aiohttp-3.10.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1923a5c44061bffd5eebeef58cecf68096e35003907d8201a4d0d6f6e387ccaa"}, - {file = "aiohttp-3.10.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d55f011da0a843c3d3df2c2cf4e537b8070a419f891c930245f05d329c4b0689"}, - {file = "aiohttp-3.10.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:afe16a84498441d05e9189a15900640a2d2b5e76cf4efe8cbb088ab4f112ee57"}, - {file = "aiohttp-3.10.5-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f8112fb501b1e0567a1251a2fd0747baae60a4ab325a871e975b7bb67e59221f"}, - {file = "aiohttp-3.10.5-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:1e72589da4c90337837fdfe2026ae1952c0f4a6e793adbbfbdd40efed7c63599"}, - {file = "aiohttp-3.10.5-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:4d46c7b4173415d8e583045fbc4daa48b40e31b19ce595b8d92cf639396c15d5"}, - {file = "aiohttp-3.10.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:33e6bc4bab477c772a541f76cd91e11ccb6d2efa2b8d7d7883591dfb523e5987"}, - {file = "aiohttp-3.10.5-cp313-cp313-win32.whl", hash = "sha256:c58c6837a2c2a7cf3133983e64173aec11f9c2cd8e87ec2fdc16ce727bcf1a04"}, - {file = "aiohttp-3.10.5-cp313-cp313-win_amd64.whl", hash = "sha256:38172a70005252b6893088c0f5e8a47d173df7cc2b2bd88650957eb84fcf5022"}, - {file = "aiohttp-3.10.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:f6f18898ace4bcd2d41a122916475344a87f1dfdec626ecde9ee802a711bc569"}, - {file = "aiohttp-3.10.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5ede29d91a40ba22ac1b922ef510aab871652f6c88ef60b9dcdf773c6d32ad7a"}, - {file = "aiohttp-3.10.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:673f988370f5954df96cc31fd99c7312a3af0a97f09e407399f61583f30da9bc"}, - {file = "aiohttp-3.10.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:58718e181c56a3c02d25b09d4115eb02aafe1a732ce5714ab70326d9776457c3"}, - {file = "aiohttp-3.10.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4b38b1570242fbab8d86a84128fb5b5234a2f70c2e32f3070143a6d94bc854cf"}, - {file = "aiohttp-3.10.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:074d1bff0163e107e97bd48cad9f928fa5a3eb4b9d33366137ffce08a63e37fe"}, - {file = "aiohttp-3.10.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd31f176429cecbc1ba499d4aba31aaccfea488f418d60376b911269d3b883c5"}, - {file = "aiohttp-3.10.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7384d0b87d4635ec38db9263e6a3f1eb609e2e06087f0aa7f63b76833737b471"}, - {file = "aiohttp-3.10.5-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:8989f46f3d7ef79585e98fa991e6ded55d2f48ae56d2c9fa5e491a6e4effb589"}, - {file = "aiohttp-3.10.5-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:c83f7a107abb89a227d6c454c613e7606c12a42b9a4ca9c5d7dad25d47c776ae"}, - {file = "aiohttp-3.10.5-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:cde98f323d6bf161041e7627a5fd763f9fd829bcfcd089804a5fdce7bb6e1b7d"}, - {file = "aiohttp-3.10.5-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:676f94c5480d8eefd97c0c7e3953315e4d8c2b71f3b49539beb2aa676c58272f"}, - {file = "aiohttp-3.10.5-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:2d21ac12dc943c68135ff858c3a989f2194a709e6e10b4c8977d7fcd67dfd511"}, - {file = "aiohttp-3.10.5-cp38-cp38-win32.whl", hash = "sha256:17e997105bd1a260850272bfb50e2a328e029c941c2708170d9d978d5a30ad9a"}, - {file = "aiohttp-3.10.5-cp38-cp38-win_amd64.whl", hash = "sha256:1c19de68896747a2aa6257ae4cf6ef59d73917a36a35ee9d0a6f48cff0f94db8"}, - {file = "aiohttp-3.10.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7e2fe37ac654032db1f3499fe56e77190282534810e2a8e833141a021faaab0e"}, - {file = "aiohttp-3.10.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f5bf3ead3cb66ab990ee2561373b009db5bc0e857549b6c9ba84b20bc462e172"}, - {file = "aiohttp-3.10.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1b2c16a919d936ca87a3c5f0e43af12a89a3ce7ccbce59a2d6784caba945b68b"}, - {file = "aiohttp-3.10.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad146dae5977c4dd435eb31373b3fe9b0b1bf26858c6fc452bf6af394067e10b"}, - {file = "aiohttp-3.10.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8c5c6fa16412b35999320f5c9690c0f554392dc222c04e559217e0f9ae244b92"}, - {file = "aiohttp-3.10.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:95c4dc6f61d610bc0ee1edc6f29d993f10febfe5b76bb470b486d90bbece6b22"}, - {file = "aiohttp-3.10.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da452c2c322e9ce0cfef392e469a26d63d42860f829026a63374fde6b5c5876f"}, - {file = "aiohttp-3.10.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:898715cf566ec2869d5cb4d5fb4be408964704c46c96b4be267442d265390f32"}, - {file = "aiohttp-3.10.5-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:391cc3a9c1527e424c6865e087897e766a917f15dddb360174a70467572ac6ce"}, - {file = "aiohttp-3.10.5-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:380f926b51b92d02a34119d072f178d80bbda334d1a7e10fa22d467a66e494db"}, - {file = "aiohttp-3.10.5-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ce91db90dbf37bb6fa0997f26574107e1b9d5ff939315247b7e615baa8ec313b"}, - {file = "aiohttp-3.10.5-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:9093a81e18c45227eebe4c16124ebf3e0d893830c6aca7cc310bfca8fe59d857"}, - {file = "aiohttp-3.10.5-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:ee40b40aa753d844162dcc80d0fe256b87cba48ca0054f64e68000453caead11"}, - {file = "aiohttp-3.10.5-cp39-cp39-win32.whl", hash = "sha256:03f2645adbe17f274444953bdea69f8327e9d278d961d85657cb0d06864814c1"}, - {file = "aiohttp-3.10.5-cp39-cp39-win_amd64.whl", hash = "sha256:d17920f18e6ee090bdd3d0bfffd769d9f2cb4c8ffde3eb203777a3895c128862"}, - {file = "aiohttp-3.10.5.tar.gz", hash = "sha256:f071854b47d39591ce9a17981c46790acb30518e2f83dfca8db2dfa091178691"}, + {file = "aiohttp-3.10.11-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5077b1a5f40ffa3ba1f40d537d3bec4383988ee51fbba6b74aa8fb1bc466599e"}, + {file = "aiohttp-3.10.11-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8d6a14a4d93b5b3c2891fca94fa9d41b2322a68194422bef0dd5ec1e57d7d298"}, + {file = "aiohttp-3.10.11-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ffbfde2443696345e23a3c597049b1dd43049bb65337837574205e7368472177"}, + {file = "aiohttp-3.10.11-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20b3d9e416774d41813bc02fdc0663379c01817b0874b932b81c7f777f67b217"}, + {file = "aiohttp-3.10.11-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2b943011b45ee6bf74b22245c6faab736363678e910504dd7531a58c76c9015a"}, + {file = "aiohttp-3.10.11-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48bc1d924490f0d0b3658fe5c4b081a4d56ebb58af80a6729d4bd13ea569797a"}, + {file = "aiohttp-3.10.11-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e12eb3f4b1f72aaaf6acd27d045753b18101524f72ae071ae1c91c1cd44ef115"}, + {file = "aiohttp-3.10.11-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f14ebc419a568c2eff3c1ed35f634435c24ead2fe19c07426af41e7adb68713a"}, + {file = "aiohttp-3.10.11-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:72b191cdf35a518bfc7ca87d770d30941decc5aaf897ec8b484eb5cc8c7706f3"}, + {file = "aiohttp-3.10.11-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:5ab2328a61fdc86424ee540d0aeb8b73bbcad7351fb7cf7a6546fc0bcffa0038"}, + {file = "aiohttp-3.10.11-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:aa93063d4af05c49276cf14e419550a3f45258b6b9d1f16403e777f1addf4519"}, + {file = "aiohttp-3.10.11-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:30283f9d0ce420363c24c5c2421e71a738a2155f10adbb1a11a4d4d6d2715cfc"}, + {file = "aiohttp-3.10.11-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e5358addc8044ee49143c546d2182c15b4ac3a60be01c3209374ace05af5733d"}, + {file = "aiohttp-3.10.11-cp310-cp310-win32.whl", hash = "sha256:e1ffa713d3ea7cdcd4aea9cddccab41edf6882fa9552940344c44e59652e1120"}, + {file = "aiohttp-3.10.11-cp310-cp310-win_amd64.whl", hash = "sha256:778cbd01f18ff78b5dd23c77eb82987ee4ba23408cbed233009fd570dda7e674"}, + {file = "aiohttp-3.10.11-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:80ff08556c7f59a7972b1e8919f62e9c069c33566a6d28586771711e0eea4f07"}, + {file = "aiohttp-3.10.11-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c8f96e9ee19f04c4914e4e7a42a60861066d3e1abf05c726f38d9d0a466e695"}, + {file = "aiohttp-3.10.11-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fb8601394d537da9221947b5d6e62b064c9a43e88a1ecd7414d21a1a6fba9c24"}, + {file = "aiohttp-3.10.11-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ea224cf7bc2d8856d6971cea73b1d50c9c51d36971faf1abc169a0d5f85a382"}, + {file = "aiohttp-3.10.11-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:db9503f79e12d5d80b3efd4d01312853565c05367493379df76d2674af881caa"}, + {file = "aiohttp-3.10.11-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0f449a50cc33f0384f633894d8d3cd020e3ccef81879c6e6245c3c375c448625"}, + {file = "aiohttp-3.10.11-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82052be3e6d9e0c123499127782a01a2b224b8af8c62ab46b3f6197035ad94e9"}, + {file = "aiohttp-3.10.11-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:20063c7acf1eec550c8eb098deb5ed9e1bb0521613b03bb93644b810986027ac"}, + {file = "aiohttp-3.10.11-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:489cced07a4c11488f47aab1f00d0c572506883f877af100a38f1fedaa884c3a"}, + {file = "aiohttp-3.10.11-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ea9b3bab329aeaa603ed3bf605f1e2a6f36496ad7e0e1aa42025f368ee2dc07b"}, + {file = "aiohttp-3.10.11-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:ca117819d8ad113413016cb29774b3f6d99ad23c220069789fc050267b786c16"}, + {file = "aiohttp-3.10.11-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:2dfb612dcbe70fb7cdcf3499e8d483079b89749c857a8f6e80263b021745c730"}, + {file = "aiohttp-3.10.11-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9b615d3da0d60e7d53c62e22b4fd1c70f4ae5993a44687b011ea3a2e49051b8"}, + {file = "aiohttp-3.10.11-cp311-cp311-win32.whl", hash = "sha256:29103f9099b6068bbdf44d6a3d090e0a0b2be6d3c9f16a070dd9d0d910ec08f9"}, + {file = "aiohttp-3.10.11-cp311-cp311-win_amd64.whl", hash = "sha256:236b28ceb79532da85d59aa9b9bf873b364e27a0acb2ceaba475dc61cffb6f3f"}, + {file = "aiohttp-3.10.11-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:7480519f70e32bfb101d71fb9a1f330fbd291655a4c1c922232a48c458c52710"}, + {file = "aiohttp-3.10.11-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f65267266c9aeb2287a6622ee2bb39490292552f9fbf851baabc04c9f84e048d"}, + {file = "aiohttp-3.10.11-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7400a93d629a0608dc1d6c55f1e3d6e07f7375745aaa8bd7f085571e4d1cee97"}, + {file = "aiohttp-3.10.11-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f34b97e4b11b8d4eb2c3a4f975be626cc8af99ff479da7de49ac2c6d02d35725"}, + {file = "aiohttp-3.10.11-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1e7b825da878464a252ccff2958838f9caa82f32a8dbc334eb9b34a026e2c636"}, + {file = "aiohttp-3.10.11-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f9f92a344c50b9667827da308473005f34767b6a2a60d9acff56ae94f895f385"}, + {file = "aiohttp-3.10.11-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc6f1ab987a27b83c5268a17218463c2ec08dbb754195113867a27b166cd6087"}, + {file = "aiohttp-3.10.11-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1dc0f4ca54842173d03322793ebcf2c8cc2d34ae91cc762478e295d8e361e03f"}, + {file = "aiohttp-3.10.11-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7ce6a51469bfaacff146e59e7fb61c9c23006495d11cc24c514a455032bcfa03"}, + {file = "aiohttp-3.10.11-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:aad3cd91d484d065ede16f3cf15408254e2469e3f613b241a1db552c5eb7ab7d"}, + {file = "aiohttp-3.10.11-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f4df4b8ca97f658c880fb4b90b1d1ec528315d4030af1ec763247ebfd33d8b9a"}, + {file = "aiohttp-3.10.11-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:2e4e18a0a2d03531edbc06c366954e40a3f8d2a88d2b936bbe78a0c75a3aab3e"}, + {file = "aiohttp-3.10.11-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6ce66780fa1a20e45bc753cda2a149daa6dbf1561fc1289fa0c308391c7bc0a4"}, + {file = "aiohttp-3.10.11-cp312-cp312-win32.whl", hash = "sha256:a919c8957695ea4c0e7a3e8d16494e3477b86f33067478f43106921c2fef15bb"}, + {file = "aiohttp-3.10.11-cp312-cp312-win_amd64.whl", hash = "sha256:b5e29706e6389a2283a91611c91bf24f218962717c8f3b4e528ef529d112ee27"}, + {file = "aiohttp-3.10.11-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:703938e22434d7d14ec22f9f310559331f455018389222eed132808cd8f44127"}, + {file = "aiohttp-3.10.11-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9bc50b63648840854e00084c2b43035a62e033cb9b06d8c22b409d56eb098413"}, + {file = "aiohttp-3.10.11-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5f0463bf8b0754bc744e1feb61590706823795041e63edf30118a6f0bf577461"}, + {file = "aiohttp-3.10.11-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f6c6dec398ac5a87cb3a407b068e1106b20ef001c344e34154616183fe684288"}, + {file = "aiohttp-3.10.11-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bcaf2d79104d53d4dcf934f7ce76d3d155302d07dae24dff6c9fffd217568067"}, + {file = "aiohttp-3.10.11-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:25fd5470922091b5a9aeeb7e75be609e16b4fba81cdeaf12981393fb240dd10e"}, + {file = "aiohttp-3.10.11-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbde2ca67230923a42161b1f408c3992ae6e0be782dca0c44cb3206bf330dee1"}, + {file = "aiohttp-3.10.11-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:249c8ff8d26a8b41a0f12f9df804e7c685ca35a207e2410adbd3e924217b9006"}, + {file = "aiohttp-3.10.11-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:878ca6a931ee8c486a8f7b432b65431d095c522cbeb34892bee5be97b3481d0f"}, + {file = "aiohttp-3.10.11-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:8663f7777ce775f0413324be0d96d9730959b2ca73d9b7e2c2c90539139cbdd6"}, + {file = "aiohttp-3.10.11-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:6cd3f10b01f0c31481fba8d302b61603a2acb37b9d30e1d14e0f5a58b7b18a31"}, + {file = "aiohttp-3.10.11-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:4e8d8aad9402d3aa02fdc5ca2fe68bcb9fdfe1f77b40b10410a94c7f408b664d"}, + {file = "aiohttp-3.10.11-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:38e3c4f80196b4f6c3a85d134a534a56f52da9cb8d8e7af1b79a32eefee73a00"}, + {file = "aiohttp-3.10.11-cp313-cp313-win32.whl", hash = "sha256:fc31820cfc3b2863c6e95e14fcf815dc7afe52480b4dc03393c4873bb5599f71"}, + {file = "aiohttp-3.10.11-cp313-cp313-win_amd64.whl", hash = "sha256:4996ff1345704ffdd6d75fb06ed175938c133425af616142e7187f28dc75f14e"}, + {file = "aiohttp-3.10.11-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:74baf1a7d948b3d640badeac333af581a367ab916b37e44cf90a0334157cdfd2"}, + {file = "aiohttp-3.10.11-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:473aebc3b871646e1940c05268d451f2543a1d209f47035b594b9d4e91ce8339"}, + {file = "aiohttp-3.10.11-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c2f746a6968c54ab2186574e15c3f14f3e7f67aef12b761e043b33b89c5b5f95"}, + {file = "aiohttp-3.10.11-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d110cabad8360ffa0dec8f6ec60e43286e9d251e77db4763a87dcfe55b4adb92"}, + {file = "aiohttp-3.10.11-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e0099c7d5d7afff4202a0c670e5b723f7718810000b4abcbc96b064129e64bc7"}, + {file = "aiohttp-3.10.11-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0316e624b754dbbf8c872b62fe6dcb395ef20c70e59890dfa0de9eafccd2849d"}, + {file = "aiohttp-3.10.11-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a5f7ab8baf13314e6b2485965cbacb94afff1e93466ac4d06a47a81c50f9cca"}, + {file = "aiohttp-3.10.11-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c891011e76041e6508cbfc469dd1a8ea09bc24e87e4c204e05f150c4c455a5fa"}, + {file = "aiohttp-3.10.11-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:9208299251370ee815473270c52cd3f7069ee9ed348d941d574d1457d2c73e8b"}, + {file = "aiohttp-3.10.11-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:459f0f32c8356e8125f45eeff0ecf2b1cb6db1551304972702f34cd9e6c44658"}, + {file = "aiohttp-3.10.11-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:14cdc8c1810bbd4b4b9f142eeee23cda528ae4e57ea0923551a9af4820980e39"}, + {file = "aiohttp-3.10.11-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:971aa438a29701d4b34e4943e91b5e984c3ae6ccbf80dd9efaffb01bd0b243a9"}, + {file = "aiohttp-3.10.11-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:9a309c5de392dfe0f32ee57fa43ed8fc6ddf9985425e84bd51ed66bb16bce3a7"}, + {file = "aiohttp-3.10.11-cp38-cp38-win32.whl", hash = "sha256:9ec1628180241d906a0840b38f162a3215114b14541f1a8711c368a8739a9be4"}, + {file = "aiohttp-3.10.11-cp38-cp38-win_amd64.whl", hash = "sha256:9c6e0ffd52c929f985c7258f83185d17c76d4275ad22e90aa29f38e211aacbec"}, + {file = "aiohttp-3.10.11-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:cdc493a2e5d8dc79b2df5bec9558425bcd39aff59fc949810cbd0832e294b106"}, + {file = "aiohttp-3.10.11-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b3e70f24e7d0405be2348da9d5a7836936bf3a9b4fd210f8c37e8d48bc32eca6"}, + {file = "aiohttp-3.10.11-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:968b8fb2a5eee2770eda9c7b5581587ef9b96fbdf8dcabc6b446d35ccc69df01"}, + {file = "aiohttp-3.10.11-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:deef4362af9493d1382ef86732ee2e4cbc0d7c005947bd54ad1a9a16dd59298e"}, + {file = "aiohttp-3.10.11-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:686b03196976e327412a1b094f4120778c7c4b9cff9bce8d2fdfeca386b89829"}, + {file = "aiohttp-3.10.11-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3bf6d027d9d1d34e1c2e1645f18a6498c98d634f8e373395221121f1c258ace8"}, + {file = "aiohttp-3.10.11-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:099fd126bf960f96d34a760e747a629c27fb3634da5d05c7ef4d35ef4ea519fc"}, + {file = "aiohttp-3.10.11-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c73c4d3dae0b4644bc21e3de546530531d6cdc88659cdeb6579cd627d3c206aa"}, + {file = "aiohttp-3.10.11-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0c5580f3c51eea91559db3facd45d72e7ec970b04528b4709b1f9c2555bd6d0b"}, + {file = "aiohttp-3.10.11-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:fdf6429f0caabfd8a30c4e2eaecb547b3c340e4730ebfe25139779b9815ba138"}, + {file = "aiohttp-3.10.11-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:d97187de3c276263db3564bb9d9fad9e15b51ea10a371ffa5947a5ba93ad6777"}, + {file = "aiohttp-3.10.11-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:0acafb350cfb2eba70eb5d271f55e08bd4502ec35e964e18ad3e7d34d71f7261"}, + {file = "aiohttp-3.10.11-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c13ed0c779911c7998a58e7848954bd4d63df3e3575f591e321b19a2aec8df9f"}, + {file = "aiohttp-3.10.11-cp39-cp39-win32.whl", hash = "sha256:22b7c540c55909140f63ab4f54ec2c20d2635c0289cdd8006da46f3327f971b9"}, + {file = "aiohttp-3.10.11-cp39-cp39-win_amd64.whl", hash = "sha256:7b26b1551e481012575dab8e3727b16fe7dd27eb2711d2e63ced7368756268fb"}, + {file = "aiohttp-3.10.11.tar.gz", hash = "sha256:9dc2b8f3dcab2e39e0fa309c8da50c3b55e6f34ab25f1a71d3288f24924d33a7"}, ] [package.dependencies] aiodns = {version = ">=3.2.0", optional = true, markers = "(sys_platform == \"linux\" or sys_platform == \"darwin\") and extra == \"speedups\""} aiohappyeyeballs = ">=2.3.0" aiosignal = ">=1.1.2" -async-timeout = {version = ">=4.0,<5.0", markers = "python_version < \"3.11\""} +async-timeout = {version = ">=4.0,<6.0", markers = "python_version < \"3.11\""} attrs = ">=17.3.0" Brotli = {version = "*", optional = true, markers = "platform_python_implementation == \"CPython\" and extra == \"speedups\""} brotlicffi = {version = "*", optional = true, markers = "platform_python_implementation != \"CPython\" and extra == \"speedups\""} frozenlist = ">=1.1.1" multidict = ">=4.5,<7.0" -yarl = ">=1.0,<2.0" +yarl = ">=1.12.0,<2.0" [package.extras] speedups = ["Brotli", "aiodns (>=3.2.0)", "brotlicffi"] @@ -156,31 +156,31 @@ frozenlist = ">=1.1.0" [[package]] name = "async-timeout" -version = "4.0.3" +version = "5.0.1" description = "Timeout context manager for asyncio programs" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f"}, - {file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"}, + {file = "async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c"}, + {file = "async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3"}, ] [[package]] name = "attrs" -version = "24.2.0" +version = "25.3.0" description = "Classes Without Boilerplate" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2"}, - {file = "attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346"}, + {file = "attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3"}, + {file = "attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b"}, ] [package.extras] benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"] cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] -dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] -docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"] +dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit-uv", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier"] tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"] @@ -317,78 +317,78 @@ cffi = ">=1.0.0" [[package]] name = "cffi" -version = "1.17.0" +version = "1.17.1" description = "Foreign Function Interface for Python calling C code." optional = false python-versions = ">=3.8" files = [ - {file = "cffi-1.17.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f9338cc05451f1942d0d8203ec2c346c830f8e86469903d5126c1f0a13a2bcbb"}, - {file = "cffi-1.17.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a0ce71725cacc9ebf839630772b07eeec220cbb5f03be1399e0457a1464f8e1a"}, - {file = "cffi-1.17.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c815270206f983309915a6844fe994b2fa47e5d05c4c4cef267c3b30e34dbe42"}, - {file = "cffi-1.17.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6bdcd415ba87846fd317bee0774e412e8792832e7805938987e4ede1d13046d"}, - {file = "cffi-1.17.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a98748ed1a1df4ee1d6f927e151ed6c1a09d5ec21684de879c7ea6aa96f58f2"}, - {file = "cffi-1.17.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0a048d4f6630113e54bb4b77e315e1ba32a5a31512c31a273807d0027a7e69ab"}, - {file = "cffi-1.17.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24aa705a5f5bd3a8bcfa4d123f03413de5d86e497435693b638cbffb7d5d8a1b"}, - {file = "cffi-1.17.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:856bf0924d24e7f93b8aee12a3a1095c34085600aa805693fb7f5d1962393206"}, - {file = "cffi-1.17.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:4304d4416ff032ed50ad6bb87416d802e67139e31c0bde4628f36a47a3164bfa"}, - {file = "cffi-1.17.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:331ad15c39c9fe9186ceaf87203a9ecf5ae0ba2538c9e898e3a6967e8ad3db6f"}, - {file = "cffi-1.17.0-cp310-cp310-win32.whl", hash = "sha256:669b29a9eca6146465cc574659058ed949748f0809a2582d1f1a324eb91054dc"}, - {file = "cffi-1.17.0-cp310-cp310-win_amd64.whl", hash = "sha256:48b389b1fd5144603d61d752afd7167dfd205973a43151ae5045b35793232aa2"}, - {file = "cffi-1.17.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c5d97162c196ce54af6700949ddf9409e9833ef1003b4741c2b39ef46f1d9720"}, - {file = "cffi-1.17.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5ba5c243f4004c750836f81606a9fcb7841f8874ad8f3bf204ff5e56332b72b9"}, - {file = "cffi-1.17.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bb9333f58fc3a2296fb1d54576138d4cf5d496a2cc118422bd77835e6ae0b9cb"}, - {file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:435a22d00ec7d7ea533db494da8581b05977f9c37338c80bc86314bec2619424"}, - {file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d1df34588123fcc88c872f5acb6f74ae59e9d182a2707097f9e28275ec26a12d"}, - {file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:df8bb0010fdd0a743b7542589223a2816bdde4d94bb5ad67884348fa2c1c67e8"}, - {file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8b5b9712783415695663bd463990e2f00c6750562e6ad1d28e072a611c5f2a6"}, - {file = "cffi-1.17.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ffef8fd58a36fb5f1196919638f73dd3ae0db1a878982b27a9a5a176ede4ba91"}, - {file = "cffi-1.17.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4e67d26532bfd8b7f7c05d5a766d6f437b362c1bf203a3a5ce3593a645e870b8"}, - {file = "cffi-1.17.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:45f7cd36186db767d803b1473b3c659d57a23b5fa491ad83c6d40f2af58e4dbb"}, - {file = "cffi-1.17.0-cp311-cp311-win32.whl", hash = "sha256:a9015f5b8af1bb6837a3fcb0cdf3b874fe3385ff6274e8b7925d81ccaec3c5c9"}, - {file = "cffi-1.17.0-cp311-cp311-win_amd64.whl", hash = "sha256:b50aaac7d05c2c26dfd50c3321199f019ba76bb650e346a6ef3616306eed67b0"}, - {file = "cffi-1.17.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aec510255ce690d240f7cb23d7114f6b351c733a74c279a84def763660a2c3bc"}, - {file = "cffi-1.17.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2770bb0d5e3cc0e31e7318db06efcbcdb7b31bcb1a70086d3177692a02256f59"}, - {file = "cffi-1.17.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:db9a30ec064129d605d0f1aedc93e00894b9334ec74ba9c6bdd08147434b33eb"}, - {file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a47eef975d2b8b721775a0fa286f50eab535b9d56c70a6e62842134cf7841195"}, - {file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f3e0992f23bbb0be00a921eae5363329253c3b86287db27092461c887b791e5e"}, - {file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6107e445faf057c118d5050560695e46d272e5301feffda3c41849641222a828"}, - {file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb862356ee9391dc5a0b3cbc00f416b48c1b9a52d252d898e5b7696a5f9fe150"}, - {file = "cffi-1.17.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c1c13185b90bbd3f8b5963cd8ce7ad4ff441924c31e23c975cb150e27c2bf67a"}, - {file = "cffi-1.17.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:17c6d6d3260c7f2d94f657e6872591fe8733872a86ed1345bda872cfc8c74885"}, - {file = "cffi-1.17.0-cp312-cp312-win32.whl", hash = "sha256:c3b8bd3133cd50f6b637bb4322822c94c5ce4bf0d724ed5ae70afce62187c492"}, - {file = "cffi-1.17.0-cp312-cp312-win_amd64.whl", hash = "sha256:dca802c8db0720ce1c49cce1149ff7b06e91ba15fa84b1d59144fef1a1bc7ac2"}, - {file = "cffi-1.17.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6ce01337d23884b21c03869d2f68c5523d43174d4fc405490eb0091057943118"}, - {file = "cffi-1.17.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cab2eba3830bf4f6d91e2d6718e0e1c14a2f5ad1af68a89d24ace0c6b17cced7"}, - {file = "cffi-1.17.0-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:14b9cbc8f7ac98a739558eb86fabc283d4d564dafed50216e7f7ee62d0d25377"}, - {file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b00e7bcd71caa0282cbe3c90966f738e2db91e64092a877c3ff7f19a1628fdcb"}, - {file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:41f4915e09218744d8bae14759f983e466ab69b178de38066f7579892ff2a555"}, - {file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e4760a68cab57bfaa628938e9c2971137e05ce48e762a9cb53b76c9b569f1204"}, - {file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:011aff3524d578a9412c8b3cfaa50f2c0bd78e03eb7af7aa5e0df59b158efb2f"}, - {file = "cffi-1.17.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:a003ac9edc22d99ae1286b0875c460351f4e101f8c9d9d2576e78d7e048f64e0"}, - {file = "cffi-1.17.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ef9528915df81b8f4c7612b19b8628214c65c9b7f74db2e34a646a0a2a0da2d4"}, - {file = "cffi-1.17.0-cp313-cp313-win32.whl", hash = "sha256:70d2aa9fb00cf52034feac4b913181a6e10356019b18ef89bc7c12a283bf5f5a"}, - {file = "cffi-1.17.0-cp313-cp313-win_amd64.whl", hash = "sha256:b7b6ea9e36d32582cda3465f54c4b454f62f23cb083ebc7a94e2ca6ef011c3a7"}, - {file = "cffi-1.17.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:964823b2fc77b55355999ade496c54dde161c621cb1f6eac61dc30ed1b63cd4c"}, - {file = "cffi-1.17.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:516a405f174fd3b88829eabfe4bb296ac602d6a0f68e0d64d5ac9456194a5b7e"}, - {file = "cffi-1.17.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dec6b307ce928e8e112a6bb9921a1cb00a0e14979bf28b98e084a4b8a742bd9b"}, - {file = "cffi-1.17.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e4094c7b464cf0a858e75cd14b03509e84789abf7b79f8537e6a72152109c76e"}, - {file = "cffi-1.17.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2404f3de742f47cb62d023f0ba7c5a916c9c653d5b368cc966382ae4e57da401"}, - {file = "cffi-1.17.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3aa9d43b02a0c681f0bfbc12d476d47b2b2b6a3f9287f11ee42989a268a1833c"}, - {file = "cffi-1.17.0-cp38-cp38-win32.whl", hash = "sha256:0bb15e7acf8ab35ca8b24b90af52c8b391690ef5c4aec3d31f38f0d37d2cc499"}, - {file = "cffi-1.17.0-cp38-cp38-win_amd64.whl", hash = "sha256:93a7350f6706b31f457c1457d3a3259ff9071a66f312ae64dc024f049055f72c"}, - {file = "cffi-1.17.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1a2ddbac59dc3716bc79f27906c010406155031a1c801410f1bafff17ea304d2"}, - {file = "cffi-1.17.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6327b572f5770293fc062a7ec04160e89741e8552bf1c358d1a23eba68166759"}, - {file = "cffi-1.17.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbc183e7bef690c9abe5ea67b7b60fdbca81aa8da43468287dae7b5c046107d4"}, - {file = "cffi-1.17.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5bdc0f1f610d067c70aa3737ed06e2726fd9d6f7bfee4a351f4c40b6831f4e82"}, - {file = "cffi-1.17.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6d872186c1617d143969defeadac5a904e6e374183e07977eedef9c07c8953bf"}, - {file = "cffi-1.17.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0d46ee4764b88b91f16661a8befc6bfb24806d885e27436fdc292ed7e6f6d058"}, - {file = "cffi-1.17.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f76a90c345796c01d85e6332e81cab6d70de83b829cf1d9762d0a3da59c7932"}, - {file = "cffi-1.17.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0e60821d312f99d3e1569202518dddf10ae547e799d75aef3bca3a2d9e8ee693"}, - {file = "cffi-1.17.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:eb09b82377233b902d4c3fbeeb7ad731cdab579c6c6fda1f763cd779139e47c3"}, - {file = "cffi-1.17.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:24658baf6224d8f280e827f0a50c46ad819ec8ba380a42448e24459daf809cf4"}, - {file = "cffi-1.17.0-cp39-cp39-win32.whl", hash = "sha256:0fdacad9e0d9fc23e519efd5ea24a70348305e8d7d85ecbb1a5fa66dc834e7fb"}, - {file = "cffi-1.17.0-cp39-cp39-win_amd64.whl", hash = "sha256:7cbc78dc018596315d4e7841c8c3a7ae31cc4d638c9b627f87d52e8abaaf2d29"}, - {file = "cffi-1.17.0.tar.gz", hash = "sha256:f3157624b7558b914cb039fd1af735e5e8049a87c817cc215109ad1c8779df76"}, + {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"}, + {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be"}, + {file = "cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c"}, + {file = "cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15"}, + {file = "cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401"}, + {file = "cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b"}, + {file = "cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655"}, + {file = "cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0"}, + {file = "cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4"}, + {file = "cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8"}, + {file = "cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65"}, + {file = "cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903"}, + {file = "cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e"}, + {file = "cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd"}, + {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed"}, + {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9"}, + {file = "cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d"}, + {file = "cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"}, + {file = "cffi-1.17.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1"}, + {file = "cffi-1.17.1-cp38-cp38-win32.whl", hash = "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8"}, + {file = "cffi-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1"}, + {file = "cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16"}, + {file = "cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e"}, + {file = "cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7"}, + {file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"}, + {file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"}, ] [package.dependencies] @@ -407,225 +407,251 @@ files = [ [[package]] name = "exceptiongroup" -version = "1.2.2" +version = "1.3.0" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" files = [ - {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, - {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, + {file = "exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10"}, + {file = "exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88"}, ] +[package.dependencies] +typing-extensions = {version = ">=4.6.0", markers = "python_version < \"3.13\""} + [package.extras] test = ["pytest (>=6)"] [[package]] name = "frozenlist" -version = "1.4.1" +version = "1.5.0" description = "A list-like structure which implements collections.abc.MutableSequence" optional = false python-versions = ">=3.8" files = [ - {file = "frozenlist-1.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f9aa1878d1083b276b0196f2dfbe00c9b7e752475ed3b682025ff20c1c1f51ac"}, - {file = "frozenlist-1.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:29acab3f66f0f24674b7dc4736477bcd4bc3ad4b896f5f45379a67bce8b96868"}, - {file = "frozenlist-1.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:74fb4bee6880b529a0c6560885fce4dc95936920f9f20f53d99a213f7bf66776"}, - {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:590344787a90ae57d62511dd7c736ed56b428f04cd8c161fcc5e7232c130c69a"}, - {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:068b63f23b17df8569b7fdca5517edef76171cf3897eb68beb01341131fbd2ad"}, - {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c849d495bf5154cd8da18a9eb15db127d4dba2968d88831aff6f0331ea9bd4c"}, - {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9750cc7fe1ae3b1611bb8cfc3f9ec11d532244235d75901fb6b8e42ce9229dfe"}, - {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9b2de4cf0cdd5bd2dee4c4f63a653c61d2408055ab77b151c1957f221cabf2a"}, - {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0633c8d5337cb5c77acbccc6357ac49a1770b8c487e5b3505c57b949b4b82e98"}, - {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:27657df69e8801be6c3638054e202a135c7f299267f1a55ed3a598934f6c0d75"}, - {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:f9a3ea26252bd92f570600098783d1371354d89d5f6b7dfd87359d669f2109b5"}, - {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:4f57dab5fe3407b6c0c1cc907ac98e8a189f9e418f3b6e54d65a718aaafe3950"}, - {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e02a0e11cf6597299b9f3bbd3f93d79217cb90cfd1411aec33848b13f5c656cc"}, - {file = "frozenlist-1.4.1-cp310-cp310-win32.whl", hash = "sha256:a828c57f00f729620a442881cc60e57cfcec6842ba38e1b19fd3e47ac0ff8dc1"}, - {file = "frozenlist-1.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:f56e2333dda1fe0f909e7cc59f021eba0d2307bc6f012a1ccf2beca6ba362439"}, - {file = "frozenlist-1.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a0cb6f11204443f27a1628b0e460f37fb30f624be6051d490fa7d7e26d4af3d0"}, - {file = "frozenlist-1.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b46c8ae3a8f1f41a0d2ef350c0b6e65822d80772fe46b653ab6b6274f61d4a49"}, - {file = "frozenlist-1.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fde5bd59ab5357e3853313127f4d3565fc7dad314a74d7b5d43c22c6a5ed2ced"}, - {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:722e1124aec435320ae01ee3ac7bec11a5d47f25d0ed6328f2273d287bc3abb0"}, - {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2471c201b70d58a0f0c1f91261542a03d9a5e088ed3dc6c160d614c01649c106"}, - {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c757a9dd70d72b076d6f68efdbb9bc943665ae954dad2801b874c8c69e185068"}, - {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f146e0911cb2f1da549fc58fc7bcd2b836a44b79ef871980d605ec392ff6b0d2"}, - {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f9c515e7914626b2a2e1e311794b4c35720a0be87af52b79ff8e1429fc25f19"}, - {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c302220494f5c1ebeb0912ea782bcd5e2f8308037b3c7553fad0e48ebad6ad82"}, - {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:442acde1e068288a4ba7acfe05f5f343e19fac87bfc96d89eb886b0363e977ec"}, - {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:1b280e6507ea8a4fa0c0a7150b4e526a8d113989e28eaaef946cc77ffd7efc0a"}, - {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:fe1a06da377e3a1062ae5fe0926e12b84eceb8a50b350ddca72dc85015873f74"}, - {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:db9e724bebd621d9beca794f2a4ff1d26eed5965b004a97f1f1685a173b869c2"}, - {file = "frozenlist-1.4.1-cp311-cp311-win32.whl", hash = "sha256:e774d53b1a477a67838a904131c4b0eef6b3d8a651f8b138b04f748fccfefe17"}, - {file = "frozenlist-1.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:fb3c2db03683b5767dedb5769b8a40ebb47d6f7f45b1b3e3b4b51ec8ad9d9825"}, - {file = "frozenlist-1.4.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:1979bc0aeb89b33b588c51c54ab0161791149f2461ea7c7c946d95d5f93b56ae"}, - {file = "frozenlist-1.4.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cc7b01b3754ea68a62bd77ce6020afaffb44a590c2289089289363472d13aedb"}, - {file = "frozenlist-1.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c9c92be9fd329ac801cc420e08452b70e7aeab94ea4233a4804f0915c14eba9b"}, - {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c3894db91f5a489fc8fa6a9991820f368f0b3cbdb9cd8849547ccfab3392d86"}, - {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ba60bb19387e13597fb059f32cd4d59445d7b18b69a745b8f8e5db0346f33480"}, - {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8aefbba5f69d42246543407ed2461db31006b0f76c4e32dfd6f42215a2c41d09"}, - {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:780d3a35680ced9ce682fbcf4cb9c2bad3136eeff760ab33707b71db84664e3a"}, - {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9acbb16f06fe7f52f441bb6f413ebae6c37baa6ef9edd49cdd567216da8600cd"}, - {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:23b701e65c7b36e4bf15546a89279bd4d8675faabc287d06bbcfac7d3c33e1e6"}, - {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3e0153a805a98f5ada7e09826255ba99fb4f7524bb81bf6b47fb702666484ae1"}, - {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:dd9b1baec094d91bf36ec729445f7769d0d0cf6b64d04d86e45baf89e2b9059b"}, - {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:1a4471094e146b6790f61b98616ab8e44f72661879cc63fa1049d13ef711e71e"}, - {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5667ed53d68d91920defdf4035d1cdaa3c3121dc0b113255124bcfada1cfa1b8"}, - {file = "frozenlist-1.4.1-cp312-cp312-win32.whl", hash = "sha256:beee944ae828747fd7cb216a70f120767fc9f4f00bacae8543c14a6831673f89"}, - {file = "frozenlist-1.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:64536573d0a2cb6e625cf309984e2d873979709f2cf22839bf2d61790b448ad5"}, - {file = "frozenlist-1.4.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:20b51fa3f588ff2fe658663db52a41a4f7aa6c04f6201449c6c7c476bd255c0d"}, - {file = "frozenlist-1.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:410478a0c562d1a5bcc2f7ea448359fcb050ed48b3c6f6f4f18c313a9bdb1826"}, - {file = "frozenlist-1.4.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c6321c9efe29975232da3bd0af0ad216800a47e93d763ce64f291917a381b8eb"}, - {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48f6a4533887e189dae092f1cf981f2e3885175f7a0f33c91fb5b7b682b6bab6"}, - {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6eb73fa5426ea69ee0e012fb59cdc76a15b1283d6e32e4f8dc4482ec67d1194d"}, - {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fbeb989b5cc29e8daf7f976b421c220f1b8c731cbf22b9130d8815418ea45887"}, - {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:32453c1de775c889eb4e22f1197fe3bdfe457d16476ea407472b9442e6295f7a"}, - {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:693945278a31f2086d9bf3df0fe8254bbeaef1fe71e1351c3bd730aa7d31c41b"}, - {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:1d0ce09d36d53bbbe566fe296965b23b961764c0bcf3ce2fa45f463745c04701"}, - {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:3a670dc61eb0d0eb7080890c13de3066790f9049b47b0de04007090807c776b0"}, - {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:dca69045298ce5c11fd539682cff879cc1e664c245d1c64da929813e54241d11"}, - {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a06339f38e9ed3a64e4c4e43aec7f59084033647f908e4259d279a52d3757d09"}, - {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b7f2f9f912dca3934c1baec2e4585a674ef16fe00218d833856408c48d5beee7"}, - {file = "frozenlist-1.4.1-cp38-cp38-win32.whl", hash = "sha256:e7004be74cbb7d9f34553a5ce5fb08be14fb33bc86f332fb71cbe5216362a497"}, - {file = "frozenlist-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:5a7d70357e7cee13f470c7883a063aae5fe209a493c57d86eb7f5a6f910fae09"}, - {file = "frozenlist-1.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bfa4a17e17ce9abf47a74ae02f32d014c5e9404b6d9ac7f729e01562bbee601e"}, - {file = "frozenlist-1.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b7e3ed87d4138356775346e6845cccbe66cd9e207f3cd11d2f0b9fd13681359d"}, - {file = "frozenlist-1.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c99169d4ff810155ca50b4da3b075cbde79752443117d89429595c2e8e37fed8"}, - {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edb678da49d9f72c9f6c609fbe41a5dfb9a9282f9e6a2253d5a91e0fc382d7c0"}, - {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6db4667b187a6742b33afbbaf05a7bc551ffcf1ced0000a571aedbb4aa42fc7b"}, - {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55fdc093b5a3cb41d420884cdaf37a1e74c3c37a31f46e66286d9145d2063bd0"}, - {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82e8211d69a4f4bc360ea22cd6555f8e61a1bd211d1d5d39d3d228b48c83a897"}, - {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89aa2c2eeb20957be2d950b85974b30a01a762f3308cd02bb15e1ad632e22dc7"}, - {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9d3e0c25a2350080e9319724dede4f31f43a6c9779be48021a7f4ebde8b2d742"}, - {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7268252af60904bf52c26173cbadc3a071cece75f873705419c8681f24d3edea"}, - {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:0c250a29735d4f15321007fb02865f0e6b6a41a6b88f1f523ca1596ab5f50bd5"}, - {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:96ec70beabbd3b10e8bfe52616a13561e58fe84c0101dd031dc78f250d5128b9"}, - {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:23b2d7679b73fe0e5a4560b672a39f98dfc6f60df63823b0a9970525325b95f6"}, - {file = "frozenlist-1.4.1-cp39-cp39-win32.whl", hash = "sha256:a7496bfe1da7fb1a4e1cc23bb67c58fab69311cc7d32b5a99c2007b4b2a0e932"}, - {file = "frozenlist-1.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:e6a20a581f9ce92d389a8c7d7c3dd47c81fd5d6e655c8dddf341e14aa48659d0"}, - {file = "frozenlist-1.4.1-py3-none-any.whl", hash = "sha256:04ced3e6a46b4cfffe20f9ae482818e34eba9b5fb0ce4056e4cc9b6e212d09b7"}, - {file = "frozenlist-1.4.1.tar.gz", hash = "sha256:c037a86e8513059a2613aaba4d817bb90b9d9b6b69aace3ce9c877e8c8ed402b"}, + {file = "frozenlist-1.5.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5b6a66c18b5b9dd261ca98dffcb826a525334b2f29e7caa54e182255c5f6a65a"}, + {file = "frozenlist-1.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d1b3eb7b05ea246510b43a7e53ed1653e55c2121019a97e60cad7efb881a97bb"}, + {file = "frozenlist-1.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:15538c0cbf0e4fa11d1e3a71f823524b0c46299aed6e10ebb4c2089abd8c3bec"}, + {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e79225373c317ff1e35f210dd5f1344ff31066ba8067c307ab60254cd3a78ad5"}, + {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9272fa73ca71266702c4c3e2d4a28553ea03418e591e377a03b8e3659d94fa76"}, + {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:498524025a5b8ba81695761d78c8dd7382ac0b052f34e66939c42df860b8ff17"}, + {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:92b5278ed9d50fe610185ecd23c55d8b307d75ca18e94c0e7de328089ac5dcba"}, + {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f3c8c1dacd037df16e85227bac13cca58c30da836c6f936ba1df0c05d046d8d"}, + {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f2ac49a9bedb996086057b75bf93538240538c6d9b38e57c82d51f75a73409d2"}, + {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e66cc454f97053b79c2ab09c17fbe3c825ea6b4de20baf1be28919460dd7877f"}, + {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:5a3ba5f9a0dfed20337d3e966dc359784c9f96503674c2faf015f7fe8e96798c"}, + {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6321899477db90bdeb9299ac3627a6a53c7399c8cd58d25da094007402b039ab"}, + {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:76e4753701248476e6286f2ef492af900ea67d9706a0155335a40ea21bf3b2f5"}, + {file = "frozenlist-1.5.0-cp310-cp310-win32.whl", hash = "sha256:977701c081c0241d0955c9586ffdd9ce44f7a7795df39b9151cd9a6fd0ce4cfb"}, + {file = "frozenlist-1.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:189f03b53e64144f90990d29a27ec4f7997d91ed3d01b51fa39d2dbe77540fd4"}, + {file = "frozenlist-1.5.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:fd74520371c3c4175142d02a976aee0b4cb4a7cc912a60586ffd8d5929979b30"}, + {file = "frozenlist-1.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2f3f7a0fbc219fb4455264cae4d9f01ad41ae6ee8524500f381de64ffaa077d5"}, + {file = "frozenlist-1.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f47c9c9028f55a04ac254346e92977bf0f166c483c74b4232bee19a6697e4778"}, + {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0996c66760924da6e88922756d99b47512a71cfd45215f3570bf1e0b694c206a"}, + {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a2fe128eb4edeabe11896cb6af88fca5346059f6c8d807e3b910069f39157869"}, + {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a8ea951bbb6cacd492e3948b8da8c502a3f814f5d20935aae74b5df2b19cf3d"}, + {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de537c11e4aa01d37db0d403b57bd6f0546e71a82347a97c6a9f0dcc532b3a45"}, + {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c2623347b933fcb9095841f1cc5d4ff0b278addd743e0e966cb3d460278840d"}, + {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cee6798eaf8b1416ef6909b06f7dc04b60755206bddc599f52232606e18179d3"}, + {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f5f9da7f5dbc00a604fe74aa02ae7c98bcede8a3b8b9666f9f86fc13993bc71a"}, + {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:90646abbc7a5d5c7c19461d2e3eeb76eb0b204919e6ece342feb6032c9325ae9"}, + {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:bdac3c7d9b705d253b2ce370fde941836a5f8b3c5c2b8fd70940a3ea3af7f4f2"}, + {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:03d33c2ddbc1816237a67f66336616416e2bbb6beb306e5f890f2eb22b959cdf"}, + {file = "frozenlist-1.5.0-cp311-cp311-win32.whl", hash = "sha256:237f6b23ee0f44066219dae14c70ae38a63f0440ce6750f868ee08775073f942"}, + {file = "frozenlist-1.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:0cc974cc93d32c42e7b0f6cf242a6bd941c57c61b618e78b6c0a96cb72788c1d"}, + {file = "frozenlist-1.5.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:31115ba75889723431aa9a4e77d5f398f5cf976eea3bdf61749731f62d4a4a21"}, + {file = "frozenlist-1.5.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7437601c4d89d070eac8323f121fcf25f88674627505334654fd027b091db09d"}, + {file = "frozenlist-1.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7948140d9f8ece1745be806f2bfdf390127cf1a763b925c4a805c603df5e697e"}, + {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:feeb64bc9bcc6b45c6311c9e9b99406660a9c05ca8a5b30d14a78555088b0b3a"}, + {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:683173d371daad49cffb8309779e886e59c2f369430ad28fe715f66d08d4ab1a"}, + {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7d57d8f702221405a9d9b40f9da8ac2e4a1a8b5285aac6100f3393675f0a85ee"}, + {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:30c72000fbcc35b129cb09956836c7d7abf78ab5416595e4857d1cae8d6251a6"}, + {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:000a77d6034fbad9b6bb880f7ec073027908f1b40254b5d6f26210d2dab1240e"}, + {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5d7f5a50342475962eb18b740f3beecc685a15b52c91f7d975257e13e029eca9"}, + {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:87f724d055eb4785d9be84e9ebf0f24e392ddfad00b3fe036e43f489fafc9039"}, + {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:6e9080bb2fb195a046e5177f10d9d82b8a204c0736a97a153c2466127de87784"}, + {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9b93d7aaa36c966fa42efcaf716e6b3900438632a626fb09c049f6a2f09fc631"}, + {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:52ef692a4bc60a6dd57f507429636c2af8b6046db8b31b18dac02cbc8f507f7f"}, + {file = "frozenlist-1.5.0-cp312-cp312-win32.whl", hash = "sha256:29d94c256679247b33a3dc96cce0f93cbc69c23bf75ff715919332fdbb6a32b8"}, + {file = "frozenlist-1.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:8969190d709e7c48ea386db202d708eb94bdb29207a1f269bab1196ce0dcca1f"}, + {file = "frozenlist-1.5.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7a1a048f9215c90973402e26c01d1cff8a209e1f1b53f72b95c13db61b00f953"}, + {file = "frozenlist-1.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dd47a5181ce5fcb463b5d9e17ecfdb02b678cca31280639255ce9d0e5aa67af0"}, + {file = "frozenlist-1.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1431d60b36d15cda188ea222033eec8e0eab488f39a272461f2e6d9e1a8e63c2"}, + {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6482a5851f5d72767fbd0e507e80737f9c8646ae7fd303def99bfe813f76cf7f"}, + {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:44c49271a937625619e862baacbd037a7ef86dd1ee215afc298a417ff3270608"}, + {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:12f78f98c2f1c2429d42e6a485f433722b0061d5c0b0139efa64f396efb5886b"}, + {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce3aa154c452d2467487765e3adc730a8c153af77ad84096bc19ce19a2400840"}, + {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b7dc0c4338e6b8b091e8faf0db3168a37101943e687f373dce00959583f7439"}, + {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:45e0896250900b5aa25180f9aec243e84e92ac84bd4a74d9ad4138ef3f5c97de"}, + {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:561eb1c9579d495fddb6da8959fd2a1fca2c6d060d4113f5844b433fc02f2641"}, + {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:df6e2f325bfee1f49f81aaac97d2aa757c7646534a06f8f577ce184afe2f0a9e"}, + {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:140228863501b44b809fb39ec56b5d4071f4d0aa6d216c19cbb08b8c5a7eadb9"}, + {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7707a25d6a77f5d27ea7dc7d1fc608aa0a478193823f88511ef5e6b8a48f9d03"}, + {file = "frozenlist-1.5.0-cp313-cp313-win32.whl", hash = "sha256:31a9ac2b38ab9b5a8933b693db4939764ad3f299fcaa931a3e605bc3460e693c"}, + {file = "frozenlist-1.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:11aabdd62b8b9c4b84081a3c246506d1cddd2dd93ff0ad53ede5defec7886b28"}, + {file = "frozenlist-1.5.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:dd94994fc91a6177bfaafd7d9fd951bc8689b0a98168aa26b5f543868548d3ca"}, + {file = "frozenlist-1.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2d0da8bbec082bf6bf18345b180958775363588678f64998c2b7609e34719b10"}, + {file = "frozenlist-1.5.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:73f2e31ea8dd7df61a359b731716018c2be196e5bb3b74ddba107f694fbd7604"}, + {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:828afae9f17e6de596825cf4228ff28fbdf6065974e5ac1410cecc22f699d2b3"}, + {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1577515d35ed5649d52ab4319db757bb881ce3b2b796d7283e6634d99ace307"}, + {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2150cc6305a2c2ab33299453e2968611dacb970d2283a14955923062c8d00b10"}, + {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a72b7a6e3cd2725eff67cd64c8f13335ee18fc3c7befc05aed043d24c7b9ccb9"}, + {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c16d2fa63e0800723139137d667e1056bee1a1cf7965153d2d104b62855e9b99"}, + {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:17dcc32fc7bda7ce5875435003220a457bcfa34ab7924a49a1c19f55b6ee185c"}, + {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:97160e245ea33d8609cd2b8fd997c850b56db147a304a262abc2b3be021a9171"}, + {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:f1e6540b7fa044eee0bb5111ada694cf3dc15f2b0347ca125ee9ca984d5e9e6e"}, + {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:91d6c171862df0a6c61479d9724f22efb6109111017c87567cfeb7b5d1449fdf"}, + {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:c1fac3e2ace2eb1052e9f7c7db480818371134410e1f5c55d65e8f3ac6d1407e"}, + {file = "frozenlist-1.5.0-cp38-cp38-win32.whl", hash = "sha256:b97f7b575ab4a8af9b7bc1d2ef7f29d3afee2226bd03ca3875c16451ad5a7723"}, + {file = "frozenlist-1.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:374ca2dabdccad8e2a76d40b1d037f5bd16824933bf7bcea3e59c891fd4a0923"}, + {file = "frozenlist-1.5.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9bbcdfaf4af7ce002694a4e10a0159d5a8d20056a12b05b45cea944a4953f972"}, + {file = "frozenlist-1.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1893f948bf6681733aaccf36c5232c231e3b5166d607c5fa77773611df6dc336"}, + {file = "frozenlist-1.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2b5e23253bb709ef57a8e95e6ae48daa9ac5f265637529e4ce6b003a37b2621f"}, + {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f253985bb515ecd89629db13cb58d702035ecd8cfbca7d7a7e29a0e6d39af5f"}, + {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:04a5c6babd5e8fb7d3c871dc8b321166b80e41b637c31a995ed844a6139942b6"}, + {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9fe0f1c29ba24ba6ff6abf688cb0b7cf1efab6b6aa6adc55441773c252f7411"}, + {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:226d72559fa19babe2ccd920273e767c96a49b9d3d38badd7c91a0fdeda8ea08"}, + {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15b731db116ab3aedec558573c1a5eec78822b32292fe4f2f0345b7f697745c2"}, + {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:366d8f93e3edfe5a918c874702f78faac300209a4d5bf38352b2c1bdc07a766d"}, + {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1b96af8c582b94d381a1c1f51ffaedeb77c821c690ea5f01da3d70a487dd0a9b"}, + {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:c03eff4a41bd4e38415cbed054bbaff4a075b093e2394b6915dca34a40d1e38b"}, + {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:50cf5e7ee9b98f22bdecbabf3800ae78ddcc26e4a435515fc72d97903e8488e0"}, + {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1e76bfbc72353269c44e0bc2cfe171900fbf7f722ad74c9a7b638052afe6a00c"}, + {file = "frozenlist-1.5.0-cp39-cp39-win32.whl", hash = "sha256:666534d15ba8f0fda3f53969117383d5dc021266b3c1a42c9ec4855e4b58b9d3"}, + {file = "frozenlist-1.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:5c28f4b5dbef8a0d8aad0d4de24d1e9e981728628afaf4ea0792f5d0939372f0"}, + {file = "frozenlist-1.5.0-py3-none-any.whl", hash = "sha256:d994863bba198a4a518b467bb971c56e1db3f180a25c6cf7bb1949c267f748c3"}, + {file = "frozenlist-1.5.0.tar.gz", hash = "sha256:81d5af29e61b9c8348e876d442253723928dce6433e0e76cd925cd83f1b4b817"}, ] [[package]] name = "idna" -version = "3.7" +version = "3.10" description = "Internationalized Domain Names in Applications (IDNA)" optional = false -python-versions = ">=3.5" +python-versions = ">=3.6" files = [ - {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, - {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, + {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, + {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, ] +[package.extras] +all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] + [[package]] name = "iniconfig" -version = "2.0.0" +version = "2.1.0" description = "brain-dead simple config-ini parsing" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, - {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, + {file = "iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760"}, + {file = "iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7"}, ] [[package]] name = "multidict" -version = "6.0.5" +version = "6.1.0" description = "multidict implementation" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "multidict-6.0.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:228b644ae063c10e7f324ab1ab6b548bdf6f8b47f3ec234fef1093bc2735e5f9"}, - {file = "multidict-6.0.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:896ebdcf62683551312c30e20614305f53125750803b614e9e6ce74a96232604"}, - {file = "multidict-6.0.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:411bf8515f3be9813d06004cac41ccf7d1cd46dfe233705933dd163b60e37600"}, - {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d147090048129ce3c453f0292e7697d333db95e52616b3793922945804a433c"}, - {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:215ed703caf15f578dca76ee6f6b21b7603791ae090fbf1ef9d865571039ade5"}, - {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c6390cf87ff6234643428991b7359b5f59cc15155695deb4eda5c777d2b880f"}, - {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21fd81c4ebdb4f214161be351eb5bcf385426bf023041da2fd9e60681f3cebae"}, - {file = "multidict-6.0.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3cc2ad10255f903656017363cd59436f2111443a76f996584d1077e43ee51182"}, - {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6939c95381e003f54cd4c5516740faba40cf5ad3eeff460c3ad1d3e0ea2549bf"}, - {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:220dd781e3f7af2c2c1053da9fa96d9cf3072ca58f057f4c5adaaa1cab8fc442"}, - {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:766c8f7511df26d9f11cd3a8be623e59cca73d44643abab3f8c8c07620524e4a"}, - {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:fe5d7785250541f7f5019ab9cba2c71169dc7d74d0f45253f8313f436458a4ef"}, - {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c1c1496e73051918fcd4f58ff2e0f2f3066d1c76a0c6aeffd9b45d53243702cc"}, - {file = "multidict-6.0.5-cp310-cp310-win32.whl", hash = "sha256:7afcdd1fc07befad18ec4523a782cde4e93e0a2bf71239894b8d61ee578c1319"}, - {file = "multidict-6.0.5-cp310-cp310-win_amd64.whl", hash = "sha256:99f60d34c048c5c2fabc766108c103612344c46e35d4ed9ae0673d33c8fb26e8"}, - {file = "multidict-6.0.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f285e862d2f153a70586579c15c44656f888806ed0e5b56b64489afe4a2dbfba"}, - {file = "multidict-6.0.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:53689bb4e102200a4fafa9de9c7c3c212ab40a7ab2c8e474491914d2305f187e"}, - {file = "multidict-6.0.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:612d1156111ae11d14afaf3a0669ebf6c170dbb735e510a7438ffe2369a847fd"}, - {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7be7047bd08accdb7487737631d25735c9a04327911de89ff1b26b81745bd4e3"}, - {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de170c7b4fe6859beb8926e84f7d7d6c693dfe8e27372ce3b76f01c46e489fcf"}, - {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04bde7a7b3de05732a4eb39c94574db1ec99abb56162d6c520ad26f83267de29"}, - {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85f67aed7bb647f93e7520633d8f51d3cbc6ab96957c71272b286b2f30dc70ed"}, - {file = "multidict-6.0.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425bf820055005bfc8aa9a0b99ccb52cc2f4070153e34b701acc98d201693733"}, - {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d3eb1ceec286eba8220c26f3b0096cf189aea7057b6e7b7a2e60ed36b373b77f"}, - {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7901c05ead4b3fb75113fb1dd33eb1253c6d3ee37ce93305acd9d38e0b5f21a4"}, - {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:e0e79d91e71b9867c73323a3444724d496c037e578a0e1755ae159ba14f4f3d1"}, - {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:29bfeb0dff5cb5fdab2023a7a9947b3b4af63e9c47cae2a10ad58394b517fddc"}, - {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e030047e85cbcedbfc073f71836d62dd5dadfbe7531cae27789ff66bc551bd5e"}, - {file = "multidict-6.0.5-cp311-cp311-win32.whl", hash = "sha256:2f4848aa3baa109e6ab81fe2006c77ed4d3cd1e0ac2c1fbddb7b1277c168788c"}, - {file = "multidict-6.0.5-cp311-cp311-win_amd64.whl", hash = "sha256:2faa5ae9376faba05f630d7e5e6be05be22913782b927b19d12b8145968a85ea"}, - {file = "multidict-6.0.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:51d035609b86722963404f711db441cf7134f1889107fb171a970c9701f92e1e"}, - {file = "multidict-6.0.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cbebcd5bcaf1eaf302617c114aa67569dd3f090dd0ce8ba9e35e9985b41ac35b"}, - {file = "multidict-6.0.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2ffc42c922dbfddb4a4c3b438eb056828719f07608af27d163191cb3e3aa6cc5"}, - {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ceb3b7e6a0135e092de86110c5a74e46bda4bd4fbfeeb3a3bcec79c0f861e450"}, - {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:79660376075cfd4b2c80f295528aa6beb2058fd289f4c9252f986751a4cd0496"}, - {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e4428b29611e989719874670fd152b6625500ad6c686d464e99f5aaeeaca175a"}, - {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d84a5c3a5f7ce6db1f999fb9438f686bc2e09d38143f2d93d8406ed2dd6b9226"}, - {file = "multidict-6.0.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:76c0de87358b192de7ea9649beb392f107dcad9ad27276324c24c91774ca5271"}, - {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:79a6d2ba910adb2cbafc95dad936f8b9386e77c84c35bc0add315b856d7c3abb"}, - {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:92d16a3e275e38293623ebf639c471d3e03bb20b8ebb845237e0d3664914caef"}, - {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:fb616be3538599e797a2017cccca78e354c767165e8858ab5116813146041a24"}, - {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:14c2976aa9038c2629efa2c148022ed5eb4cb939e15ec7aace7ca932f48f9ba6"}, - {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:435a0984199d81ca178b9ae2c26ec3d49692d20ee29bc4c11a2a8d4514c67eda"}, - {file = "multidict-6.0.5-cp312-cp312-win32.whl", hash = "sha256:9fe7b0653ba3d9d65cbe7698cca585bf0f8c83dbbcc710db9c90f478e175f2d5"}, - {file = "multidict-6.0.5-cp312-cp312-win_amd64.whl", hash = "sha256:01265f5e40f5a17f8241d52656ed27192be03bfa8764d88e8220141d1e4b3556"}, - {file = "multidict-6.0.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:19fe01cea168585ba0f678cad6f58133db2aa14eccaf22f88e4a6dccadfad8b3"}, - {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bf7a982604375a8d49b6cc1b781c1747f243d91b81035a9b43a2126c04766f5"}, - {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:107c0cdefe028703fb5dafe640a409cb146d44a6ae201e55b35a4af8e95457dd"}, - {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:403c0911cd5d5791605808b942c88a8155c2592e05332d2bf78f18697a5fa15e"}, - {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aeaf541ddbad8311a87dd695ed9642401131ea39ad7bc8cf3ef3967fd093b626"}, - {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e4972624066095e52b569e02b5ca97dbd7a7ddd4294bf4e7247d52635630dd83"}, - {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d946b0a9eb8aaa590df1fe082cee553ceab173e6cb5b03239716338629c50c7a"}, - {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b55358304d7a73d7bdf5de62494aaf70bd33015831ffd98bc498b433dfe5b10c"}, - {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:a3145cb08d8625b2d3fee1b2d596a8766352979c9bffe5d7833e0503d0f0b5e5"}, - {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:d65f25da8e248202bd47445cec78e0025c0fe7582b23ec69c3b27a640dd7a8e3"}, - {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c9bf56195c6bbd293340ea82eafd0071cb3d450c703d2c93afb89f93b8386ccc"}, - {file = "multidict-6.0.5-cp37-cp37m-win32.whl", hash = "sha256:69db76c09796b313331bb7048229e3bee7928eb62bab5e071e9f7fcc4879caee"}, - {file = "multidict-6.0.5-cp37-cp37m-win_amd64.whl", hash = "sha256:fce28b3c8a81b6b36dfac9feb1de115bab619b3c13905b419ec71d03a3fc1423"}, - {file = "multidict-6.0.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:76f067f5121dcecf0d63a67f29080b26c43c71a98b10c701b0677e4a065fbd54"}, - {file = "multidict-6.0.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b82cc8ace10ab5bd93235dfaab2021c70637005e1ac787031f4d1da63d493c1d"}, - {file = "multidict-6.0.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5cb241881eefd96b46f89b1a056187ea8e9ba14ab88ba632e68d7a2ecb7aadf7"}, - {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8e94e6912639a02ce173341ff62cc1201232ab86b8a8fcc05572741a5dc7d93"}, - {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09a892e4a9fb47331da06948690ae38eaa2426de97b4ccbfafbdcbe5c8f37ff8"}, - {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55205d03e8a598cfc688c71ca8ea5f66447164efff8869517f175ea632c7cb7b"}, - {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37b15024f864916b4951adb95d3a80c9431299080341ab9544ed148091b53f50"}, - {file = "multidict-6.0.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2a1dee728b52b33eebff5072817176c172050d44d67befd681609b4746e1c2e"}, - {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:edd08e6f2f1a390bf137080507e44ccc086353c8e98c657e666c017718561b89"}, - {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:60d698e8179a42ec85172d12f50b1668254628425a6bd611aba022257cac1386"}, - {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:3d25f19500588cbc47dc19081d78131c32637c25804df8414463ec908631e453"}, - {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:4cc0ef8b962ac7a5e62b9e826bd0cd5040e7d401bc45a6835910ed699037a461"}, - {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:eca2e9d0cc5a889850e9bbd68e98314ada174ff6ccd1129500103df7a94a7a44"}, - {file = "multidict-6.0.5-cp38-cp38-win32.whl", hash = "sha256:4a6a4f196f08c58c59e0b8ef8ec441d12aee4125a7d4f4fef000ccb22f8d7241"}, - {file = "multidict-6.0.5-cp38-cp38-win_amd64.whl", hash = "sha256:0275e35209c27a3f7951e1ce7aaf93ce0d163b28948444bec61dd7badc6d3f8c"}, - {file = "multidict-6.0.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e7be68734bd8c9a513f2b0cfd508802d6609da068f40dc57d4e3494cefc92929"}, - {file = "multidict-6.0.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1d9ea7a7e779d7a3561aade7d596649fbecfa5c08a7674b11b423783217933f9"}, - {file = "multidict-6.0.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ea1456df2a27c73ce51120fa2f519f1bea2f4a03a917f4a43c8707cf4cbbae1a"}, - {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf590b134eb70629e350691ecca88eac3e3b8b3c86992042fb82e3cb1830d5e1"}, - {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5c0631926c4f58e9a5ccce555ad7747d9a9f8b10619621f22f9635f069f6233e"}, - {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dce1c6912ab9ff5f179eaf6efe7365c1f425ed690b03341911bf4939ef2f3046"}, - {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0868d64af83169e4d4152ec612637a543f7a336e4a307b119e98042e852ad9c"}, - {file = "multidict-6.0.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:141b43360bfd3bdd75f15ed811850763555a251e38b2405967f8e25fb43f7d40"}, - {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7df704ca8cf4a073334e0427ae2345323613e4df18cc224f647f251e5e75a527"}, - {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6214c5a5571802c33f80e6c84713b2c79e024995b9c5897f794b43e714daeec9"}, - {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:cd6c8fca38178e12c00418de737aef1261576bd1b6e8c6134d3e729a4e858b38"}, - {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:e02021f87a5b6932fa6ce916ca004c4d441509d33bbdbeca70d05dff5e9d2479"}, - {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ebd8d160f91a764652d3e51ce0d2956b38efe37c9231cd82cfc0bed2e40b581c"}, - {file = "multidict-6.0.5-cp39-cp39-win32.whl", hash = "sha256:04da1bb8c8dbadf2a18a452639771951c662c5ad03aefe4884775454be322c9b"}, - {file = "multidict-6.0.5-cp39-cp39-win_amd64.whl", hash = "sha256:d6f6d4f185481c9669b9447bf9d9cf3b95a0e9df9d169bbc17e363b7d5487755"}, - {file = "multidict-6.0.5-py3-none-any.whl", hash = "sha256:0d63c74e3d7ab26de115c49bffc92cc77ed23395303d496eae515d4204a625e7"}, - {file = "multidict-6.0.5.tar.gz", hash = "sha256:f7e301075edaf50500f0b341543c41194d8df3ae5caf4702f2095f3ca73dd8da"}, + {file = "multidict-6.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3380252550e372e8511d49481bd836264c009adb826b23fefcc5dd3c69692f60"}, + {file = "multidict-6.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:99f826cbf970077383d7de805c0681799491cb939c25450b9b5b3ced03ca99f1"}, + {file = "multidict-6.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a114d03b938376557927ab23f1e950827c3b893ccb94b62fd95d430fd0e5cf53"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1c416351ee6271b2f49b56ad7f308072f6f44b37118d69c2cad94f3fa8a40d5"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6b5d83030255983181005e6cfbac1617ce9746b219bc2aad52201ad121226581"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3e97b5e938051226dc025ec80980c285b053ffb1e25a3db2a3aa3bc046bf7f56"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d618649d4e70ac6efcbba75be98b26ef5078faad23592f9b51ca492953012429"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10524ebd769727ac77ef2278390fb0068d83f3acb7773792a5080f2b0abf7748"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ff3827aef427c89a25cc96ded1759271a93603aba9fb977a6d264648ebf989db"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:06809f4f0f7ab7ea2cabf9caca7d79c22c0758b58a71f9d32943ae13c7ace056"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f179dee3b863ab1c59580ff60f9d99f632f34ccb38bf67a33ec6b3ecadd0fd76"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:aaed8b0562be4a0876ee3b6946f6869b7bcdb571a5d1496683505944e268b160"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3c8b88a2ccf5493b6c8da9076fb151ba106960a2df90c2633f342f120751a9e7"}, + {file = "multidict-6.1.0-cp310-cp310-win32.whl", hash = "sha256:4a9cb68166a34117d6646c0023c7b759bf197bee5ad4272f420a0141d7eb03a0"}, + {file = "multidict-6.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:20b9b5fbe0b88d0bdef2012ef7dee867f874b72528cf1d08f1d59b0e3850129d"}, + {file = "multidict-6.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3efe2c2cb5763f2f1b275ad2bf7a287d3f7ebbef35648a9726e3b69284a4f3d6"}, + {file = "multidict-6.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7053d3b0353a8b9de430a4f4b4268ac9a4fb3481af37dfe49825bf45ca24156"}, + {file = "multidict-6.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:27e5fc84ccef8dfaabb09d82b7d179c7cf1a3fbc8a966f8274fcb4ab2eb4cadb"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e2b90b43e696f25c62656389d32236e049568b39320e2735d51f08fd362761b"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d83a047959d38a7ff552ff94be767b7fd79b831ad1cd9920662db05fec24fe72"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1a9dd711d0877a1ece3d2e4fea11a8e75741ca21954c919406b44e7cf971304"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec2abea24d98246b94913b76a125e855eb5c434f7c46546046372fe60f666351"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4867cafcbc6585e4b678876c489b9273b13e9fff9f6d6d66add5e15d11d926cb"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5b48204e8d955c47c55b72779802b219a39acc3ee3d0116d5080c388970b76e3"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:d8fff389528cad1618fb4b26b95550327495462cd745d879a8c7c2115248e399"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a7a9541cd308eed5e30318430a9c74d2132e9a8cb46b901326272d780bf2d423"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:da1758c76f50c39a2efd5e9859ce7d776317eb1dd34317c8152ac9251fc574a3"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c943a53e9186688b45b323602298ab727d8865d8c9ee0b17f8d62d14b56f0753"}, + {file = "multidict-6.1.0-cp311-cp311-win32.whl", hash = "sha256:90f8717cb649eea3504091e640a1b8568faad18bd4b9fcd692853a04475a4b80"}, + {file = "multidict-6.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:82176036e65644a6cc5bd619f65f6f19781e8ec2e5330f51aa9ada7504cc1926"}, + {file = "multidict-6.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b04772ed465fa3cc947db808fa306d79b43e896beb677a56fb2347ca1a49c1fa"}, + {file = "multidict-6.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6180c0ae073bddeb5a97a38c03f30c233e0a4d39cd86166251617d1bbd0af436"}, + {file = "multidict-6.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:071120490b47aa997cca00666923a83f02c7fbb44f71cf7f136df753f7fa8761"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50b3a2710631848991d0bf7de077502e8994c804bb805aeb2925a981de58ec2e"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b58c621844d55e71c1b7f7c498ce5aa6985d743a1a59034c57a905b3f153c1ef"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55b6d90641869892caa9ca42ff913f7ff1c5ece06474fbd32fb2cf6834726c95"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b820514bfc0b98a30e3d85462084779900347e4d49267f747ff54060cc33925"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10a9b09aba0c5b48c53761b7c720aaaf7cf236d5fe394cd399c7ba662d5f9966"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1e16bf3e5fc9f44632affb159d30a437bfe286ce9e02754759be5536b169b305"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:76f364861c3bfc98cbbcbd402d83454ed9e01a5224bb3a28bf70002a230f73e2"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:820c661588bd01a0aa62a1283f20d2be4281b086f80dad9e955e690c75fb54a2"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:0e5f362e895bc5b9e67fe6e4ded2492d8124bdf817827f33c5b46c2fe3ffaca6"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3ec660d19bbc671e3a6443325f07263be452c453ac9e512f5eb935e7d4ac28b3"}, + {file = "multidict-6.1.0-cp312-cp312-win32.whl", hash = "sha256:58130ecf8f7b8112cdb841486404f1282b9c86ccb30d3519faf301b2e5659133"}, + {file = "multidict-6.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:188215fc0aafb8e03341995e7c4797860181562380f81ed0a87ff455b70bf1f1"}, + {file = "multidict-6.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:d569388c381b24671589335a3be6e1d45546c2988c2ebe30fdcada8457a31008"}, + {file = "multidict-6.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:052e10d2d37810b99cc170b785945421141bf7bb7d2f8799d431e7db229c385f"}, + {file = "multidict-6.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f90c822a402cb865e396a504f9fc8173ef34212a342d92e362ca498cad308e28"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b225d95519a5bf73860323e633a664b0d85ad3d5bede6d30d95b35d4dfe8805b"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:23bfd518810af7de1116313ebd9092cb9aa629beb12f6ed631ad53356ed6b86c"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c09fcfdccdd0b57867577b719c69e347a436b86cd83747f179dbf0cc0d4c1f3"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf6bea52ec97e95560af5ae576bdac3aa3aae0b6758c6efa115236d9e07dae44"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57feec87371dbb3520da6192213c7d6fc892d5589a93db548331954de8248fd2"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0c3f390dc53279cbc8ba976e5f8035eab997829066756d811616b652b00a23a3"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:59bfeae4b25ec05b34f1956eaa1cb38032282cd4dfabc5056d0a1ec4d696d3aa"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b2f59caeaf7632cc633b5cf6fc449372b83bbdf0da4ae04d5be36118e46cc0aa"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:37bb93b2178e02b7b618893990941900fd25b6b9ac0fa49931a40aecdf083fe4"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4e9f48f58c2c523d5a06faea47866cd35b32655c46b443f163d08c6d0ddb17d6"}, + {file = "multidict-6.1.0-cp313-cp313-win32.whl", hash = "sha256:3a37ffb35399029b45c6cc33640a92bef403c9fd388acce75cdc88f58bd19a81"}, + {file = "multidict-6.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:e9aa71e15d9d9beaad2c6b9319edcdc0a49a43ef5c0a4c8265ca9ee7d6c67774"}, + {file = "multidict-6.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:db7457bac39421addd0c8449933ac32d8042aae84a14911a757ae6ca3eef1392"}, + {file = "multidict-6.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d094ddec350a2fb899fec68d8353c78233debde9b7d8b4beeafa70825f1c281a"}, + {file = "multidict-6.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5845c1fd4866bb5dd3125d89b90e57ed3138241540897de748cdf19de8a2fca2"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9079dfc6a70abe341f521f78405b8949f96db48da98aeb43f9907f342f627cdc"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3914f5aaa0f36d5d60e8ece6a308ee1c9784cd75ec8151062614657a114c4478"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c08be4f460903e5a9d0f76818db3250f12e9c344e79314d1d570fc69d7f4eae4"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d093be959277cb7dee84b801eb1af388b6ad3ca6a6b6bf1ed7585895789d027d"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3702ea6872c5a2a4eeefa6ffd36b042e9773f05b1f37ae3ef7264b1163c2dcf6"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:2090f6a85cafc5b2db085124d752757c9d251548cedabe9bd31afe6363e0aff2"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:f67f217af4b1ff66c68a87318012de788dd95fcfeb24cc889011f4e1c7454dfd"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:189f652a87e876098bbc67b4da1049afb5f5dfbaa310dd67c594b01c10388db6"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:6bb5992037f7a9eff7991ebe4273ea7f51f1c1c511e6a2ce511d0e7bdb754492"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:ac10f4c2b9e770c4e393876e35a7046879d195cd123b4f116d299d442b335bcd"}, + {file = "multidict-6.1.0-cp38-cp38-win32.whl", hash = "sha256:e27bbb6d14416713a8bd7aaa1313c0fc8d44ee48d74497a0ff4c3a1b6ccb5167"}, + {file = "multidict-6.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:22f3105d4fb15c8f57ff3959a58fcab6ce36814486500cd7485651230ad4d4ef"}, + {file = "multidict-6.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:4e18b656c5e844539d506a0a06432274d7bd52a7487e6828c63a63d69185626c"}, + {file = "multidict-6.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a185f876e69897a6f3325c3f19f26a297fa058c5e456bfcff8015e9a27e83ae1"}, + {file = "multidict-6.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ab7c4ceb38d91570a650dba194e1ca87c2b543488fe9309b4212694174fd539c"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e617fb6b0b6953fffd762669610c1c4ffd05632c138d61ac7e14ad187870669c"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:16e5f4bf4e603eb1fdd5d8180f1a25f30056f22e55ce51fb3d6ad4ab29f7d96f"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4c035da3f544b1882bac24115f3e2e8760f10a0107614fc9839fd232200b875"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:957cf8e4b6e123a9eea554fa7ebc85674674b713551de587eb318a2df3e00255"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:483a6aea59cb89904e1ceabd2b47368b5600fb7de78a6e4a2c2987b2d256cf30"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:87701f25a2352e5bf7454caa64757642734da9f6b11384c1f9d1a8e699758057"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:682b987361e5fd7a139ed565e30d81fd81e9629acc7d925a205366877d8c8657"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ce2186a7df133a9c895dea3331ddc5ddad42cdd0d1ea2f0a51e5d161e4762f28"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:9f636b730f7e8cb19feb87094949ba54ee5357440b9658b2a32a5ce4bce53972"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:73eae06aa53af2ea5270cc066dcaf02cc60d2994bbb2c4ef5764949257d10f43"}, + {file = "multidict-6.1.0-cp39-cp39-win32.whl", hash = "sha256:1ca0083e80e791cffc6efce7660ad24af66c8d4079d2a750b29001b53ff59ada"}, + {file = "multidict-6.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:aa466da5b15ccea564bdab9c89175c762bc12825f4659c11227f515cee76fa4a"}, + {file = "multidict-6.1.0-py3-none-any.whl", hash = "sha256:48e171e52d1c4d33888e529b999e5900356b9ae588c2f09a52dcefb158b27506"}, + {file = "multidict-6.1.0.tar.gz", hash = "sha256:22ae2ebf9b0c69d206c003e2f6a914ea33f0a932d4aa16f236afc049d9958f4a"}, ] +[package.dependencies] +typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.11\""} + [[package]] name = "numpy" version = "1.24.4" @@ -665,128 +691,214 @@ files = [ [[package]] name = "numpy" -version = "2.0.1" +version = "2.0.2" description = "Fundamental package for array computing in Python" optional = false python-versions = ">=3.9" files = [ - {file = "numpy-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0fbb536eac80e27a2793ffd787895242b7f18ef792563d742c2d673bfcb75134"}, - {file = "numpy-2.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:69ff563d43c69b1baba77af455dd0a839df8d25e8590e79c90fcbe1499ebde42"}, - {file = "numpy-2.0.1-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:1b902ce0e0a5bb7704556a217c4f63a7974f8f43e090aff03fcf262e0b135e02"}, - {file = "numpy-2.0.1-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:f1659887361a7151f89e79b276ed8dff3d75877df906328f14d8bb40bb4f5101"}, - {file = "numpy-2.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4658c398d65d1b25e1760de3157011a80375da861709abd7cef3bad65d6543f9"}, - {file = "numpy-2.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4127d4303b9ac9f94ca0441138acead39928938660ca58329fe156f84b9f3015"}, - {file = "numpy-2.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e5eeca8067ad04bc8a2a8731183d51d7cbaac66d86085d5f4766ee6bf19c7f87"}, - {file = "numpy-2.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9adbd9bb520c866e1bfd7e10e1880a1f7749f1f6e5017686a5fbb9b72cf69f82"}, - {file = "numpy-2.0.1-cp310-cp310-win32.whl", hash = "sha256:7b9853803278db3bdcc6cd5beca37815b133e9e77ff3d4733c247414e78eb8d1"}, - {file = "numpy-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:81b0893a39bc5b865b8bf89e9ad7807e16717f19868e9d234bdaf9b1f1393868"}, - {file = "numpy-2.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:75b4e316c5902d8163ef9d423b1c3f2f6252226d1aa5cd8a0a03a7d01ffc6268"}, - {file = "numpy-2.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6e4eeb6eb2fced786e32e6d8df9e755ce5be920d17f7ce00bc38fcde8ccdbf9e"}, - {file = "numpy-2.0.1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:a1e01dcaab205fbece13c1410253a9eea1b1c9b61d237b6fa59bcc46e8e89343"}, - {file = "numpy-2.0.1-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:a8fc2de81ad835d999113ddf87d1ea2b0f4704cbd947c948d2f5513deafe5a7b"}, - {file = "numpy-2.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5a3d94942c331dd4e0e1147f7a8699a4aa47dffc11bf8a1523c12af8b2e91bbe"}, - {file = "numpy-2.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15eb4eca47d36ec3f78cde0a3a2ee24cf05ca7396ef808dda2c0ddad7c2bde67"}, - {file = "numpy-2.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b83e16a5511d1b1f8a88cbabb1a6f6a499f82c062a4251892d9ad5d609863fb7"}, - {file = "numpy-2.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1f87fec1f9bc1efd23f4227becff04bd0e979e23ca50cc92ec88b38489db3b55"}, - {file = "numpy-2.0.1-cp311-cp311-win32.whl", hash = "sha256:36d3a9405fd7c511804dc56fc32974fa5533bdeb3cd1604d6b8ff1d292b819c4"}, - {file = "numpy-2.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:08458fbf403bff5e2b45f08eda195d4b0c9b35682311da5a5a0a0925b11b9bd8"}, - {file = "numpy-2.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6bf4e6f4a2a2e26655717a1983ef6324f2664d7011f6ef7482e8c0b3d51e82ac"}, - {file = "numpy-2.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7d6fddc5fe258d3328cd8e3d7d3e02234c5d70e01ebe377a6ab92adb14039cb4"}, - {file = "numpy-2.0.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:5daab361be6ddeb299a918a7c0864fa8618af66019138263247af405018b04e1"}, - {file = "numpy-2.0.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:ea2326a4dca88e4a274ba3a4405eb6c6467d3ffbd8c7d38632502eaae3820587"}, - {file = "numpy-2.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:529af13c5f4b7a932fb0e1911d3a75da204eff023ee5e0e79c1751564221a5c8"}, - {file = "numpy-2.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6790654cb13eab303d8402354fabd47472b24635700f631f041bd0b65e37298a"}, - {file = "numpy-2.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:cbab9fc9c391700e3e1287666dfd82d8666d10e69a6c4a09ab97574c0b7ee0a7"}, - {file = "numpy-2.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:99d0d92a5e3613c33a5f01db206a33f8fdf3d71f2912b0de1739894668b7a93b"}, - {file = "numpy-2.0.1-cp312-cp312-win32.whl", hash = "sha256:173a00b9995f73b79eb0191129f2455f1e34c203f559dd118636858cc452a1bf"}, - {file = "numpy-2.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:bb2124fdc6e62baae159ebcfa368708867eb56806804d005860b6007388df171"}, - {file = "numpy-2.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bfc085b28d62ff4009364e7ca34b80a9a080cbd97c2c0630bb5f7f770dae9414"}, - {file = "numpy-2.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8fae4ebbf95a179c1156fab0b142b74e4ba4204c87bde8d3d8b6f9c34c5825ef"}, - {file = "numpy-2.0.1-cp39-cp39-macosx_14_0_arm64.whl", hash = "sha256:72dc22e9ec8f6eaa206deb1b1355eb2e253899d7347f5e2fae5f0af613741d06"}, - {file = "numpy-2.0.1-cp39-cp39-macosx_14_0_x86_64.whl", hash = "sha256:ec87f5f8aca726117a1c9b7083e7656a9d0d606eec7299cc067bb83d26f16e0c"}, - {file = "numpy-2.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f682ea61a88479d9498bf2091fdcd722b090724b08b31d63e022adc063bad59"}, - {file = "numpy-2.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8efc84f01c1cd7e34b3fb310183e72fcdf55293ee736d679b6d35b35d80bba26"}, - {file = "numpy-2.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3fdabe3e2a52bc4eff8dc7a5044342f8bd9f11ef0934fcd3289a788c0eb10018"}, - {file = "numpy-2.0.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:24a0e1befbfa14615b49ba9659d3d8818a0f4d8a1c5822af8696706fbda7310c"}, - {file = "numpy-2.0.1-cp39-cp39-win32.whl", hash = "sha256:f9cf5ea551aec449206954b075db819f52adc1638d46a6738253a712d553c7b4"}, - {file = "numpy-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:e9e81fa9017eaa416c056e5d9e71be93d05e2c3c2ab308d23307a8bc4443c368"}, - {file = "numpy-2.0.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:61728fba1e464f789b11deb78a57805c70b2ed02343560456190d0501ba37b0f"}, - {file = "numpy-2.0.1-pp39-pypy39_pp73-macosx_14_0_x86_64.whl", hash = "sha256:12f5d865d60fb9734e60a60f1d5afa6d962d8d4467c120a1c0cda6eb2964437d"}, - {file = "numpy-2.0.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eacf3291e263d5a67d8c1a581a8ebbcfd6447204ef58828caf69a5e3e8c75990"}, - {file = "numpy-2.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2c3a346ae20cfd80b6cfd3e60dc179963ef2ea58da5ec074fd3d9e7a1e7ba97f"}, - {file = "numpy-2.0.1.tar.gz", hash = "sha256:485b87235796410c3519a699cfe1faab097e509e90ebb05dcd098db2ae87e7b3"}, + {file = "numpy-2.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:51129a29dbe56f9ca83438b706e2e69a39892b5eda6cedcb6b0c9fdc9b0d3ece"}, + {file = "numpy-2.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f15975dfec0cf2239224d80e32c3170b1d168335eaedee69da84fbe9f1f9cd04"}, + {file = "numpy-2.0.2-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:8c5713284ce4e282544c68d1c3b2c7161d38c256d2eefc93c1d683cf47683e66"}, + {file = "numpy-2.0.2-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:becfae3ddd30736fe1889a37f1f580e245ba79a5855bff5f2a29cb3ccc22dd7b"}, + {file = "numpy-2.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2da5960c3cf0df7eafefd806d4e612c5e19358de82cb3c343631188991566ccd"}, + {file = "numpy-2.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:496f71341824ed9f3d2fd36cf3ac57ae2e0165c143b55c3a035ee219413f3318"}, + {file = "numpy-2.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a61ec659f68ae254e4d237816e33171497e978140353c0c2038d46e63282d0c8"}, + {file = "numpy-2.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d731a1c6116ba289c1e9ee714b08a8ff882944d4ad631fd411106a30f083c326"}, + {file = "numpy-2.0.2-cp310-cp310-win32.whl", hash = "sha256:984d96121c9f9616cd33fbd0618b7f08e0cfc9600a7ee1d6fd9b239186d19d97"}, + {file = "numpy-2.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:c7b0be4ef08607dd04da4092faee0b86607f111d5ae68036f16cc787e250a131"}, + {file = "numpy-2.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:49ca4decb342d66018b01932139c0961a8f9ddc7589611158cb3c27cbcf76448"}, + {file = "numpy-2.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:11a76c372d1d37437857280aa142086476136a8c0f373b2e648ab2c8f18fb195"}, + {file = "numpy-2.0.2-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:807ec44583fd708a21d4a11d94aedf2f4f3c3719035c76a2bbe1fe8e217bdc57"}, + {file = "numpy-2.0.2-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:8cafab480740e22f8d833acefed5cc87ce276f4ece12fdaa2e8903db2f82897a"}, + {file = "numpy-2.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a15f476a45e6e5a3a79d8a14e62161d27ad897381fecfa4a09ed5322f2085669"}, + {file = "numpy-2.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13e689d772146140a252c3a28501da66dfecd77490b498b168b501835041f951"}, + {file = "numpy-2.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9ea91dfb7c3d1c56a0e55657c0afb38cf1eeae4544c208dc465c3c9f3a7c09f9"}, + {file = "numpy-2.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c1c9307701fec8f3f7a1e6711f9089c06e6284b3afbbcd259f7791282d660a15"}, + {file = "numpy-2.0.2-cp311-cp311-win32.whl", hash = "sha256:a392a68bd329eafac5817e5aefeb39038c48b671afd242710b451e76090e81f4"}, + {file = "numpy-2.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:286cd40ce2b7d652a6f22efdfc6d1edf879440e53e76a75955bc0c826c7e64dc"}, + {file = "numpy-2.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:df55d490dea7934f330006d0f81e8551ba6010a5bf035a249ef61a94f21c500b"}, + {file = "numpy-2.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8df823f570d9adf0978347d1f926b2a867d5608f434a7cff7f7908c6570dcf5e"}, + {file = "numpy-2.0.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:9a92ae5c14811e390f3767053ff54eaee3bf84576d99a2456391401323f4ec2c"}, + {file = "numpy-2.0.2-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:a842d573724391493a97a62ebbb8e731f8a5dcc5d285dfc99141ca15a3302d0c"}, + {file = "numpy-2.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c05e238064fc0610c840d1cf6a13bf63d7e391717d247f1bf0318172e759e692"}, + {file = "numpy-2.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0123ffdaa88fa4ab64835dcbde75dcdf89c453c922f18dced6e27c90d1d0ec5a"}, + {file = "numpy-2.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:96a55f64139912d61de9137f11bf39a55ec8faec288c75a54f93dfd39f7eb40c"}, + {file = "numpy-2.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ec9852fb39354b5a45a80bdab5ac02dd02b15f44b3804e9f00c556bf24b4bded"}, + {file = "numpy-2.0.2-cp312-cp312-win32.whl", hash = "sha256:671bec6496f83202ed2d3c8fdc486a8fc86942f2e69ff0e986140339a63bcbe5"}, + {file = "numpy-2.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:cfd41e13fdc257aa5778496b8caa5e856dc4896d4ccf01841daee1d96465467a"}, + {file = "numpy-2.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9059e10581ce4093f735ed23f3b9d283b9d517ff46009ddd485f1747eb22653c"}, + {file = "numpy-2.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:423e89b23490805d2a5a96fe40ec507407b8ee786d66f7328be214f9679df6dd"}, + {file = "numpy-2.0.2-cp39-cp39-macosx_14_0_arm64.whl", hash = "sha256:2b2955fa6f11907cf7a70dab0d0755159bca87755e831e47932367fc8f2f2d0b"}, + {file = "numpy-2.0.2-cp39-cp39-macosx_14_0_x86_64.whl", hash = "sha256:97032a27bd9d8988b9a97a8c4d2c9f2c15a81f61e2f21404d7e8ef00cb5be729"}, + {file = "numpy-2.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e795a8be3ddbac43274f18588329c72939870a16cae810c2b73461c40718ab1"}, + {file = "numpy-2.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f26b258c385842546006213344c50655ff1555a9338e2e5e02a0756dc3e803dd"}, + {file = "numpy-2.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5fec9451a7789926bcf7c2b8d187292c9f93ea30284802a0ab3f5be8ab36865d"}, + {file = "numpy-2.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:9189427407d88ff25ecf8f12469d4d39d35bee1db5d39fc5c168c6f088a6956d"}, + {file = "numpy-2.0.2-cp39-cp39-win32.whl", hash = "sha256:905d16e0c60200656500c95b6b8dca5d109e23cb24abc701d41c02d74c6b3afa"}, + {file = "numpy-2.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:a3f4ab0caa7f053f6797fcd4e1e25caee367db3112ef2b6ef82d749530768c73"}, + {file = "numpy-2.0.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:7f0a0c6f12e07fa94133c8a67404322845220c06a9e80e85999afe727f7438b8"}, + {file = "numpy-2.0.2-pp39-pypy39_pp73-macosx_14_0_x86_64.whl", hash = "sha256:312950fdd060354350ed123c0e25a71327d3711584beaef30cdaa93320c392d4"}, + {file = "numpy-2.0.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26df23238872200f63518dd2aa984cfca675d82469535dc7162dc2ee52d9dd5c"}, + {file = "numpy-2.0.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a46288ec55ebbd58947d31d72be2c63cbf839f0a63b49cb755022310792a3385"}, + {file = "numpy-2.0.2.tar.gz", hash = "sha256:883c987dee1880e2a864ab0dc9892292582510604156762362d9326444636e78"}, ] [[package]] name = "numpy" -version = "2.1.0" +version = "2.2.6" description = "Fundamental package for array computing in Python" optional = false python-versions = ">=3.10" files = [ - {file = "numpy-2.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6326ab99b52fafdcdeccf602d6286191a79fe2fda0ae90573c5814cd2b0bc1b8"}, - {file = "numpy-2.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0937e54c09f7a9a68da6889362ddd2ff584c02d015ec92672c099b61555f8911"}, - {file = "numpy-2.1.0-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:30014b234f07b5fec20f4146f69e13cfb1e33ee9a18a1879a0142fbb00d47673"}, - {file = "numpy-2.1.0-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:899da829b362ade41e1e7eccad2cf274035e1cb36ba73034946fccd4afd8606b"}, - {file = "numpy-2.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:08801848a40aea24ce16c2ecde3b756f9ad756586fb2d13210939eb69b023f5b"}, - {file = "numpy-2.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:398049e237d1aae53d82a416dade04defed1a47f87d18d5bd615b6e7d7e41d1f"}, - {file = "numpy-2.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0abb3916a35d9090088a748636b2c06dc9a6542f99cd476979fb156a18192b84"}, - {file = "numpy-2.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:10e2350aea18d04832319aac0f887d5fcec1b36abd485d14f173e3e900b83e33"}, - {file = "numpy-2.1.0-cp310-cp310-win32.whl", hash = "sha256:f6b26e6c3b98adb648243670fddc8cab6ae17473f9dc58c51574af3e64d61211"}, - {file = "numpy-2.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:f505264735ee074250a9c78247ee8618292091d9d1fcc023290e9ac67e8f1afa"}, - {file = "numpy-2.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:76368c788ccb4f4782cf9c842b316140142b4cbf22ff8db82724e82fe1205dce"}, - {file = "numpy-2.1.0-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:f8e93a01a35be08d31ae33021e5268f157a2d60ebd643cfc15de6ab8e4722eb1"}, - {file = "numpy-2.1.0-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:9523f8b46485db6939bd069b28b642fec86c30909cea90ef550373787f79530e"}, - {file = "numpy-2.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54139e0eb219f52f60656d163cbe67c31ede51d13236c950145473504fa208cb"}, - {file = "numpy-2.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5ebbf9fbdabed208d4ecd2e1dfd2c0741af2f876e7ae522c2537d404ca895c3"}, - {file = "numpy-2.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:378cb4f24c7d93066ee4103204f73ed046eb88f9ad5bb2275bb9fa0f6a02bd36"}, - {file = "numpy-2.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8f699a709120b220dfe173f79c73cb2a2cab2c0b88dd59d7b49407d032b8ebd"}, - {file = "numpy-2.1.0-cp311-cp311-win32.whl", hash = "sha256:ffbd6faeb190aaf2b5e9024bac9622d2ee549b7ec89ef3a9373fa35313d44e0e"}, - {file = "numpy-2.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:0af3a5987f59d9c529c022c8c2a64805b339b7ef506509fba7d0556649b9714b"}, - {file = "numpy-2.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fe76d75b345dc045acdbc006adcb197cc680754afd6c259de60d358d60c93736"}, - {file = "numpy-2.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f358ea9e47eb3c2d6eba121ab512dfff38a88db719c38d1e67349af210bc7529"}, - {file = "numpy-2.1.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:dd94ce596bda40a9618324547cfaaf6650b1a24f5390350142499aa4e34e53d1"}, - {file = "numpy-2.1.0-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:b47c551c6724960479cefd7353656498b86e7232429e3a41ab83be4da1b109e8"}, - {file = "numpy-2.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0756a179afa766ad7cb6f036de622e8a8f16ffdd55aa31f296c870b5679d745"}, - {file = "numpy-2.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24003ba8ff22ea29a8c306e61d316ac74111cebf942afbf692df65509a05f111"}, - {file = "numpy-2.1.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b34fa5e3b5d6dc7e0a4243fa0f81367027cb6f4a7215a17852979634b5544ee0"}, - {file = "numpy-2.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c4f982715e65036c34897eb598d64aef15150c447be2cfc6643ec7a11af06574"}, - {file = "numpy-2.1.0-cp312-cp312-win32.whl", hash = "sha256:c4cd94dfefbefec3f8b544f61286584292d740e6e9d4677769bc76b8f41deb02"}, - {file = "numpy-2.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:a0cdef204199278f5c461a0bed6ed2e052998276e6d8ab2963d5b5c39a0500bc"}, - {file = "numpy-2.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8ab81ccd753859ab89e67199b9da62c543850f819993761c1e94a75a814ed667"}, - {file = "numpy-2.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:442596f01913656d579309edcd179a2a2f9977d9a14ff41d042475280fc7f34e"}, - {file = "numpy-2.1.0-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:848c6b5cad9898e4b9ef251b6f934fa34630371f2e916261070a4eb9092ffd33"}, - {file = "numpy-2.1.0-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:54c6a63e9d81efe64bfb7bcb0ec64332a87d0b87575f6009c8ba67ea6374770b"}, - {file = "numpy-2.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:652e92fc409e278abdd61e9505649e3938f6d04ce7ef1953f2ec598a50e7c195"}, - {file = "numpy-2.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ab32eb9170bf8ffcbb14f11613f4a0b108d3ffee0832457c5d4808233ba8977"}, - {file = "numpy-2.1.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:8fb49a0ba4d8f41198ae2d52118b050fd34dace4b8f3fb0ee34e23eb4ae775b1"}, - {file = "numpy-2.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:44e44973262dc3ae79e9063a1284a73e09d01b894b534a769732ccd46c28cc62"}, - {file = "numpy-2.1.0-cp313-cp313-win32.whl", hash = "sha256:ab83adc099ec62e044b1fbb3a05499fa1e99f6d53a1dde102b2d85eff66ed324"}, - {file = "numpy-2.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:de844aaa4815b78f6023832590d77da0e3b6805c644c33ce94a1e449f16d6ab5"}, - {file = "numpy-2.1.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:343e3e152bf5a087511cd325e3b7ecfd5b92d369e80e74c12cd87826e263ec06"}, - {file = "numpy-2.1.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f07fa2f15dabe91259828ce7d71b5ca9e2eb7c8c26baa822c825ce43552f4883"}, - {file = "numpy-2.1.0-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:5474dad8c86ee9ba9bb776f4b99ef2d41b3b8f4e0d199d4f7304728ed34d0300"}, - {file = "numpy-2.1.0-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:1f817c71683fd1bb5cff1529a1d085a57f02ccd2ebc5cd2c566f9a01118e3b7d"}, - {file = "numpy-2.1.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a3336fbfa0d38d3deacd3fe7f3d07e13597f29c13abf4d15c3b6dc2291cbbdd"}, - {file = "numpy-2.1.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a894c51fd8c4e834f00ac742abad73fc485df1062f1b875661a3c1e1fb1c2f6"}, - {file = "numpy-2.1.0-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:9156ca1f79fc4acc226696e95bfcc2b486f165a6a59ebe22b2c1f82ab190384a"}, - {file = "numpy-2.1.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:624884b572dff8ca8f60fab591413f077471de64e376b17d291b19f56504b2bb"}, - {file = "numpy-2.1.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:15ef8b2177eeb7e37dd5ef4016f30b7659c57c2c0b57a779f1d537ff33a72c7b"}, - {file = "numpy-2.1.0-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:e5f0642cdf4636198a4990de7a71b693d824c56a757862230454629cf62e323d"}, - {file = "numpy-2.1.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f15976718c004466406342789f31b6673776360f3b1e3c575f25302d7e789575"}, - {file = "numpy-2.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:6c1de77ded79fef664d5098a66810d4d27ca0224e9051906e634b3f7ead134c2"}, - {file = "numpy-2.1.0.tar.gz", hash = "sha256:7dc90da0081f7e1da49ec4e398ede6a8e9cc4f5ebe5f9e06b443ed889ee9aaa2"}, + {file = "numpy-2.2.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b412caa66f72040e6d268491a59f2c43bf03eb6c96dd8f0307829feb7fa2b6fb"}, + {file = "numpy-2.2.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e41fd67c52b86603a91c1a505ebaef50b3314de0213461c7a6e99c9a3beff90"}, + {file = "numpy-2.2.6-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:37e990a01ae6ec7fe7fa1c26c55ecb672dd98b19c3d0e1d1f326fa13cb38d163"}, + {file = "numpy-2.2.6-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:5a6429d4be8ca66d889b7cf70f536a397dc45ba6faeb5f8c5427935d9592e9cf"}, + {file = "numpy-2.2.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:efd28d4e9cd7d7a8d39074a4d44c63eda73401580c5c76acda2ce969e0a38e83"}, + {file = "numpy-2.2.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc7b73d02efb0e18c000e9ad8b83480dfcd5dfd11065997ed4c6747470ae8915"}, + {file = "numpy-2.2.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:74d4531beb257d2c3f4b261bfb0fc09e0f9ebb8842d82a7b4209415896adc680"}, + {file = "numpy-2.2.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8fc377d995680230e83241d8a96def29f204b5782f371c532579b4f20607a289"}, + {file = "numpy-2.2.6-cp310-cp310-win32.whl", hash = "sha256:b093dd74e50a8cba3e873868d9e93a85b78e0daf2e98c6797566ad8044e8363d"}, + {file = "numpy-2.2.6-cp310-cp310-win_amd64.whl", hash = "sha256:f0fd6321b839904e15c46e0d257fdd101dd7f530fe03fd6359c1ea63738703f3"}, + {file = "numpy-2.2.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f9f1adb22318e121c5c69a09142811a201ef17ab257a1e66ca3025065b7f53ae"}, + {file = "numpy-2.2.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c820a93b0255bc360f53eca31a0e676fd1101f673dda8da93454a12e23fc5f7a"}, + {file = "numpy-2.2.6-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:3d70692235e759f260c3d837193090014aebdf026dfd167834bcba43e30c2a42"}, + {file = "numpy-2.2.6-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:481b49095335f8eed42e39e8041327c05b0f6f4780488f61286ed3c01368d491"}, + {file = "numpy-2.2.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b64d8d4d17135e00c8e346e0a738deb17e754230d7e0810ac5012750bbd85a5a"}, + {file = "numpy-2.2.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba10f8411898fc418a521833e014a77d3ca01c15b0c6cdcce6a0d2897e6dbbdf"}, + {file = "numpy-2.2.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:bd48227a919f1bafbdda0583705e547892342c26fb127219d60a5c36882609d1"}, + {file = "numpy-2.2.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9551a499bf125c1d4f9e250377c1ee2eddd02e01eac6644c080162c0c51778ab"}, + {file = "numpy-2.2.6-cp311-cp311-win32.whl", hash = "sha256:0678000bb9ac1475cd454c6b8c799206af8107e310843532b04d49649c717a47"}, + {file = "numpy-2.2.6-cp311-cp311-win_amd64.whl", hash = "sha256:e8213002e427c69c45a52bbd94163084025f533a55a59d6f9c5b820774ef3303"}, + {file = "numpy-2.2.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:41c5a21f4a04fa86436124d388f6ed60a9343a6f767fced1a8a71c3fbca038ff"}, + {file = "numpy-2.2.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:de749064336d37e340f640b05f24e9e3dd678c57318c7289d222a8a2f543e90c"}, + {file = "numpy-2.2.6-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:894b3a42502226a1cac872f840030665f33326fc3dac8e57c607905773cdcde3"}, + {file = "numpy-2.2.6-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:71594f7c51a18e728451bb50cc60a3ce4e6538822731b2933209a1f3614e9282"}, + {file = "numpy-2.2.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2618db89be1b4e05f7a1a847a9c1c0abd63e63a1607d892dd54668dd92faf87"}, + {file = "numpy-2.2.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd83c01228a688733f1ded5201c678f0c53ecc1006ffbc404db9f7a899ac6249"}, + {file = "numpy-2.2.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:37c0ca431f82cd5fa716eca9506aefcabc247fb27ba69c5062a6d3ade8cf8f49"}, + {file = "numpy-2.2.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fe27749d33bb772c80dcd84ae7e8df2adc920ae8297400dabec45f0dedb3f6de"}, + {file = "numpy-2.2.6-cp312-cp312-win32.whl", hash = "sha256:4eeaae00d789f66c7a25ac5f34b71a7035bb474e679f410e5e1a94deb24cf2d4"}, + {file = "numpy-2.2.6-cp312-cp312-win_amd64.whl", hash = "sha256:c1f9540be57940698ed329904db803cf7a402f3fc200bfe599334c9bd84a40b2"}, + {file = "numpy-2.2.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0811bb762109d9708cca4d0b13c4f67146e3c3b7cf8d34018c722adb2d957c84"}, + {file = "numpy-2.2.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:287cc3162b6f01463ccd86be154f284d0893d2b3ed7292439ea97eafa8170e0b"}, + {file = "numpy-2.2.6-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:f1372f041402e37e5e633e586f62aa53de2eac8d98cbfb822806ce4bbefcb74d"}, + {file = "numpy-2.2.6-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:55a4d33fa519660d69614a9fad433be87e5252f4b03850642f88993f7b2ca566"}, + {file = "numpy-2.2.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f92729c95468a2f4f15e9bb94c432a9229d0d50de67304399627a943201baa2f"}, + {file = "numpy-2.2.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bc23a79bfabc5d056d106f9befb8d50c31ced2fbc70eedb8155aec74a45798f"}, + {file = "numpy-2.2.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e3143e4451880bed956e706a3220b4e5cf6172ef05fcc397f6f36a550b1dd868"}, + {file = "numpy-2.2.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b4f13750ce79751586ae2eb824ba7e1e8dba64784086c98cdbbcc6a42112ce0d"}, + {file = "numpy-2.2.6-cp313-cp313-win32.whl", hash = "sha256:5beb72339d9d4fa36522fc63802f469b13cdbe4fdab4a288f0c441b74272ebfd"}, + {file = "numpy-2.2.6-cp313-cp313-win_amd64.whl", hash = "sha256:b0544343a702fa80c95ad5d3d608ea3599dd54d4632df855e4c8d24eb6ecfa1c"}, + {file = "numpy-2.2.6-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0bca768cd85ae743b2affdc762d617eddf3bcf8724435498a1e80132d04879e6"}, + {file = "numpy-2.2.6-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:fc0c5673685c508a142ca65209b4e79ed6740a4ed6b2267dbba90f34b0b3cfda"}, + {file = "numpy-2.2.6-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:5bd4fc3ac8926b3819797a7c0e2631eb889b4118a9898c84f585a54d475b7e40"}, + {file = "numpy-2.2.6-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:fee4236c876c4e8369388054d02d0e9bb84821feb1a64dd59e137e6511a551f8"}, + {file = "numpy-2.2.6-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1dda9c7e08dc141e0247a5b8f49cf05984955246a327d4c48bda16821947b2f"}, + {file = "numpy-2.2.6-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f447e6acb680fd307f40d3da4852208af94afdfab89cf850986c3ca00562f4fa"}, + {file = "numpy-2.2.6-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:389d771b1623ec92636b0786bc4ae56abafad4a4c513d36a55dce14bd9ce8571"}, + {file = "numpy-2.2.6-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8e9ace4a37db23421249ed236fdcdd457d671e25146786dfc96835cd951aa7c1"}, + {file = "numpy-2.2.6-cp313-cp313t-win32.whl", hash = "sha256:038613e9fb8c72b0a41f025a7e4c3f0b7a1b5d768ece4796b674c8f3fe13efff"}, + {file = "numpy-2.2.6-cp313-cp313t-win_amd64.whl", hash = "sha256:6031dd6dfecc0cf9f668681a37648373bddd6421fff6c66ec1624eed0180ee06"}, + {file = "numpy-2.2.6-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0b605b275d7bd0c640cad4e5d30fa701a8d59302e127e5f79138ad62762c3e3d"}, + {file = "numpy-2.2.6-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:7befc596a7dc9da8a337f79802ee8adb30a552a94f792b9c9d18c840055907db"}, + {file = "numpy-2.2.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce47521a4754c8f4593837384bd3424880629f718d87c5d44f8ed763edd63543"}, + {file = "numpy-2.2.6-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d042d24c90c41b54fd506da306759e06e568864df8ec17ccc17e9e884634fd00"}, + {file = "numpy-2.2.6.tar.gz", hash = "sha256:e29554e2bef54a90aa5cc07da6ce955accb83f21ab5de01a62c8478897b264fd"}, +] + +[[package]] +name = "numpy" +version = "2.3.3" +description = "Fundamental package for array computing in Python" +optional = false +python-versions = ">=3.11" +files = [ + {file = "numpy-2.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0ffc4f5caba7dfcbe944ed674b7eef683c7e94874046454bb79ed7ee0236f59d"}, + {file = "numpy-2.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e7e946c7170858a0295f79a60214424caac2ffdb0063d4d79cb681f9aa0aa569"}, + {file = "numpy-2.3.3-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:cd4260f64bc794c3390a63bf0728220dd1a68170c169088a1e0dfa2fde1be12f"}, + {file = "numpy-2.3.3-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:f0ddb4b96a87b6728df9362135e764eac3cfa674499943ebc44ce96c478ab125"}, + {file = "numpy-2.3.3-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:afd07d377f478344ec6ca2b8d4ca08ae8bd44706763d1efb56397de606393f48"}, + {file = "numpy-2.3.3-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bc92a5dedcc53857249ca51ef29f5e5f2f8c513e22cfb90faeb20343b8c6f7a6"}, + {file = "numpy-2.3.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7af05ed4dc19f308e1d9fc759f36f21921eb7bbfc82843eeec6b2a2863a0aefa"}, + {file = "numpy-2.3.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:433bf137e338677cebdd5beac0199ac84712ad9d630b74eceeb759eaa45ddf30"}, + {file = "numpy-2.3.3-cp311-cp311-win32.whl", hash = "sha256:eb63d443d7b4ffd1e873f8155260d7f58e7e4b095961b01c91062935c2491e57"}, + {file = "numpy-2.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:ec9d249840f6a565f58d8f913bccac2444235025bbb13e9a4681783572ee3caa"}, + {file = "numpy-2.3.3-cp311-cp311-win_arm64.whl", hash = "sha256:74c2a948d02f88c11a3c075d9733f1ae67d97c6bdb97f2bb542f980458b257e7"}, + {file = "numpy-2.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cfdd09f9c84a1a934cde1eec2267f0a43a7cd44b2cca4ff95b7c0d14d144b0bf"}, + {file = "numpy-2.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cb32e3cf0f762aee47ad1ddc6672988f7f27045b0783c887190545baba73aa25"}, + {file = "numpy-2.3.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:396b254daeb0a57b1fe0ecb5e3cff6fa79a380fa97c8f7781a6d08cd429418fe"}, + {file = "numpy-2.3.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:067e3d7159a5d8f8a0b46ee11148fc35ca9b21f61e3c49fbd0a027450e65a33b"}, + {file = "numpy-2.3.3-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1c02d0629d25d426585fb2e45a66154081b9fa677bc92a881ff1d216bc9919a8"}, + {file = "numpy-2.3.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d9192da52b9745f7f0766531dcfa978b7763916f158bb63bdb8a1eca0068ab20"}, + {file = "numpy-2.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:cd7de500a5b66319db419dc3c345244404a164beae0d0937283b907d8152e6ea"}, + {file = "numpy-2.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:93d4962d8f82af58f0b2eb85daaf1b3ca23fe0a85d0be8f1f2b7bb46034e56d7"}, + {file = "numpy-2.3.3-cp312-cp312-win32.whl", hash = "sha256:5534ed6b92f9b7dca6c0a19d6df12d41c68b991cef051d108f6dbff3babc4ebf"}, + {file = "numpy-2.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:497d7cad08e7092dba36e3d296fe4c97708c93daf26643a1ae4b03f6294d30eb"}, + {file = "numpy-2.3.3-cp312-cp312-win_arm64.whl", hash = "sha256:ca0309a18d4dfea6fc6262a66d06c26cfe4640c3926ceec90e57791a82b6eee5"}, + {file = "numpy-2.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f5415fb78995644253370985342cd03572ef8620b934da27d77377a2285955bf"}, + {file = "numpy-2.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d00de139a3324e26ed5b95870ce63be7ec7352171bc69a4cf1f157a48e3eb6b7"}, + {file = "numpy-2.3.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:9dc13c6a5829610cc07422bc74d3ac083bd8323f14e2827d992f9e52e22cd6a6"}, + {file = "numpy-2.3.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:d79715d95f1894771eb4e60fb23f065663b2298f7d22945d66877aadf33d00c7"}, + {file = "numpy-2.3.3-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:952cfd0748514ea7c3afc729a0fc639e61655ce4c55ab9acfab14bda4f402b4c"}, + {file = "numpy-2.3.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5b83648633d46f77039c29078751f80da65aa64d5622a3cd62aaef9d835b6c93"}, + {file = "numpy-2.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b001bae8cea1c7dfdb2ae2b017ed0a6f2102d7a70059df1e338e307a4c78a8ae"}, + {file = "numpy-2.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8e9aced64054739037d42fb84c54dd38b81ee238816c948c8f3ed134665dcd86"}, + {file = "numpy-2.3.3-cp313-cp313-win32.whl", hash = "sha256:9591e1221db3f37751e6442850429b3aabf7026d3b05542d102944ca7f00c8a8"}, + {file = "numpy-2.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:f0dadeb302887f07431910f67a14d57209ed91130be0adea2f9793f1a4f817cf"}, + {file = "numpy-2.3.3-cp313-cp313-win_arm64.whl", hash = "sha256:3c7cf302ac6e0b76a64c4aecf1a09e51abd9b01fc7feee80f6c43e3ab1b1dbc5"}, + {file = "numpy-2.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:eda59e44957d272846bb407aad19f89dc6f58fecf3504bd144f4c5cf81a7eacc"}, + {file = "numpy-2.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:823d04112bc85ef5c4fda73ba24e6096c8f869931405a80aa8b0e604510a26bc"}, + {file = "numpy-2.3.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:40051003e03db4041aa325da2a0971ba41cf65714e65d296397cc0e32de6018b"}, + {file = "numpy-2.3.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:6ee9086235dd6ab7ae75aba5662f582a81ced49f0f1c6de4260a78d8f2d91a19"}, + {file = "numpy-2.3.3-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:94fcaa68757c3e2e668ddadeaa86ab05499a70725811e582b6a9858dd472fb30"}, + {file = "numpy-2.3.3-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:da1a74b90e7483d6ce5244053399a614b1d6b7bc30a60d2f570e5071f8959d3e"}, + {file = "numpy-2.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:2990adf06d1ecee3b3dcbb4977dfab6e9f09807598d647f04d385d29e7a3c3d3"}, + {file = "numpy-2.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:ed635ff692483b8e3f0fcaa8e7eb8a75ee71aa6d975388224f70821421800cea"}, + {file = "numpy-2.3.3-cp313-cp313t-win32.whl", hash = "sha256:a333b4ed33d8dc2b373cc955ca57babc00cd6f9009991d9edc5ddbc1bac36bcd"}, + {file = "numpy-2.3.3-cp313-cp313t-win_amd64.whl", hash = "sha256:4384a169c4d8f97195980815d6fcad04933a7e1ab3b530921c3fef7a1c63426d"}, + {file = "numpy-2.3.3-cp313-cp313t-win_arm64.whl", hash = "sha256:75370986cc0bc66f4ce5110ad35aae6d182cc4ce6433c40ad151f53690130bf1"}, + {file = "numpy-2.3.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:cd052f1fa6a78dee696b58a914b7229ecfa41f0a6d96dc663c1220a55e137593"}, + {file = "numpy-2.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:414a97499480067d305fcac9716c29cf4d0d76db6ebf0bf3cbce666677f12652"}, + {file = "numpy-2.3.3-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:50a5fe69f135f88a2be9b6ca0481a68a136f6febe1916e4920e12f1a34e708a7"}, + {file = "numpy-2.3.3-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:b912f2ed2b67a129e6a601e9d93d4fa37bef67e54cac442a2f588a54afe5c67a"}, + {file = "numpy-2.3.3-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9e318ee0596d76d4cb3d78535dc005fa60e5ea348cd131a51e99d0bdbe0b54fe"}, + {file = "numpy-2.3.3-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ce020080e4a52426202bdb6f7691c65bb55e49f261f31a8f506c9f6bc7450421"}, + {file = "numpy-2.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e6687dc183aa55dae4a705b35f9c0f8cb178bcaa2f029b241ac5356221d5c021"}, + {file = "numpy-2.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d8f3b1080782469fdc1718c4ed1d22549b5fb12af0d57d35e992158a772a37cf"}, + {file = "numpy-2.3.3-cp314-cp314-win32.whl", hash = "sha256:cb248499b0bc3be66ebd6578b83e5acacf1d6cb2a77f2248ce0e40fbec5a76d0"}, + {file = "numpy-2.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:691808c2b26b0f002a032c73255d0bd89751425f379f7bcd22d140db593a96e8"}, + {file = "numpy-2.3.3-cp314-cp314-win_arm64.whl", hash = "sha256:9ad12e976ca7b10f1774b03615a2a4bab8addce37ecc77394d8e986927dc0dfe"}, + {file = "numpy-2.3.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9cc48e09feb11e1db00b320e9d30a4151f7369afb96bd0e48d942d09da3a0d00"}, + {file = "numpy-2.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:901bf6123879b7f251d3631967fd574690734236075082078e0571977c6a8e6a"}, + {file = "numpy-2.3.3-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:7f025652034199c301049296b59fa7d52c7e625017cae4c75d8662e377bf487d"}, + {file = "numpy-2.3.3-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:533ca5f6d325c80b6007d4d7fb1984c303553534191024ec6a524a4c92a5935a"}, + {file = "numpy-2.3.3-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0edd58682a399824633b66885d699d7de982800053acf20be1eaa46d92009c54"}, + {file = "numpy-2.3.3-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:367ad5d8fbec5d9296d18478804a530f1191e24ab4d75ab408346ae88045d25e"}, + {file = "numpy-2.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8f6ac61a217437946a1fa48d24c47c91a0c4f725237871117dea264982128097"}, + {file = "numpy-2.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:179a42101b845a816d464b6fe9a845dfaf308fdfc7925387195570789bb2c970"}, + {file = "numpy-2.3.3-cp314-cp314t-win32.whl", hash = "sha256:1250c5d3d2562ec4174bce2e3a1523041595f9b651065e4a4473f5f48a6bc8a5"}, + {file = "numpy-2.3.3-cp314-cp314t-win_amd64.whl", hash = "sha256:b37a0b2e5935409daebe82c1e42274d30d9dd355852529eab91dab8dcca7419f"}, + {file = "numpy-2.3.3-cp314-cp314t-win_arm64.whl", hash = "sha256:78c9f6560dc7e6b3990e32df7ea1a50bbd0e2a111e05209963f5ddcab7073b0b"}, + {file = "numpy-2.3.3-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:1e02c7159791cd481e1e6d5ddd766b62a4d5acf8df4d4d1afe35ee9c5c33a41e"}, + {file = "numpy-2.3.3-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:dca2d0fc80b3893ae72197b39f69d55a3cd8b17ea1b50aa4c62de82419936150"}, + {file = "numpy-2.3.3-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:99683cbe0658f8271b333a1b1b4bb3173750ad59c0c61f5bbdc5b318918fffe3"}, + {file = "numpy-2.3.3-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:d9d537a39cc9de668e5cd0e25affb17aec17b577c6b3ae8a3d866b479fbe88d0"}, + {file = "numpy-2.3.3-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8596ba2f8af5f93b01d97563832686d20206d303024777f6dfc2e7c7c3f1850e"}, + {file = "numpy-2.3.3-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e1ec5615b05369925bd1125f27df33f3b6c8bc10d788d5999ecd8769a1fa04db"}, + {file = "numpy-2.3.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:2e267c7da5bf7309670523896df97f93f6e469fb931161f483cd6882b3b1a5dc"}, + {file = "numpy-2.3.3.tar.gz", hash = "sha256:ddc7c39727ba62b80dfdbedf400d1c10ddfa8eefbd7ec8dcb118be8b56d31029"}, ] [[package]] name = "packaging" -version = "24.1" +version = "25.0" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, - {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, + {file = "packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484"}, + {file = "packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f"}, ] [[package]] @@ -815,6 +927,113 @@ files = [ dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] +[[package]] +name = "propcache" +version = "0.2.0" +description = "Accelerated property cache" +optional = false +python-versions = ">=3.8" +files = [ + {file = "propcache-0.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c5869b8fd70b81835a6f187c5fdbe67917a04d7e52b6e7cc4e5fe39d55c39d58"}, + {file = "propcache-0.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:952e0d9d07609d9c5be361f33b0d6d650cd2bae393aabb11d9b719364521984b"}, + {file = "propcache-0.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:33ac8f098df0585c0b53009f039dfd913b38c1d2edafed0cedcc0c32a05aa110"}, + {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:97e48e8875e6c13909c800fa344cd54cc4b2b0db1d5f911f840458a500fde2c2"}, + {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:388f3217649d6d59292b722d940d4d2e1e6a7003259eb835724092a1cca0203a"}, + {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f571aea50ba5623c308aa146eb650eebf7dbe0fd8c5d946e28343cb3b5aad577"}, + {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3dfafb44f7bb35c0c06eda6b2ab4bfd58f02729e7c4045e179f9a861b07c9850"}, + {file = "propcache-0.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a3ebe9a75be7ab0b7da2464a77bb27febcb4fab46a34f9288f39d74833db7f61"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d2f0d0f976985f85dfb5f3d685697ef769faa6b71993b46b295cdbbd6be8cc37"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:a3dc1a4b165283bd865e8f8cb5f0c64c05001e0718ed06250d8cac9bec115b48"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:9e0f07b42d2a50c7dd2d8675d50f7343d998c64008f1da5fef888396b7f84630"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:e63e3e1e0271f374ed489ff5ee73d4b6e7c60710e1f76af5f0e1a6117cd26394"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:56bb5c98f058a41bb58eead194b4db8c05b088c93d94d5161728515bd52b052b"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7665f04d0c7f26ff8bb534e1c65068409bf4687aa2534faf7104d7182debb336"}, + {file = "propcache-0.2.0-cp310-cp310-win32.whl", hash = "sha256:7cf18abf9764746b9c8704774d8b06714bcb0a63641518a3a89c7f85cc02c2ad"}, + {file = "propcache-0.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:cfac69017ef97db2438efb854edf24f5a29fd09a536ff3a992b75990720cdc99"}, + {file = "propcache-0.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:63f13bf09cc3336eb04a837490b8f332e0db41da66995c9fd1ba04552e516354"}, + {file = "propcache-0.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:608cce1da6f2672a56b24a015b42db4ac612ee709f3d29f27a00c943d9e851de"}, + {file = "propcache-0.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:466c219deee4536fbc83c08d09115249db301550625c7fef1c5563a584c9bc87"}, + {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc2db02409338bf36590aa985a461b2c96fce91f8e7e0f14c50c5fcc4f229016"}, + {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a6ed8db0a556343d566a5c124ee483ae113acc9a557a807d439bcecc44e7dfbb"}, + {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:91997d9cb4a325b60d4e3f20967f8eb08dfcb32b22554d5ef78e6fd1dda743a2"}, + {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c7dde9e533c0a49d802b4f3f218fa9ad0a1ce21f2c2eb80d5216565202acab4"}, + {file = "propcache-0.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffcad6c564fe6b9b8916c1aefbb37a362deebf9394bd2974e9d84232e3e08504"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:97a58a28bcf63284e8b4d7b460cbee1edaab24634e82059c7b8c09e65284f178"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:945db8ee295d3af9dbdbb698cce9bbc5c59b5c3fe328bbc4387f59a8a35f998d"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:39e104da444a34830751715f45ef9fc537475ba21b7f1f5b0f4d71a3b60d7fe2"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c5ecca8f9bab618340c8e848d340baf68bcd8ad90a8ecd7a4524a81c1764b3db"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:c436130cc779806bdf5d5fae0d848713105472b8566b75ff70048c47d3961c5b"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:191db28dc6dcd29d1a3e063c3be0b40688ed76434622c53a284e5427565bbd9b"}, + {file = "propcache-0.2.0-cp311-cp311-win32.whl", hash = "sha256:5f2564ec89058ee7c7989a7b719115bdfe2a2fb8e7a4543b8d1c0cc4cf6478c1"}, + {file = "propcache-0.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:6e2e54267980349b723cff366d1e29b138b9a60fa376664a157a342689553f71"}, + {file = "propcache-0.2.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:2ee7606193fb267be4b2e3b32714f2d58cad27217638db98a60f9efb5efeccc2"}, + {file = "propcache-0.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:91ee8fc02ca52e24bcb77b234f22afc03288e1dafbb1f88fe24db308910c4ac7"}, + {file = "propcache-0.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2e900bad2a8456d00a113cad8c13343f3b1f327534e3589acc2219729237a2e8"}, + {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f52a68c21363c45297aca15561812d542f8fc683c85201df0bebe209e349f793"}, + {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1e41d67757ff4fbc8ef2af99b338bfb955010444b92929e9e55a6d4dcc3c4f09"}, + {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a64e32f8bd94c105cc27f42d3b658902b5bcc947ece3c8fe7bc1b05982f60e89"}, + {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:55346705687dbd7ef0d77883ab4f6fabc48232f587925bdaf95219bae072491e"}, + {file = "propcache-0.2.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00181262b17e517df2cd85656fcd6b4e70946fe62cd625b9d74ac9977b64d8d9"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6994984550eaf25dd7fc7bd1b700ff45c894149341725bb4edc67f0ffa94efa4"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:56295eb1e5f3aecd516d91b00cfd8bf3a13991de5a479df9e27dd569ea23959c"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:439e76255daa0f8151d3cb325f6dd4a3e93043e6403e6491813bcaaaa8733887"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f6475a1b2ecb310c98c28d271a30df74f9dd436ee46d09236a6b750a7599ce57"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3444cdba6628accf384e349014084b1cacd866fbb88433cd9d279d90a54e0b23"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4a9d9b4d0a9b38d1c391bb4ad24aa65f306c6f01b512e10a8a34a2dc5675d348"}, + {file = "propcache-0.2.0-cp312-cp312-win32.whl", hash = "sha256:69d3a98eebae99a420d4b28756c8ce6ea5a29291baf2dc9ff9414b42676f61d5"}, + {file = "propcache-0.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:ad9c9b99b05f163109466638bd30ada1722abb01bbb85c739c50b6dc11f92dc3"}, + {file = "propcache-0.2.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ecddc221a077a8132cf7c747d5352a15ed763b674c0448d811f408bf803d9ad7"}, + {file = "propcache-0.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0e53cb83fdd61cbd67202735e6a6687a7b491c8742dfc39c9e01e80354956763"}, + {file = "propcache-0.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92fe151145a990c22cbccf9ae15cae8ae9eddabfc949a219c9f667877e40853d"}, + {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6a21ef516d36909931a2967621eecb256018aeb11fc48656e3257e73e2e247a"}, + {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f88a4095e913f98988f5b338c1d4d5d07dbb0b6bad19892fd447484e483ba6b"}, + {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a5b3bb545ead161be780ee85a2b54fdf7092815995661947812dde94a40f6fb"}, + {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67aeb72e0f482709991aa91345a831d0b707d16b0257e8ef88a2ad246a7280bf"}, + {file = "propcache-0.2.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c997f8c44ec9b9b0bcbf2d422cc00a1d9b9c681f56efa6ca149a941e5560da2"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2a66df3d4992bc1d725b9aa803e8c5a66c010c65c741ad901e260ece77f58d2f"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:3ebbcf2a07621f29638799828b8d8668c421bfb94c6cb04269130d8de4fb7136"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1235c01ddaa80da8235741e80815ce381c5267f96cc49b1477fdcf8c047ef325"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3947483a381259c06921612550867b37d22e1df6d6d7e8361264b6d037595f44"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d5bed7f9805cc29c780f3aee05de3262ee7ce1f47083cfe9f77471e9d6777e83"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e4a91d44379f45f5e540971d41e4626dacd7f01004826a18cb048e7da7e96544"}, + {file = "propcache-0.2.0-cp313-cp313-win32.whl", hash = "sha256:f902804113e032e2cdf8c71015651c97af6418363bea8d78dc0911d56c335032"}, + {file = "propcache-0.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:8f188cfcc64fb1266f4684206c9de0e80f54622c3f22a910cbd200478aeae61e"}, + {file = "propcache-0.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:53d1bd3f979ed529f0805dd35ddaca330f80a9a6d90bc0121d2ff398f8ed8861"}, + {file = "propcache-0.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:83928404adf8fb3d26793665633ea79b7361efa0287dfbd372a7e74311d51ee6"}, + {file = "propcache-0.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:77a86c261679ea5f3896ec060be9dc8e365788248cc1e049632a1be682442063"}, + {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:218db2a3c297a3768c11a34812e63b3ac1c3234c3a086def9c0fee50d35add1f"}, + {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7735e82e3498c27bcb2d17cb65d62c14f1100b71723b68362872bca7d0913d90"}, + {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:20a617c776f520c3875cf4511e0d1db847a076d720714ae35ffe0df3e440be68"}, + {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67b69535c870670c9f9b14a75d28baa32221d06f6b6fa6f77a0a13c5a7b0a5b9"}, + {file = "propcache-0.2.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4569158070180c3855e9c0791c56be3ceeb192defa2cdf6a3f39e54319e56b89"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:db47514ffdbd91ccdc7e6f8407aac4ee94cc871b15b577c1c324236b013ddd04"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_armv7l.whl", hash = "sha256:2a60ad3e2553a74168d275a0ef35e8c0a965448ffbc3b300ab3a5bb9956c2162"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:662dd62358bdeaca0aee5761de8727cfd6861432e3bb828dc2a693aa0471a563"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:25a1f88b471b3bc911d18b935ecb7115dff3a192b6fef46f0bfaf71ff4f12418"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:f60f0ac7005b9f5a6091009b09a419ace1610e163fa5deaba5ce3484341840e7"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:74acd6e291f885678631b7ebc85d2d4aec458dd849b8c841b57ef04047833bed"}, + {file = "propcache-0.2.0-cp38-cp38-win32.whl", hash = "sha256:d9b6ddac6408194e934002a69bcaadbc88c10b5f38fb9307779d1c629181815d"}, + {file = "propcache-0.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:676135dcf3262c9c5081cc8f19ad55c8a64e3f7282a21266d05544450bffc3a5"}, + {file = "propcache-0.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:25c8d773a62ce0451b020c7b29a35cfbc05de8b291163a7a0f3b7904f27253e6"}, + {file = "propcache-0.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:375a12d7556d462dc64d70475a9ee5982465fbb3d2b364f16b86ba9135793638"}, + {file = "propcache-0.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1ec43d76b9677637a89d6ab86e1fef70d739217fefa208c65352ecf0282be957"}, + {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f45eec587dafd4b2d41ac189c2156461ebd0c1082d2fe7013571598abb8505d1"}, + {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bc092ba439d91df90aea38168e11f75c655880c12782facf5cf9c00f3d42b562"}, + {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fa1076244f54bb76e65e22cb6910365779d5c3d71d1f18b275f1dfc7b0d71b4d"}, + {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:682a7c79a2fbf40f5dbb1eb6bfe2cd865376deeac65acf9beb607505dced9e12"}, + {file = "propcache-0.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8e40876731f99b6f3c897b66b803c9e1c07a989b366c6b5b475fafd1f7ba3fb8"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:363ea8cd3c5cb6679f1c2f5f1f9669587361c062e4899fce56758efa928728f8"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:140fbf08ab3588b3468932974a9331aff43c0ab8a2ec2c608b6d7d1756dbb6cb"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:e70fac33e8b4ac63dfc4c956fd7d85a0b1139adcfc0d964ce288b7c527537fea"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:b33d7a286c0dc1a15f5fc864cc48ae92a846df287ceac2dd499926c3801054a6"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:f6d5749fdd33d90e34c2efb174c7e236829147a2713334d708746e94c4bde40d"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:22aa8f2272d81d9317ff5756bb108021a056805ce63dd3630e27d042c8092798"}, + {file = "propcache-0.2.0-cp39-cp39-win32.whl", hash = "sha256:73e4b40ea0eda421b115248d7e79b59214411109a5bc47d0d48e4c73e3b8fcf9"}, + {file = "propcache-0.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:9517d5e9e0731957468c29dbfd0f976736a0e55afaea843726e887f36fe017df"}, + {file = "propcache-0.2.0-py3-none-any.whl", hash = "sha256:2ccc28197af5313706511fab3a8b66dcd6da067a1331372c82ea1cb74285e036"}, + {file = "propcache-0.2.0.tar.gz", hash = "sha256:df81779732feb9d01e5d513fad0122efb3d53bbc75f61b2a4f29a020bc985e70"}, +] + [[package]] name = "pycares" version = "4.4.0" @@ -883,26 +1102,29 @@ idna = ["idna (>=2.1)"] [[package]] name = "pycparser" -version = "2.22" +version = "2.23" description = "C parser in Python" optional = false python-versions = ">=3.8" files = [ - {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, - {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, + {file = "pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934"}, + {file = "pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2"}, ] [[package]] name = "pyreadline3" -version = "3.4.1" +version = "3.5.4" description = "A python implementation of GNU readline." optional = false -python-versions = "*" +python-versions = ">=3.8" files = [ - {file = "pyreadline3-3.4.1-py3-none-any.whl", hash = "sha256:b0efb6516fd4fb07b45949053826a62fa4cb353db5be2bbb4a7aa1fdd1e345fb"}, - {file = "pyreadline3-3.4.1.tar.gz", hash = "sha256:6f3d1f7b8a31ba32b73917cefc1f28cc660562f39aea8646d30bd6eff21f7bae"}, + {file = "pyreadline3-3.5.4-py3-none-any.whl", hash = "sha256:eaf8e6cc3c49bcccf145fc6067ba8643d1df34d604a1ec0eccbf7a18e6d3fae6"}, + {file = "pyreadline3-3.5.4.tar.gz", hash = "sha256:8d57d53039a1c75adba8e50dd3d992b28143480816187ea5efbd5c78e6c885b7"}, ] +[package.extras] +dev = ["build", "flake8", "mypy", "pytest", "twine"] + [[package]] name = "pytest" version = "7.4.4" @@ -927,119 +1149,169 @@ testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "no [[package]] name = "tomli" -version = "2.0.1" +version = "2.2.1" description = "A lil' TOML parser" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, - {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, + {file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"}, + {file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8"}, + {file = "tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff"}, + {file = "tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e"}, + {file = "tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98"}, + {file = "tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744"}, + {file = "tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec"}, + {file = "tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"}, + {file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"}, + {file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"}, +] + +[[package]] +name = "typing-extensions" +version = "4.13.2" +description = "Backported and Experimental Type Hints for Python 3.8+" +optional = false +python-versions = ">=3.8" +files = [ + {file = "typing_extensions-4.13.2-py3-none-any.whl", hash = "sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c"}, + {file = "typing_extensions-4.13.2.tar.gz", hash = "sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef"}, ] [[package]] name = "yarl" -version = "1.9.4" +version = "1.15.2" description = "Yet another URL library" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "yarl-1.9.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a8c1df72eb746f4136fe9a2e72b0c9dc1da1cbd23b5372f94b5820ff8ae30e0e"}, - {file = "yarl-1.9.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a3a6ed1d525bfb91b3fc9b690c5a21bb52de28c018530ad85093cc488bee2dd2"}, - {file = "yarl-1.9.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c38c9ddb6103ceae4e4498f9c08fac9b590c5c71b0370f98714768e22ac6fa66"}, - {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d9e09c9d74f4566e905a0b8fa668c58109f7624db96a2171f21747abc7524234"}, - {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8477c1ee4bd47c57d49621a062121c3023609f7a13b8a46953eb6c9716ca392"}, - {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5ff2c858f5f6a42c2a8e751100f237c5e869cbde669a724f2062d4c4ef93551"}, - {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:357495293086c5b6d34ca9616a43d329317feab7917518bc97a08f9e55648455"}, - {file = "yarl-1.9.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54525ae423d7b7a8ee81ba189f131054defdb122cde31ff17477951464c1691c"}, - {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:801e9264d19643548651b9db361ce3287176671fb0117f96b5ac0ee1c3530d53"}, - {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e516dc8baf7b380e6c1c26792610230f37147bb754d6426462ab115a02944385"}, - {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:7d5aaac37d19b2904bb9dfe12cdb08c8443e7ba7d2852894ad448d4b8f442863"}, - {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:54beabb809ffcacbd9d28ac57b0db46e42a6e341a030293fb3185c409e626b8b"}, - {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bac8d525a8dbc2a1507ec731d2867025d11ceadcb4dd421423a5d42c56818541"}, - {file = "yarl-1.9.4-cp310-cp310-win32.whl", hash = "sha256:7855426dfbddac81896b6e533ebefc0af2f132d4a47340cee6d22cac7190022d"}, - {file = "yarl-1.9.4-cp310-cp310-win_amd64.whl", hash = "sha256:848cd2a1df56ddbffeb375535fb62c9d1645dde33ca4d51341378b3f5954429b"}, - {file = "yarl-1.9.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:35a2b9396879ce32754bd457d31a51ff0a9d426fd9e0e3c33394bf4b9036b099"}, - {file = "yarl-1.9.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c7d56b293cc071e82532f70adcbd8b61909eec973ae9d2d1f9b233f3d943f2c"}, - {file = "yarl-1.9.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d8a1c6c0be645c745a081c192e747c5de06e944a0d21245f4cf7c05e457c36e0"}, - {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4b3c1ffe10069f655ea2d731808e76e0f452fc6c749bea04781daf18e6039525"}, - {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:549d19c84c55d11687ddbd47eeb348a89df9cb30e1993f1b128f4685cd0ebbf8"}, - {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7409f968456111140c1c95301cadf071bd30a81cbd7ab829169fb9e3d72eae9"}, - {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e23a6d84d9d1738dbc6e38167776107e63307dfc8ad108e580548d1f2c587f42"}, - {file = "yarl-1.9.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d8b889777de69897406c9fb0b76cdf2fd0f31267861ae7501d93003d55f54fbe"}, - {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:03caa9507d3d3c83bca08650678e25364e1843b484f19986a527630ca376ecce"}, - {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4e9035df8d0880b2f1c7f5031f33f69e071dfe72ee9310cfc76f7b605958ceb9"}, - {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:c0ec0ed476f77db9fb29bca17f0a8fcc7bc97ad4c6c1d8959c507decb22e8572"}, - {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:ee04010f26d5102399bd17f8df8bc38dc7ccd7701dc77f4a68c5b8d733406958"}, - {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:49a180c2e0743d5d6e0b4d1a9e5f633c62eca3f8a86ba5dd3c471060e352ca98"}, - {file = "yarl-1.9.4-cp311-cp311-win32.whl", hash = "sha256:81eb57278deb6098a5b62e88ad8281b2ba09f2f1147c4767522353eaa6260b31"}, - {file = "yarl-1.9.4-cp311-cp311-win_amd64.whl", hash = "sha256:d1d2532b340b692880261c15aee4dc94dd22ca5d61b9db9a8a361953d36410b1"}, - {file = "yarl-1.9.4-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0d2454f0aef65ea81037759be5ca9947539667eecebca092733b2eb43c965a81"}, - {file = "yarl-1.9.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:44d8ffbb9c06e5a7f529f38f53eda23e50d1ed33c6c869e01481d3fafa6b8142"}, - {file = "yarl-1.9.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:aaaea1e536f98754a6e5c56091baa1b6ce2f2700cc4a00b0d49eca8dea471074"}, - {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3777ce5536d17989c91696db1d459574e9a9bd37660ea7ee4d3344579bb6f129"}, - {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fc5fc1eeb029757349ad26bbc5880557389a03fa6ada41703db5e068881e5f2"}, - {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ea65804b5dc88dacd4a40279af0cdadcfe74b3e5b4c897aa0d81cf86927fee78"}, - {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa102d6d280a5455ad6a0f9e6d769989638718e938a6a0a2ff3f4a7ff8c62cc4"}, - {file = "yarl-1.9.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09efe4615ada057ba2d30df871d2f668af661e971dfeedf0c159927d48bbeff0"}, - {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:008d3e808d03ef28542372d01057fd09168419cdc8f848efe2804f894ae03e51"}, - {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:6f5cb257bc2ec58f437da2b37a8cd48f666db96d47b8a3115c29f316313654ff"}, - {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:992f18e0ea248ee03b5a6e8b3b4738850ae7dbb172cc41c966462801cbf62cf7"}, - {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:0e9d124c191d5b881060a9e5060627694c3bdd1fe24c5eecc8d5d7d0eb6faabc"}, - {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3986b6f41ad22988e53d5778f91855dc0399b043fc8946d4f2e68af22ee9ff10"}, - {file = "yarl-1.9.4-cp312-cp312-win32.whl", hash = "sha256:4b21516d181cd77ebd06ce160ef8cc2a5e9ad35fb1c5930882baff5ac865eee7"}, - {file = "yarl-1.9.4-cp312-cp312-win_amd64.whl", hash = "sha256:a9bd00dc3bc395a662900f33f74feb3e757429e545d831eef5bb280252631984"}, - {file = "yarl-1.9.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:63b20738b5aac74e239622d2fe30df4fca4942a86e31bf47a81a0e94c14df94f"}, - {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7d7f7de27b8944f1fee2c26a88b4dabc2409d2fea7a9ed3df79b67277644e17"}, - {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c74018551e31269d56fab81a728f683667e7c28c04e807ba08f8c9e3bba32f14"}, - {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ca06675212f94e7a610e85ca36948bb8fc023e458dd6c63ef71abfd482481aa5"}, - {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5aef935237d60a51a62b86249839b51345f47564208c6ee615ed2a40878dccdd"}, - {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b134fd795e2322b7684155b7855cc99409d10b2e408056db2b93b51a52accc7"}, - {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d25039a474c4c72a5ad4b52495056f843a7ff07b632c1b92ea9043a3d9950f6e"}, - {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f7d6b36dd2e029b6bcb8a13cf19664c7b8e19ab3a58e0fefbb5b8461447ed5ec"}, - {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:957b4774373cf6f709359e5c8c4a0af9f6d7875db657adb0feaf8d6cb3c3964c"}, - {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:d7eeb6d22331e2fd42fce928a81c697c9ee2d51400bd1a28803965883e13cead"}, - {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:6a962e04b8f91f8c4e5917e518d17958e3bdee71fd1d8b88cdce74dd0ebbf434"}, - {file = "yarl-1.9.4-cp37-cp37m-win32.whl", hash = "sha256:f3bc6af6e2b8f92eced34ef6a96ffb248e863af20ef4fde9448cc8c9b858b749"}, - {file = "yarl-1.9.4-cp37-cp37m-win_amd64.whl", hash = "sha256:ad4d7a90a92e528aadf4965d685c17dacff3df282db1121136c382dc0b6014d2"}, - {file = "yarl-1.9.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ec61d826d80fc293ed46c9dd26995921e3a82146feacd952ef0757236fc137be"}, - {file = "yarl-1.9.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8be9e837ea9113676e5754b43b940b50cce76d9ed7d2461df1af39a8ee674d9f"}, - {file = "yarl-1.9.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:bef596fdaa8f26e3d66af846bbe77057237cb6e8efff8cd7cc8dff9a62278bbf"}, - {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d47552b6e52c3319fede1b60b3de120fe83bde9b7bddad11a69fb0af7db32f1"}, - {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84fc30f71689d7fc9168b92788abc977dc8cefa806909565fc2951d02f6b7d57"}, - {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4aa9741085f635934f3a2583e16fcf62ba835719a8b2b28fb2917bb0537c1dfa"}, - {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:206a55215e6d05dbc6c98ce598a59e6fbd0c493e2de4ea6cc2f4934d5a18d130"}, - {file = "yarl-1.9.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07574b007ee20e5c375a8fe4a0789fad26db905f9813be0f9fef5a68080de559"}, - {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5a2e2433eb9344a163aced6a5f6c9222c0786e5a9e9cac2c89f0b28433f56e23"}, - {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6ad6d10ed9b67a382b45f29ea028f92d25bc0bc1daf6c5b801b90b5aa70fb9ec"}, - {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:6fe79f998a4052d79e1c30eeb7d6c1c1056ad33300f682465e1b4e9b5a188b78"}, - {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a825ec844298c791fd28ed14ed1bffc56a98d15b8c58a20e0e08c1f5f2bea1be"}, - {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8619d6915b3b0b34420cf9b2bb6d81ef59d984cb0fde7544e9ece32b4b3043c3"}, - {file = "yarl-1.9.4-cp38-cp38-win32.whl", hash = "sha256:686a0c2f85f83463272ddffd4deb5e591c98aac1897d65e92319f729c320eece"}, - {file = "yarl-1.9.4-cp38-cp38-win_amd64.whl", hash = "sha256:a00862fb23195b6b8322f7d781b0dc1d82cb3bcac346d1e38689370cc1cc398b"}, - {file = "yarl-1.9.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:604f31d97fa493083ea21bd9b92c419012531c4e17ea6da0f65cacdcf5d0bd27"}, - {file = "yarl-1.9.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8a854227cf581330ffa2c4824d96e52ee621dd571078a252c25e3a3b3d94a1b1"}, - {file = "yarl-1.9.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ba6f52cbc7809cd8d74604cce9c14868306ae4aa0282016b641c661f981a6e91"}, - {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a6327976c7c2f4ee6816eff196e25385ccc02cb81427952414a64811037bbc8b"}, - {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8397a3817d7dcdd14bb266283cd1d6fc7264a48c186b986f32e86d86d35fbac5"}, - {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e0381b4ce23ff92f8170080c97678040fc5b08da85e9e292292aba67fdac6c34"}, - {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23d32a2594cb5d565d358a92e151315d1b2268bc10f4610d098f96b147370136"}, - {file = "yarl-1.9.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ddb2a5c08a4eaaba605340fdee8fc08e406c56617566d9643ad8bf6852778fc7"}, - {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:26a1dc6285e03f3cc9e839a2da83bcbf31dcb0d004c72d0730e755b33466c30e"}, - {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:18580f672e44ce1238b82f7fb87d727c4a131f3a9d33a5e0e82b793362bf18b4"}, - {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:29e0f83f37610f173eb7e7b5562dd71467993495e568e708d99e9d1944f561ec"}, - {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:1f23e4fe1e8794f74b6027d7cf19dc25f8b63af1483d91d595d4a07eca1fb26c"}, - {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:db8e58b9d79200c76956cefd14d5c90af54416ff5353c5bfd7cbe58818e26ef0"}, - {file = "yarl-1.9.4-cp39-cp39-win32.whl", hash = "sha256:c7224cab95645c7ab53791022ae77a4509472613e839dab722a72abe5a684575"}, - {file = "yarl-1.9.4-cp39-cp39-win_amd64.whl", hash = "sha256:824d6c50492add5da9374875ce72db7a0733b29c2394890aef23d533106e2b15"}, - {file = "yarl-1.9.4-py3-none-any.whl", hash = "sha256:928cecb0ef9d5a7946eb6ff58417ad2fe9375762382f1bf5c55e61645f2c43ad"}, - {file = "yarl-1.9.4.tar.gz", hash = "sha256:566db86717cf8080b99b58b083b773a908ae40f06681e87e589a976faf8246bf"}, + {file = "yarl-1.15.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e4ee8b8639070ff246ad3649294336b06db37a94bdea0d09ea491603e0be73b8"}, + {file = "yarl-1.15.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a7cf963a357c5f00cb55b1955df8bbe68d2f2f65de065160a1c26b85a1e44172"}, + {file = "yarl-1.15.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:43ebdcc120e2ca679dba01a779333a8ea76b50547b55e812b8b92818d604662c"}, + {file = "yarl-1.15.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3433da95b51a75692dcf6cc8117a31410447c75a9a8187888f02ad45c0a86c50"}, + {file = "yarl-1.15.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:38d0124fa992dbacd0c48b1b755d3ee0a9f924f427f95b0ef376556a24debf01"}, + {file = "yarl-1.15.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ded1b1803151dd0f20a8945508786d57c2f97a50289b16f2629f85433e546d47"}, + {file = "yarl-1.15.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ace4cad790f3bf872c082366c9edd7f8f8f77afe3992b134cfc810332206884f"}, + {file = "yarl-1.15.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c77494a2f2282d9bbbbcab7c227a4d1b4bb829875c96251f66fb5f3bae4fb053"}, + {file = "yarl-1.15.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b7f227ca6db5a9fda0a2b935a2ea34a7267589ffc63c8045f0e4edb8d8dcf956"}, + {file = "yarl-1.15.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:31561a5b4d8dbef1559b3600b045607cf804bae040f64b5f5bca77da38084a8a"}, + {file = "yarl-1.15.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3e52474256a7db9dcf3c5f4ca0b300fdea6c21cca0148c8891d03a025649d935"}, + {file = "yarl-1.15.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:0e1af74a9529a1137c67c887ed9cde62cff53aa4d84a3adbec329f9ec47a3936"}, + {file = "yarl-1.15.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:15c87339490100c63472a76d87fe7097a0835c705eb5ae79fd96e343473629ed"}, + {file = "yarl-1.15.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:74abb8709ea54cc483c4fb57fb17bb66f8e0f04438cff6ded322074dbd17c7ec"}, + {file = "yarl-1.15.2-cp310-cp310-win32.whl", hash = "sha256:ffd591e22b22f9cb48e472529db6a47203c41c2c5911ff0a52e85723196c0d75"}, + {file = "yarl-1.15.2-cp310-cp310-win_amd64.whl", hash = "sha256:1695497bb2a02a6de60064c9f077a4ae9c25c73624e0d43e3aa9d16d983073c2"}, + {file = "yarl-1.15.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9fcda20b2de7042cc35cf911702fa3d8311bd40055a14446c1e62403684afdc5"}, + {file = "yarl-1.15.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0545de8c688fbbf3088f9e8b801157923be4bf8e7b03e97c2ecd4dfa39e48e0e"}, + {file = "yarl-1.15.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fbda058a9a68bec347962595f50546a8a4a34fd7b0654a7b9697917dc2bf810d"}, + {file = "yarl-1.15.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1ac2bc069f4a458634c26b101c2341b18da85cb96afe0015990507efec2e417"}, + {file = "yarl-1.15.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cd126498171f752dd85737ab1544329a4520c53eed3997f9b08aefbafb1cc53b"}, + {file = "yarl-1.15.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3db817b4e95eb05c362e3b45dafe7144b18603e1211f4a5b36eb9522ecc62bcf"}, + {file = "yarl-1.15.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:076b1ed2ac819933895b1a000904f62d615fe4533a5cf3e052ff9a1da560575c"}, + {file = "yarl-1.15.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f8cfd847e6b9ecf9f2f2531c8427035f291ec286c0a4944b0a9fce58c6446046"}, + {file = "yarl-1.15.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:32b66be100ac5739065496c74c4b7f3015cef792c3174982809274d7e51b3e04"}, + {file = "yarl-1.15.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:34a2d76a1984cac04ff8b1bfc939ec9dc0914821264d4a9c8fd0ed6aa8d4cfd2"}, + {file = "yarl-1.15.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0afad2cd484908f472c8fe2e8ef499facee54a0a6978be0e0cff67b1254fd747"}, + {file = "yarl-1.15.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c68e820879ff39992c7f148113b46efcd6ec765a4865581f2902b3c43a5f4bbb"}, + {file = "yarl-1.15.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:98f68df80ec6ca3015186b2677c208c096d646ef37bbf8b49764ab4a38183931"}, + {file = "yarl-1.15.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3c56ec1eacd0a5d35b8a29f468659c47f4fe61b2cab948ca756c39b7617f0aa5"}, + {file = "yarl-1.15.2-cp311-cp311-win32.whl", hash = "sha256:eedc3f247ee7b3808ea07205f3e7d7879bc19ad3e6222195cd5fbf9988853e4d"}, + {file = "yarl-1.15.2-cp311-cp311-win_amd64.whl", hash = "sha256:0ccaa1bc98751fbfcf53dc8dfdb90d96e98838010fc254180dd6707a6e8bb179"}, + {file = "yarl-1.15.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:82d5161e8cb8f36ec778fd7ac4d740415d84030f5b9ef8fe4da54784a1f46c94"}, + {file = "yarl-1.15.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fa2bea05ff0a8fb4d8124498e00e02398f06d23cdadd0fe027d84a3f7afde31e"}, + {file = "yarl-1.15.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:99e12d2bf587b44deb74e0d6170fec37adb489964dbca656ec41a7cd8f2ff178"}, + {file = "yarl-1.15.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:243fbbbf003754fe41b5bdf10ce1e7f80bcc70732b5b54222c124d6b4c2ab31c"}, + {file = "yarl-1.15.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:856b7f1a7b98a8c31823285786bd566cf06226ac4f38b3ef462f593c608a9bd6"}, + {file = "yarl-1.15.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:553dad9af802a9ad1a6525e7528152a015b85fb8dbf764ebfc755c695f488367"}, + {file = "yarl-1.15.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:30c3ff305f6e06650a761c4393666f77384f1cc6c5c0251965d6bfa5fbc88f7f"}, + {file = "yarl-1.15.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:353665775be69bbfc6d54c8d134bfc533e332149faeddd631b0bc79df0897f46"}, + {file = "yarl-1.15.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f4fe99ce44128c71233d0d72152db31ca119711dfc5f2c82385ad611d8d7f897"}, + {file = "yarl-1.15.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:9c1e3ff4b89cdd2e1a24c214f141e848b9e0451f08d7d4963cb4108d4d798f1f"}, + {file = "yarl-1.15.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:711bdfae4e699a6d4f371137cbe9e740dc958530cb920eb6f43ff9551e17cfbc"}, + {file = "yarl-1.15.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4388c72174868884f76affcdd3656544c426407e0043c89b684d22fb265e04a5"}, + {file = "yarl-1.15.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:f0e1844ad47c7bd5d6fa784f1d4accc5f4168b48999303a868fe0f8597bde715"}, + {file = "yarl-1.15.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a5cafb02cf097a82d74403f7e0b6b9df3ffbfe8edf9415ea816314711764a27b"}, + {file = "yarl-1.15.2-cp312-cp312-win32.whl", hash = "sha256:156ececdf636143f508770bf8a3a0498de64da5abd890c7dbb42ca9e3b6c05b8"}, + {file = "yarl-1.15.2-cp312-cp312-win_amd64.whl", hash = "sha256:435aca062444a7f0c884861d2e3ea79883bd1cd19d0a381928b69ae1b85bc51d"}, + {file = "yarl-1.15.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:416f2e3beaeae81e2f7a45dc711258be5bdc79c940a9a270b266c0bec038fb84"}, + {file = "yarl-1.15.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:173563f3696124372831007e3d4b9821746964a95968628f7075d9231ac6bb33"}, + {file = "yarl-1.15.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9ce2e0f6123a60bd1a7f5ae3b2c49b240c12c132847f17aa990b841a417598a2"}, + {file = "yarl-1.15.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eaea112aed589131f73d50d570a6864728bd7c0c66ef6c9154ed7b59f24da611"}, + {file = "yarl-1.15.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e4ca3b9f370f218cc2a0309542cab8d0acdfd66667e7c37d04d617012485f904"}, + {file = "yarl-1.15.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:23ec1d3c31882b2a8a69c801ef58ebf7bae2553211ebbddf04235be275a38548"}, + {file = "yarl-1.15.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75119badf45f7183e10e348edff5a76a94dc19ba9287d94001ff05e81475967b"}, + {file = "yarl-1.15.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78e6fdc976ec966b99e4daa3812fac0274cc28cd2b24b0d92462e2e5ef90d368"}, + {file = "yarl-1.15.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:8657d3f37f781d987037f9cc20bbc8b40425fa14380c87da0cb8dfce7c92d0fb"}, + {file = "yarl-1.15.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:93bed8a8084544c6efe8856c362af08a23e959340c87a95687fdbe9c9f280c8b"}, + {file = "yarl-1.15.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:69d5856d526802cbda768d3e6246cd0d77450fa2a4bc2ea0ea14f0d972c2894b"}, + {file = "yarl-1.15.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:ccad2800dfdff34392448c4bf834be124f10a5bc102f254521d931c1c53c455a"}, + {file = "yarl-1.15.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:a880372e2e5dbb9258a4e8ff43f13888039abb9dd6d515f28611c54361bc5644"}, + {file = "yarl-1.15.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c998d0558805860503bc3a595994895ca0f7835e00668dadc673bbf7f5fbfcbe"}, + {file = "yarl-1.15.2-cp313-cp313-win32.whl", hash = "sha256:533a28754e7f7439f217550a497bb026c54072dbe16402b183fdbca2431935a9"}, + {file = "yarl-1.15.2-cp313-cp313-win_amd64.whl", hash = "sha256:5838f2b79dc8f96fdc44077c9e4e2e33d7089b10788464609df788eb97d03aad"}, + {file = "yarl-1.15.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:fbbb63bed5fcd70cd3dd23a087cd78e4675fb5a2963b8af53f945cbbca79ae16"}, + {file = "yarl-1.15.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e2e93b88ecc8f74074012e18d679fb2e9c746f2a56f79cd5e2b1afcf2a8a786b"}, + {file = "yarl-1.15.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:af8ff8d7dc07ce873f643de6dfbcd45dc3db2c87462e5c387267197f59e6d776"}, + {file = "yarl-1.15.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:66f629632220a4e7858b58e4857927dd01a850a4cef2fb4044c8662787165cf7"}, + {file = "yarl-1.15.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:833547179c31f9bec39b49601d282d6f0ea1633620701288934c5f66d88c3e50"}, + {file = "yarl-1.15.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2aa738e0282be54eede1e3f36b81f1e46aee7ec7602aa563e81e0e8d7b67963f"}, + {file = "yarl-1.15.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a13a07532e8e1c4a5a3afff0ca4553da23409fad65def1b71186fb867eeae8d"}, + {file = "yarl-1.15.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c45817e3e6972109d1a2c65091504a537e257bc3c885b4e78a95baa96df6a3f8"}, + {file = "yarl-1.15.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:670eb11325ed3a6209339974b276811867defe52f4188fe18dc49855774fa9cf"}, + {file = "yarl-1.15.2-cp38-cp38-musllinux_1_2_armv7l.whl", hash = "sha256:d417a4f6943112fae3924bae2af7112562285848d9bcee737fc4ff7cbd450e6c"}, + {file = "yarl-1.15.2-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:bc8936d06cd53fddd4892677d65e98af514c8d78c79864f418bbf78a4a2edde4"}, + {file = "yarl-1.15.2-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:954dde77c404084c2544e572f342aef384240b3e434e06cecc71597e95fd1ce7"}, + {file = "yarl-1.15.2-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:5bc0df728e4def5e15a754521e8882ba5a5121bd6b5a3a0ff7efda5d6558ab3d"}, + {file = "yarl-1.15.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:b71862a652f50babab4a43a487f157d26b464b1dedbcc0afda02fd64f3809d04"}, + {file = "yarl-1.15.2-cp38-cp38-win32.whl", hash = "sha256:63eab904f8630aed5a68f2d0aeab565dcfc595dc1bf0b91b71d9ddd43dea3aea"}, + {file = "yarl-1.15.2-cp38-cp38-win_amd64.whl", hash = "sha256:2cf441c4b6e538ba0d2591574f95d3fdd33f1efafa864faa077d9636ecc0c4e9"}, + {file = "yarl-1.15.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a32d58f4b521bb98b2c0aa9da407f8bd57ca81f34362bcb090e4a79e9924fefc"}, + {file = "yarl-1.15.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:766dcc00b943c089349d4060b935c76281f6be225e39994c2ccec3a2a36ad627"}, + {file = "yarl-1.15.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:bed1b5dbf90bad3bfc19439258c97873eab453c71d8b6869c136346acfe497e7"}, + {file = "yarl-1.15.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed20a4bdc635f36cb19e630bfc644181dd075839b6fc84cac51c0f381ac472e2"}, + {file = "yarl-1.15.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d538df442c0d9665664ab6dd5fccd0110fa3b364914f9c85b3ef9b7b2e157980"}, + {file = "yarl-1.15.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c6cf1d92edf936ceedc7afa61b07e9d78a27b15244aa46bbcd534c7458ee1b"}, + {file = "yarl-1.15.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce44217ad99ffad8027d2fde0269ae368c86db66ea0571c62a000798d69401fb"}, + {file = "yarl-1.15.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b47a6000a7e833ebfe5886b56a31cb2ff12120b1efd4578a6fcc38df16cc77bd"}, + {file = "yarl-1.15.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:e52f77a0cd246086afde8815039f3e16f8d2be51786c0a39b57104c563c5cbb0"}, + {file = "yarl-1.15.2-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:f9ca0e6ce7774dc7830dc0cc4bb6b3eec769db667f230e7c770a628c1aa5681b"}, + {file = "yarl-1.15.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:136f9db0f53c0206db38b8cd0c985c78ded5fd596c9a86ce5c0b92afb91c3a19"}, + {file = "yarl-1.15.2-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:173866d9f7409c0fb514cf6e78952e65816600cb888c68b37b41147349fe0057"}, + {file = "yarl-1.15.2-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:6e840553c9c494a35e449a987ca2c4f8372668ee954a03a9a9685075228e5036"}, + {file = "yarl-1.15.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:458c0c65802d816a6b955cf3603186de79e8fdb46d4f19abaec4ef0a906f50a7"}, + {file = "yarl-1.15.2-cp39-cp39-win32.whl", hash = "sha256:5b48388ded01f6f2429a8c55012bdbd1c2a0c3735b3e73e221649e524c34a58d"}, + {file = "yarl-1.15.2-cp39-cp39-win_amd64.whl", hash = "sha256:81dadafb3aa124f86dc267a2168f71bbd2bfb163663661ab0038f6e4b8edb810"}, + {file = "yarl-1.15.2-py3-none-any.whl", hash = "sha256:0d3105efab7c5c091609abacad33afff33bdff0035bece164c98bcf5a85ef90a"}, + {file = "yarl-1.15.2.tar.gz", hash = "sha256:a39c36f4218a5bb668b4f06874d676d35a035ee668e6e7e3538835c703634b84"}, ] [package.dependencies] idna = ">=2.0" multidict = ">=4.0" +propcache = ">=0.2.0" [metadata] lock-version = "2.0" python-versions = "^3.8" -content-hash = "4839606a2b6399486c0131ebc56057085dc19adb2b4f5f3b3a480476a4c41fff" +content-hash = "e4f32f4286c2558ea80fcba84acb74bb0a6d10ff33f02edaa7a36330ea25e07b" diff --git a/pyproject.toml b/pyproject.toml index 0cb6bdd8..39f4ae29 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -65,7 +65,8 @@ pmjs = "pythonmonkey.cli.pmjs:main" pytest = "^7.3.1" pip = "^23.1.2" numpy = [ - {version = "^2.1.0", python = ">=3.10"}, + {version = "^2.3.0", python = ">=3.11"}, + {version = "^2.1.0", python = ">=3.10,<3.11"}, # NumPy 2.3.0 drops support for Python 3.10 {version = "^2.0.1", python = ">=3.9,<3.10"}, # NumPy 2.1.0 drops support for Python 3.9 {version = "^1.24.3", python = ">=3.8,<3.9"}, # NumPy 1.25.0 drops support for Python 3.8 ] From 8e1bfe2e0c055e1b5043574a32615205480298aa Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Fri, 19 Sep 2025 15:22:26 +0000 Subject: [PATCH 416/428] fix(event-loop): fix `_getLoopOnThread` for Python 3.14 compatibility --- src/PyEventLoop.cc | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/PyEventLoop.cc b/src/PyEventLoop.cc index 3e51eabb..14b6f003 100644 --- a/src/PyEventLoop.cc +++ b/src/PyEventLoop.cc @@ -155,7 +155,14 @@ PyEventLoop PyEventLoop::_getLoopOnThread(PyThreadState *tstate) { // See https://github.com/python/cpython/blob/v3.13.0rc1/Include/internal/pycore_tstate.h#L17-L24 using PyThreadStateHolder = struct { // _PyThreadStateImpl PyThreadState base; - PyObject *asyncio_running_loop; // we only need the first field of `_PyThreadStateImpl` + #if PY_VERSION_HEX >= 0x030e0000 // Python version is greater than 3.14 + // the struct is changed with more additional fields, see https://github.com/python/cpython/blob/v3.14.0rc3/Include/internal/pycore_tstate.h#L24-L40 + Py_ssize_t refcount; + uintptr_t c_stack_top; + uintptr_t c_stack_soft_limit; + uintptr_t c_stack_hard_limit; + #endif + PyObject *asyncio_running_loop; // we only need the first few fields of `_PyThreadStateImpl` }; // Modified from https://github.com/python/cpython/blob/v3.13.0rc1/Modules/_asynciomodule.c#L3205-L3210 From f83ef8a783025dda50e95effa8127ec30c2a25e1 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Fri, 19 Sep 2025 15:27:21 +0000 Subject: [PATCH 417/428] test(event-loop): Python 3.14 changed the error message format --- tests/python/test_event_loop.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/python/test_event_loop.py b/tests/python/test_event_loop.py index 27c3ba87..2e4215ea 100644 --- a/tests/python/test_event_loop.py +++ b/tests/python/test_event_loop.py @@ -273,7 +273,8 @@ async def c(): assert "nested" == await pm.eval("(promise) => promise")(c()) assert "nested" == await pm.eval("(promise) => promise")(await c()) assert "nested" == await pm.eval("(promise) => promise")(await (await c())) - with pytest.raises(TypeError, match="object str can't be used in 'await' expression"): + with pytest.raises(TypeError, match="(object str can't be used in 'await' expression)|('str' object can't be awaited)"): + # Python 3.14 changed the error message format await pm.eval("(promise) => promise")(await (await (await c()))) # Python awaitable throwing exceptions From 799c7ea0ef3a5ee018c46892af58b1184d16d545 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Thu, 25 Sep 2025 15:20:25 +0000 Subject: [PATCH 418/428] chore(CI): use a pinned prerelease version for fast installation --- .github/workflows/test-and-publish.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index a0c320e2..44a02ba7 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -220,6 +220,10 @@ jobs: echo "$HOME/.pyenv/shims" >> $GITHUB_PATH echo "PYENV_ROOT=$HOME/.pyenv" >> $GITHUB_ENV export PATH="$HOME/.pyenv/bin:$PATH" + if [ "$PYTHON_VERSION" = "3.14-dev" ]; then + # Replacing 3.14-dev with a pinned prerelease version for fast installation + PYTHON_VERSION="3.14.0rc3" + fi pyenv install $PYTHON_VERSION pyenv global $PYTHON_VERSION env: @@ -244,6 +248,7 @@ jobs: fi echo "Installing python deps" poetry self add "poetry-dynamic-versioning[plugin]" + echo "Use the correct Python version we've set up" poetry env use python$PYTHON_VERSION || poetry env use python3 # use the correct Python version we've set up poetry install --no-root --only=dev echo "Installed Dependencies" From 7400379974e5d1f3ebe62d9087ee13f9586b1c11 Mon Sep 17 00:00:00 2001 From: Tom Wenzheng Tang Date: Fri, 6 Feb 2026 06:12:03 +0800 Subject: [PATCH 419/428] disable `aiodns`, fix futex deadlocks The locks created by `pycares`'s lingering threads would conflict with the locks created during JS JIT/GC in a rare condition. --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 39f4ae29..78edc0ef 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,7 +37,7 @@ include = [ [tool.poetry.dependencies] python = "^3.8" pyreadline3 = { version = "^3.4.1", platform = "win32" } -aiohttp = { version = "^3.9.5", extras = ["speedups"] } +aiohttp = { version = "^3.9.5" } pminit = { version = ">=0.4.0", allow-prereleases = true } @@ -83,4 +83,4 @@ ignore="E111,E114,E121" # allow 2-space indents verbose=true indent-size=2 aggressive=3 -exit-code=true \ No newline at end of file +exit-code=true From b7683ae640dfcda24344f2a510812217c3c9e47d Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Mon, 9 Feb 2026 16:57:57 +0000 Subject: [PATCH 420/428] chore: upgrade rust to v1.82 --- setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.sh b/setup.sh index 2001a374..5d01bd7a 100755 --- a/setup.sh +++ b/setup.sh @@ -27,7 +27,7 @@ else fi # Install rust compiler echo "Installing rust compiler" -curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.76 +curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.82 CARGO_BIN="$HOME/.cargo/bin/cargo" # also works for Windows. On Windows this equals to %USERPROFILE%\.cargo\bin\cargo $CARGO_BIN install cbindgen # Setup Poetry From 0ac66010c0c07b868c5173f078ee9223f572495d Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Mon, 9 Feb 2026 17:01:26 +0000 Subject: [PATCH 421/428] CI: `macos-13` runner is retired, use `macos-15-intel` runner instead for x86_64 macOS build --- .github/workflows/test-and-publish.yaml | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 44a02ba7..6ba4d15e 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -16,7 +16,7 @@ on: options: - '' - 'ubuntu-22.04' - - 'macos-13' + - 'macos-15-intel' - 'macos-14' - 'windows-2022' debug_enabled_python: @@ -67,8 +67,8 @@ jobs: strategy: fail-fast: false matrix: - # Use Ubuntu 22.04 / macOS 13 x86_64 / macOS 14 arm64 + Python 3.10 to build SpiderMonkey - os: [ 'ubuntu-22.04', 'macos-13', 'macos-14', 'ubuntu-22.04-arm' ] # macOS 14 runner exclusively runs on M1 hardwares + # Use Ubuntu 22.04 / macOS 15 x86_64 / macOS 14 arm64 + Python 3.10 to build SpiderMonkey + os: [ 'ubuntu-22.04', 'macos-15-intel', 'macos-14', 'ubuntu-22.04-arm' ] # macOS 14 runner exclusively runs on M1 hardwares # see https://github.blog/changelog/2024-01-30-github-actions-macos-14-sonoma-is-now-available python_version: [ '3.10' ] runs-on: ${{ matrix.os }} @@ -124,10 +124,6 @@ jobs: if: ${{ !startsWith(matrix.os, 'ubuntu') && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} with: python-version: ${{ matrix.python_version }} - - name: Setup XCode - if: ${{ matrix.os == 'macos-13' && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} - # SpiderMonkey requires XCode SDK version at least 13.3 - run: sudo xcode-select -switch /Applications/Xcode_14.3.app - name: Build spidermonkey if: ${{ steps.cache-spidermonkey.outputs.cache-hit != 'true' }} run: ./setup.sh @@ -181,7 +177,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ 'ubuntu-22.04', 'macos-13', 'macos-14', 'windows-2022', 'ubuntu-22.04-arm' ] + os: [ 'ubuntu-22.04', 'macos-15-intel', 'macos-14', 'windows-2022', 'ubuntu-22.04-arm' ] python_version: [ '3.8', '3.9', '3.10', '3.11', '3.12', '3.13', '3.14-dev' ] runs-on: ${{ matrix.os }} container: ${{ (startsWith(matrix.os, 'ubuntu') && 'ubuntu:20.04') || null }} @@ -293,7 +289,7 @@ jobs: BUILD_TYPE=${WORKFLOW_BUILD_TYPE:-"Debug"} poetry build --format=wheel ls -lah ./dist/ - name: Make the wheels we build also support lower versions of macOS - if: ${{ matrix.os == 'macos-13' || matrix.os == 'macos-14' }} + if: ${{ matrix.os == 'macos-15-intel' || matrix.os == 'macos-14' }} # Change the platform tag part of the wheel filename to `macosx_11_0_xxx` (means to support macOS 11.0 and above) # See https://packaging.python.org/en/latest/specifications/binary-distribution-format/#file-format # A wheel package file will only be selected by pip to install if the platform tag satisfies, regardless of whether the binary compatibility actually is. From 9a013226e23e8c2e726c387a0870eee15a5a09b8 Mon Sep 17 00:00:00 2001 From: Ryan Saweczko Date: Tue, 10 Feb 2026 15:27:38 -0500 Subject: [PATCH 422/428] CI: update rust to 1.85 for stable edition2024 --- setup.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.sh b/setup.sh index 5d01bd7a..3096525f 100755 --- a/setup.sh +++ b/setup.sh @@ -27,7 +27,7 @@ else fi # Install rust compiler echo "Installing rust compiler" -curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.82 +curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.85 CARGO_BIN="$HOME/.cargo/bin/cargo" # also works for Windows. On Windows this equals to %USERPROFILE%\.cargo\bin\cargo $CARGO_BIN install cbindgen # Setup Poetry @@ -127,4 +127,4 @@ if test -f .git/hooks/pre-commit; then fi cd ../.. echo "Done building uncrustify" -fi \ No newline at end of file +fi From 01aa5cb65a7b7cbaba22dc82a5cedf7486310b3d Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Wed, 1 Apr 2026 15:56:51 +0000 Subject: [PATCH 423/428] fix(CI): `-ld64` linker flag has been removed from Xcode 26 --- setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.sh b/setup.sh index 3096525f..a882422b 100755 --- a/setup.sh +++ b/setup.sh @@ -63,7 +63,7 @@ sed -i'' -e 's/return JS::GetWeakRefsEnabled() == JS::WeakRefSpecifier::Disabled sed -i'' -e 's/return !IsIteratorHelpersEnabled()/return false/' ./js/src/vm/GlobalObject.cpp # forcibly enable iterator helpers sed -i'' -e '/MOZ_CRASH_UNSAFE_PRINTF/,/__PRETTY_FUNCTION__);/d' ./mfbt/LinkedList.h # would crash in Debug Build: in `~LinkedList()` it should have removed all this list's elements before the list's destruction sed -i'' -e '/MOZ_ASSERT(stackRootPtr == nullptr);/d' ./js/src/vm/JSContext.cpp # would assert false in Debug Build since we extensively use `new JS::Rooted` -sed -i'' -e 's/"-fuse-ld=ld"/"-ld64" if c_compiler.version > "14.0.0" else "-fuse-ld=ld"/' ./build/moz.configure/toolchain.configure # XCode 15 changed the linker behaviour. See https://developer.apple.com/documentation/xcode-release-notes/xcode-15-release-notes#Linking +sed -i'' -e 's/"-fuse-ld=ld"/"-Wl,-ld_classic" if c_compiler.version > "14.0.0" else "-fuse-ld=ld"/' ./build/moz.configure/toolchain.configure # XCode 15 changed the linker behaviour. See https://developer.apple.com/documentation/xcode-release-notes/xcode-15-release-notes#Linking sed -i'' -e 's/defined(XP_WIN)/defined(_WIN32)/' ./mozglue/baseprofiler/public/BaseProfilerUtils.h # this header file is introduced to js/Debug.h in https://phabricator.services.mozilla.com/D221102, but it would be compiled without XP_WIN in this building configuration cd js/src From efdeb43cb88b018015115fe59ed174ec903e5d5d Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 7 Apr 2026 16:26:26 +0000 Subject: [PATCH 424/428] fix(CI): switch to an older Xcode version --- .github/workflows/test-and-publish.yaml | 4 ++++ setup.sh | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 6ba4d15e..29523de2 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -124,6 +124,10 @@ jobs: if: ${{ !startsWith(matrix.os, 'ubuntu') && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} with: python-version: ${{ matrix.python_version }} + - name: Setup XCode + if: ${{ matrix.os == 'macos-15-intel' && steps.cache-spidermonkey.outputs.cache-hit != 'true' }} + # Xcode 16.x removed the old linker behaviour (-ld64 or -ld_classic) that SpiderMonkey relies on, so we need to switch to an older version + run: sudo xcode-select -switch /Applications/Xcode_16.0.app - name: Build spidermonkey if: ${{ steps.cache-spidermonkey.outputs.cache-hit != 'true' }} run: ./setup.sh diff --git a/setup.sh b/setup.sh index a882422b..3096525f 100755 --- a/setup.sh +++ b/setup.sh @@ -63,7 +63,7 @@ sed -i'' -e 's/return JS::GetWeakRefsEnabled() == JS::WeakRefSpecifier::Disabled sed -i'' -e 's/return !IsIteratorHelpersEnabled()/return false/' ./js/src/vm/GlobalObject.cpp # forcibly enable iterator helpers sed -i'' -e '/MOZ_CRASH_UNSAFE_PRINTF/,/__PRETTY_FUNCTION__);/d' ./mfbt/LinkedList.h # would crash in Debug Build: in `~LinkedList()` it should have removed all this list's elements before the list's destruction sed -i'' -e '/MOZ_ASSERT(stackRootPtr == nullptr);/d' ./js/src/vm/JSContext.cpp # would assert false in Debug Build since we extensively use `new JS::Rooted` -sed -i'' -e 's/"-fuse-ld=ld"/"-Wl,-ld_classic" if c_compiler.version > "14.0.0" else "-fuse-ld=ld"/' ./build/moz.configure/toolchain.configure # XCode 15 changed the linker behaviour. See https://developer.apple.com/documentation/xcode-release-notes/xcode-15-release-notes#Linking +sed -i'' -e 's/"-fuse-ld=ld"/"-ld64" if c_compiler.version > "14.0.0" else "-fuse-ld=ld"/' ./build/moz.configure/toolchain.configure # XCode 15 changed the linker behaviour. See https://developer.apple.com/documentation/xcode-release-notes/xcode-15-release-notes#Linking sed -i'' -e 's/defined(XP_WIN)/defined(_WIN32)/' ./mozglue/baseprofiler/public/BaseProfilerUtils.h # this header file is introduced to js/Debug.h in https://phabricator.services.mozilla.com/D221102, but it would be compiled without XP_WIN in this building configuration cd js/src From a1543f18e9b5309dae7162fa9fef2bc49948d920 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 7 Apr 2026 18:06:45 +0000 Subject: [PATCH 425/428] test windows --- setup.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/setup.sh b/setup.sh index 3096525f..deebf5d6 100755 --- a/setup.sh +++ b/setup.sh @@ -2,6 +2,9 @@ set -euo pipefail IFS=$'\n\t' +echo "$ clang --print-target-triple" +clang --print-target-triple + # Get number of CPU cores CPUS=$(getconf _NPROCESSORS_ONLN 2>/dev/null || getconf NPROCESSORS_ONLN 2>/dev/null || echo 1) From 9e73e305d0dbf199efca960c6791e8e10889021c Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 7 Apr 2026 18:18:47 +0000 Subject: [PATCH 426/428] fix(CI): set the correct rust host triple to install (should be `x86_64-pc-windows-msvc`) --- setup.sh | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/setup.sh b/setup.sh index deebf5d6..bf28c6b2 100755 --- a/setup.sh +++ b/setup.sh @@ -2,9 +2,6 @@ set -euo pipefail IFS=$'\n\t' -echo "$ clang --print-target-triple" -clang --print-target-triple - # Get number of CPU cores CPUS=$(getconf _NPROCESSORS_ONLN 2>/dev/null || getconf NPROCESSORS_ONLN 2>/dev/null || echo 1) @@ -30,7 +27,7 @@ else fi # Install rust compiler echo "Installing rust compiler" -curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.85 +curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh -s -- -y --default-host "$(clang --print-target-triple)" --default-toolchain 1.85 CARGO_BIN="$HOME/.cargo/bin/cargo" # also works for Windows. On Windows this equals to %USERPROFILE%\.cargo\bin\cargo $CARGO_BIN install cbindgen # Setup Poetry From 6b2bf71ae22a46bfb256f365339c1f8d91a27411 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 7 Apr 2026 18:35:10 +0000 Subject: [PATCH 427/428] What? Who wrote the latest version of the rustup script? In its `get_architecture()` function, it's impossible to get to `-windows-msvc` error: error: the argument '--default-host ' cannot be used multiple times --- setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.sh b/setup.sh index bf28c6b2..c4033863 100755 --- a/setup.sh +++ b/setup.sh @@ -27,7 +27,7 @@ else fi # Install rust compiler echo "Installing rust compiler" -curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh -s -- -y --default-host "$(clang --print-target-triple)" --default-toolchain 1.85 +curl --proto '=https' --tlsv1.2 https://raw.githubusercontent.com/rust-lang/rustup/refs/tags/1.28.2/rustup-init.sh -sSf | sh -s -- -y --default-host "$(clang --print-target-triple)" --default-toolchain 1.85 CARGO_BIN="$HOME/.cargo/bin/cargo" # also works for Windows. On Windows this equals to %USERPROFILE%\.cargo\bin\cargo $CARGO_BIN install cbindgen # Setup Poetry From a6f51459a982b052fd7856e8ad5784bb9c32df35 Mon Sep 17 00:00:00 2001 From: Tom Tang Date: Tue, 7 Apr 2026 19:03:48 +0000 Subject: [PATCH 428/428] CI: Use the release version of Python 3.14 --- .github/workflows/test-and-publish.yaml | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/.github/workflows/test-and-publish.yaml b/.github/workflows/test-and-publish.yaml index 29523de2..ad562623 100644 --- a/.github/workflows/test-and-publish.yaml +++ b/.github/workflows/test-and-publish.yaml @@ -31,7 +31,7 @@ on: - '3.11' - '3.12' - '3.13' - - '3.14-dev' + - '3.14' build_type: type: choice description: 'Choose the build type to use' @@ -182,7 +182,7 @@ jobs: fail-fast: false matrix: os: [ 'ubuntu-22.04', 'macos-15-intel', 'macos-14', 'windows-2022', 'ubuntu-22.04-arm' ] - python_version: [ '3.8', '3.9', '3.10', '3.11', '3.12', '3.13', '3.14-dev' ] + python_version: [ '3.8', '3.9', '3.10', '3.11', '3.12', '3.13', '3.14' ] runs-on: ${{ matrix.os }} container: ${{ (startsWith(matrix.os, 'ubuntu') && 'ubuntu:20.04') || null }} steps: @@ -220,10 +220,6 @@ jobs: echo "$HOME/.pyenv/shims" >> $GITHUB_PATH echo "PYENV_ROOT=$HOME/.pyenv" >> $GITHUB_ENV export PATH="$HOME/.pyenv/bin:$PATH" - if [ "$PYTHON_VERSION" = "3.14-dev" ]; then - # Replacing 3.14-dev with a pinned prerelease version for fast installation - PYTHON_VERSION="3.14.0rc3" - fi pyenv install $PYTHON_VERSION pyenv global $PYTHON_VERSION env: