@@ -1121,6 +1121,7 @@ PythonQtPrivate::PythonQtPrivate()
1121
1121
_currentClassInfoForClassWrapperCreation = NULL ;
1122
1122
_profilingCB = NULL ;
1123
1123
_ErrorOccured = false ;
1124
+ _SystemExitExceptionHandlerEnabled = false ;
1124
1125
}
1125
1126
1126
1127
void PythonQtPrivate::setupSharedLibrarySuffixes ()
@@ -1217,26 +1218,93 @@ void PythonQtPrivate::removeSignalEmitter(QObject* obj)
1217
1218
_signalReceivers.remove (obj);
1218
1219
}
1219
1220
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
+
1220
1280
bool PythonQt::handleError ()
1221
1281
{
1222
1282
bool flag = false ;
1223
1283
if (PyErr_Occurred ()) {
1224
1284
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
+ }
1240
1308
flag = true ;
1241
1309
}
1242
1310
PythonQt::priv ()->_ErrorOccured = flag;
@@ -1256,6 +1324,22 @@ void PythonQt::resetErrorFlag()
1256
1324
}
1257
1325
}
1258
1326
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
+
1259
1343
void PythonQt::addSysPath (const QString& path)
1260
1344
{
1261
1345
PythonQtObjectPtr sys;
0 commit comments