@@ -1121,6 +1121,7 @@ PythonQtPrivate::PythonQtPrivate()
11211121 _currentClassInfoForClassWrapperCreation = NULL ;
11221122 _profilingCB = NULL ;
11231123 _ErrorOccured = false ;
1124+ _SystemExitExceptionHandlerEnabled = false ;
11241125}
11251126
11261127void PythonQtPrivate::setupSharedLibrarySuffixes ()
@@ -1217,26 +1218,93 @@ void PythonQtPrivate::removeSignalEmitter(QObject* obj)
12171218 _signalReceivers.remove (obj);
12181219}
12191220
1221+ namespace
1222+ {
1223+ // ! adapted from python source file "pythonrun.c", function "handle_system_exit"
1224+ // ! return the exitcode instead of calling "Py_Exit".
1225+ // ! it gives the application an opportunity to properly terminate.
1226+ int custom_system_exit_exception_handler ()
1227+ {
1228+ PyObject *exception, *value, *tb;
1229+ int exitcode = 0 ;
1230+
1231+ // if (Py_InspectFlag)
1232+ // /* Don't exit if -i flag was given. This flag is set to 0
1233+ // * when entering interactive mode for inspecting. */
1234+ // return exitcode;
1235+
1236+ PyErr_Fetch (&exception, &value, &tb);
1237+ if (Py_FlushLine ())
1238+ PyErr_Clear ();
1239+ fflush (stdout);
1240+ if (value == NULL || value == Py_None)
1241+ goto done;
1242+ if (PyExceptionInstance_Check (value)) {
1243+ /* The error code should be in the `code' attribute. */
1244+ PyObject *code = PyObject_GetAttrString (value, " code" );
1245+ if (code) {
1246+ Py_DECREF (value);
1247+ value = code;
1248+ if (value == Py_None)
1249+ goto done;
1250+ }
1251+ /* If we failed to dig out the 'code' attribute,
1252+ just let the else clause below print the error. */
1253+ }
1254+ if (PyInt_Check (value))
1255+ exitcode = (int )PyInt_AsLong (value);
1256+ else {
1257+ PyObject *sys_stderr = PySys_GetObject (const_cast <char *>(" stderr" ));
1258+ if (sys_stderr != NULL && sys_stderr != Py_None) {
1259+ PyFile_WriteObject (value, sys_stderr, Py_PRINT_RAW);
1260+ } else {
1261+ PyObject_Print (value, stderr, Py_PRINT_RAW);
1262+ fflush (stderr);
1263+ }
1264+ PySys_WriteStderr (" \n " );
1265+ exitcode = 1 ;
1266+ }
1267+ done:
1268+ /* Restore and clear the exception info, in order to properly decref
1269+ * the exception, value, and traceback. If we just exit instead,
1270+ * these leak, which confuses PYTHONDUMPREFS output, and may prevent
1271+ * some finalizers from running.
1272+ */
1273+ PyErr_Restore (exception, value, tb);
1274+ PyErr_Clear ();
1275+ return exitcode;
1276+ // Py_Exit(exitcode);
1277+ }
1278+ }
1279+
12201280bool PythonQt::handleError ()
12211281{
12221282 bool flag = false ;
12231283 if (PyErr_Occurred ()) {
12241284
1225- // currently we just print the error and the stderr handler parses the errors
1226- PyErr_Print ();
1227-
1228- /*
1229- // EXTRA: the format of the ptype and ptraceback is not really documented, so I use PyErr_Print() above
1230- PyObject *ptype;
1231- PyObject *pvalue;
1232- PyObject *ptraceback;
1233- PyErr_Fetch( &ptype, &pvalue, &ptraceback);
1234-
1235- Py_XDECREF(ptype);
1236- Py_XDECREF(pvalue);
1237- Py_XDECREF(ptraceback);
1238- */
1239- PyErr_Clear ();
1285+ if (PythonQt::priv ()->_SystemExitExceptionHandlerEnabled &&
1286+ PyErr_ExceptionMatches (PyExc_SystemExit)) {
1287+ int exitcode = custom_system_exit_exception_handler ();
1288+ emit PythonQt::self ()->systemExitExceptionRaised (exitcode);
1289+ }
1290+ else
1291+ {
1292+ // currently we just print the error and the stderr handler parses the errors
1293+ PyErr_Print ();
1294+
1295+ /*
1296+ // EXTRA: the format of the ptype and ptraceback is not really documented, so I use PyErr_Print() above
1297+ PyObject *ptype;
1298+ PyObject *pvalue;
1299+ PyObject *ptraceback;
1300+ PyErr_Fetch( &ptype, &pvalue, &ptraceback);
1301+
1302+ Py_XDECREF(ptype);
1303+ Py_XDECREF(pvalue);
1304+ Py_XDECREF(ptraceback);
1305+ */
1306+ PyErr_Clear ();
1307+ }
12401308 flag = true ;
12411309 }
12421310 PythonQt::priv ()->_ErrorOccured = flag;
@@ -1256,6 +1324,22 @@ void PythonQt::resetErrorFlag()
12561324 }
12571325}
12581326
1327+ void PythonQt::setSystemExitExceptionHandlerEnabled (bool value)
1328+ {
1329+ if (PythonQt::self ())
1330+ {
1331+ PythonQt::priv ()->_SystemExitExceptionHandlerEnabled = value;
1332+ }
1333+ }
1334+
1335+ bool PythonQt::systemExitExceptionHandlerEnabled ()const
1336+ {
1337+ if (PythonQt::self ())
1338+ {
1339+ return PythonQt::priv ()->_SystemExitExceptionHandlerEnabled ;
1340+ }
1341+ }
1342+
12591343void PythonQt::addSysPath (const QString& path)
12601344{
12611345 PythonQtObjectPtr sys;
0 commit comments