@@ -196,6 +196,21 @@ JS::Value jsTypeFactorySafe(JSContext *cx, PyObject *object) {
196196 return v;
197197}
198198
199+ void setPyException (JSContext *cx) {
200+ // Python `exit` and `sys.exit` only raise a SystemExit exception to end the program
201+ // We definitely don't want to catch it in JS
202+ if (PyErr_ExceptionMatches (PyExc_SystemExit)) {
203+ return ;
204+ }
205+
206+ PyObject *type, *value, *traceback;
207+ PyErr_Fetch (&type, &value, &traceback); // also clears the error indicator
208+
209+ JSObject *jsException = ExceptionType (value).toJsError (cx);
210+ JS::RootedValue jsExceptionValue (cx, JS::ObjectValue (*jsException));
211+ JS_SetPendingException (cx, jsExceptionValue);
212+ }
213+
199214bool callPyFunc (JSContext *cx, unsigned int argc, JS::Value *vp) {
200215 JS::CallArgs callargs = JS::CallArgsFromVp (argc, vp);
201216
@@ -213,6 +228,7 @@ bool callPyFunc(JSContext *cx, unsigned int argc, JS::Value *vp) {
213228 PyObject *pyRval = _PyObject_CallNoArg (pyFunc); // in Python 3.8, the API is only available under the name with a leading underscore
214229 #endif
215230 if (PyErr_Occurred ()) { // Check if an exception has already been set in Python error stack
231+ setPyException (cx);
216232 return false ;
217233 }
218234 // @TODO (Caleb Aikens) need to check for python exceptions here
@@ -233,11 +249,13 @@ bool callPyFunc(JSContext *cx, unsigned int argc, JS::Value *vp) {
233249
234250 PyObject *pyRval = PyObject_Call (pyFunc, pyArgs, NULL );
235251 if (PyErr_Occurred ()) {
252+ setPyException (cx);
236253 return false ;
237254 }
238255 // @TODO (Caleb Aikens) need to check for python exceptions here
239256 callargs.rval ().set (jsTypeFactory (cx, pyRval));
240257 if (PyErr_Occurred ()) {
258+ setPyException (cx);
241259 return false ;
242260 }
243261
0 commit comments