diff --git a/tools/client-plugins/browser-scripts/python-worker.ts b/tools/client-plugins/browser-scripts/python-worker.ts index 69840437f19..e91b2804da9 100644 --- a/tools/client-plugins/browser-scripts/python-worker.ts +++ b/tools/client-plugins/browser-scripts/python-worker.ts @@ -106,6 +106,10 @@ function initRunPython() { }; } + function __interruptExecution() { + postMessage({ type: 'reset' }); + } + // I tried setting jsglobals here, to provide 'input' and 'print' to python, // without having to modify the global window object. However, it didn't work // because pyodide needs access to that object. Instead, I used @@ -114,7 +118,8 @@ function initRunPython() { // Make print available to python pyodide.registerJsModule('jscustom', { print, - input + input, + __interruptExecution }); // Create fresh globals each time user code is run. // eslint-disable-next-line @typescript-eslint/no-unsafe-call @@ -123,20 +128,29 @@ function initRunPython() { // have this set by default. // eslint-disable-next-line @typescript-eslint/no-unsafe-call globals.set('__name__', '__main__'); + // The runPython helper is a shortcut for running python code with our // custom globals. const runPython = (pyCode: string) => pyodide!.runPython(pyCode, { globals }) as unknown; + runPython(` + from pyodide.ffi import JsException + import jscustom from jscustom import print from jscustom import input + def __wrap(func): def fn(*args): - data = func(*args) - if data.type == 'cancel': - raise KeyboardInterrupt(data.value) - return data.value + try: + data = func(*args) + if data.type == 'cancel': + raise KeyboardInterrupt(data.value) + return data.value + except JsException: + jscustom.__interruptExecution() + raise return fn input = __wrap(input) `);