@@ -687,6 +687,7 PythonQtObjectPtr PythonQt::importModule(const QString& name) | |||
|
687 | 687 | |
|
688 | 688 | QVariant PythonQt::evalCode(PyObject* object, PyObject* pycode) { |
|
689 | 689 | QVariant result; |
|
690 | clearError(); | |
|
690 | 691 | if (pycode) { |
|
691 | 692 | PyObject* dict = NULL; |
|
692 | 693 | PyObject* globals = NULL; |
@@ -721,6 +722,7 QVariant PythonQt::evalScript(PyObject* object, const QString& script, int start | |||
|
721 | 722 | QVariant result; |
|
722 | 723 | PythonQtObjectPtr p; |
|
723 | 724 | PyObject* dict = NULL; |
|
725 | clearError(); | |
|
724 | 726 | if (PyModule_Check(object)) { |
|
725 | 727 | dict = PyModule_GetDict(object); |
|
726 | 728 | } else if (PyDict_Check(object)) { |
@@ -740,6 +742,7 QVariant PythonQt::evalScript(PyObject* object, const QString& script, int start | |||
|
740 | 742 | void PythonQt::evalFile(PyObject* module, const QString& filename) |
|
741 | 743 | { |
|
742 | 744 | PythonQtObjectPtr code = parseFile(filename); |
|
745 | clearError(); | |
|
743 | 746 | if (code) { |
|
744 | 747 | evalCode(module, code); |
|
745 | 748 | } else { |
@@ -751,6 +754,7 PythonQtObjectPtr PythonQt::parseFile(const QString& filename) | |||
|
751 | 754 | { |
|
752 | 755 | PythonQtObjectPtr p; |
|
753 | 756 | p.setNewRef(PythonQtImport::getCodeFromPyc(filename)); |
|
757 | clearError(); | |
|
754 | 758 | if (!p) { |
|
755 | 759 | handleError(); |
|
756 | 760 | } |
@@ -1040,6 +1044,7 QVariant PythonQt::call(PyObject* callable, const QVariantList& args, const QVar | |||
|
1040 | 1044 | QVariant r; |
|
1041 | 1045 | PythonQtObjectPtr result; |
|
1042 | 1046 | result.setNewRef(callAndReturnPyObject(callable, args, kwargs)); |
|
1047 | clearError(); | |
|
1043 | 1048 | if (result) { |
|
1044 | 1049 | r = PythonQtConv::PyObjToQVariant(result); |
|
1045 | 1050 | } else { |
@@ -1156,6 +1161,8 PythonQtPrivate::PythonQtPrivate() | |||
|
1156 | 1161 | _wrappedCB = NULL; |
|
1157 | 1162 | _currentClassInfoForClassWrapperCreation = NULL; |
|
1158 | 1163 | _profilingCB = NULL; |
|
1164 | _hadError = false; | |
|
1165 | _systemExitExceptionHandlerEnabled = false; | |
|
1159 | 1166 | } |
|
1160 | 1167 | |
|
1161 | 1168 | void PythonQtPrivate::setupSharedLibrarySuffixes() |
@@ -1252,11 +1259,77 void PythonQtPrivate::removeSignalEmitter(QObject* obj) | |||
|
1252 | 1259 | _signalReceivers.remove(obj); |
|
1253 | 1260 | } |
|
1254 | 1261 | |
|
1262 | namespace | |
|
1263 | { | |
|
1264 | //! adapted from python source file "pythonrun.c", function "handle_system_exit" | |
|
1265 | //! return the exitcode instead of calling "Py_Exit". | |
|
1266 | //! it gives the application an opportunity to properly terminate. | |
|
1267 | int custom_system_exit_exception_handler() | |
|
1268 | { | |
|
1269 | PyObject *exception, *value, *tb; | |
|
1270 | int exitcode = 0; | |
|
1271 | ||
|
1272 | // if (Py_InspectFlag) | |
|
1273 | // /* Don't exit if -i flag was given. This flag is set to 0 | |
|
1274 | // * when entering interactive mode for inspecting. */ | |
|
1275 | // return exitcode; | |
|
1276 | ||
|
1277 | PyErr_Fetch(&exception, &value, &tb); | |
|
1278 | if (Py_FlushLine()) | |
|
1279 | PyErr_Clear(); | |
|
1280 | fflush(stdout); | |
|
1281 | if (value == NULL || value == Py_None) | |
|
1282 | goto done; | |
|
1283 | if (PyExceptionInstance_Check(value)) { | |
|
1284 | /* The error code should be in the `code' attribute. */ | |
|
1285 | PyObject *code = PyObject_GetAttrString(value, "code"); | |
|
1286 | if (code) { | |
|
1287 | Py_DECREF(value); | |
|
1288 | value = code; | |
|
1289 | if (value == Py_None) | |
|
1290 | goto done; | |
|
1291 | } | |
|
1292 | /* If we failed to dig out the 'code' attribute, | |
|
1293 | just let the else clause below print the error. */ | |
|
1294 | } | |
|
1295 | if (PyInt_Check(value)) | |
|
1296 | exitcode = (int)PyInt_AsLong(value); | |
|
1297 | else { | |
|
1298 | PyObject *sys_stderr = PySys_GetObject(const_cast<char*>("stderr")); | |
|
1299 | if (sys_stderr != NULL && sys_stderr != Py_None) { | |
|
1300 | PyFile_WriteObject(value, sys_stderr, Py_PRINT_RAW); | |
|
1301 | } else { | |
|
1302 | PyObject_Print(value, stderr, Py_PRINT_RAW); | |
|
1303 | fflush(stderr); | |
|
1304 | } | |
|
1305 | PySys_WriteStderr("\n"); | |
|
1306 | exitcode = 1; | |
|
1307 | } | |
|
1308 | done: | |
|
1309 | /* Restore and clear the exception info, in order to properly decref | |
|
1310 | * the exception, value, and traceback. If we just exit instead, | |
|
1311 | * these leak, which confuses PYTHONDUMPREFS output, and may prevent | |
|
1312 | * some finalizers from running. | |
|
1313 | */ | |
|
1314 | PyErr_Restore(exception, value, tb); | |
|
1315 | PyErr_Clear(); | |
|
1316 | return exitcode; | |
|
1317 | //Py_Exit(exitcode); | |
|
1318 | } | |
|
1319 | } | |
|
1320 | ||
|
1255 | 1321 | bool PythonQt::handleError() |
|
1256 | 1322 | { |
|
1257 | 1323 | bool flag = false; |
|
1258 | 1324 | if (PyErr_Occurred()) { |
|
1259 | 1325 | |
|
1326 | if (_p->_systemExitExceptionHandlerEnabled && | |
|
1327 | PyErr_ExceptionMatches(PyExc_SystemExit)) { | |
|
1328 | int exitcode = custom_system_exit_exception_handler(); | |
|
1329 | emit PythonQt::self()->systemExitExceptionRaised(exitcode); | |
|
1330 | } | |
|
1331 | else | |
|
1332 | { | |
|
1260 | 1333 | // currently we just print the error and the stderr handler parses the errors |
|
1261 | 1334 | PyErr_Print(); |
|
1262 | 1335 | |
@@ -1272,11 +1345,33 bool PythonQt::handleError() | |||
|
1272 | 1345 | Py_XDECREF(ptraceback); |
|
1273 | 1346 | */ |
|
1274 | 1347 | PyErr_Clear(); |
|
1348 | } | |
|
1275 | 1349 | flag = true; |
|
1276 | 1350 | } |
|
1351 | _p->_hadError = flag; | |
|
1277 | 1352 | return flag; |
|
1278 | 1353 | } |
|
1279 | 1354 | |
|
1355 | bool PythonQt::hadError()const | |
|
1356 | { | |
|
1357 | return _p->_hadError; | |
|
1358 | } | |
|
1359 | ||
|
1360 | void PythonQt::clearError() | |
|
1361 | { | |
|
1362 | _p->_hadError = false; | |
|
1363 | } | |
|
1364 | ||
|
1365 | void PythonQt::setSystemExitExceptionHandlerEnabled(bool value) | |
|
1366 | { | |
|
1367 | _p->_systemExitExceptionHandlerEnabled = value; | |
|
1368 | } | |
|
1369 | ||
|
1370 | bool PythonQt::systemExitExceptionHandlerEnabled() const | |
|
1371 | { | |
|
1372 | return _p->_systemExitExceptionHandlerEnabled; | |
|
1373 | } | |
|
1374 | ||
|
1280 | 1375 | void PythonQt::addSysPath(const QString& path) |
|
1281 | 1376 | { |
|
1282 | 1377 | PythonQtObjectPtr sys; |
@@ -1602,6 +1697,7 PythonQtInstanceWrapper* PythonQtPrivate::findWrapperAndRemoveUnused(void* obj) | |||
|
1602 | 1697 | PythonQtObjectPtr PythonQtPrivate::createModule(const QString& name, PyObject* pycode) |
|
1603 | 1698 | { |
|
1604 | 1699 | PythonQtObjectPtr result; |
|
1700 | PythonQt::self()->clearError(); | |
|
1605 | 1701 | if (pycode) { |
|
1606 | 1702 | result.setNewRef(PyImport_ExecCodeModule((char*)name.toLatin1().data(), pycode)); |
|
1607 | 1703 | } else { |
@@ -473,17 +473,32 public: | |||
|
473 | 473 | //! get access to internal data (should not be used on the public API, but is used by some C functions) |
|
474 | 474 | static PythonQtPrivate* priv() { return _self->_p; } |
|
475 | 475 | |
|
476 | //! clear all NotFound entries on all class infos, to ensure that | |
|
477 | //! newly loaded wrappers can add methods even when the object was wrapped by PythonQt before the wrapper was loaded | |
|
478 | void clearNotFoundCachedMembers(); | |
|
479 | ||
|
476 | 480 | //! handle a python error, call this when a python function fails. If no error occurred, it returns false. |
|
477 | 481 | //! The error is currently just output to the python stderr, future version might implement better trace printing |
|
478 | 482 | bool handleError(); |
|
479 | 483 | |
|
480 | //! clear all NotFound entries on all class infos, to ensure that | |
|
481 | //! newly loaded wrappers can add methods even when the object was wrapped by PythonQt before the wrapper was loaded | |
|
482 | void clearNotFoundCachedMembers(); | |
|
484 | //! return \a true if \a handleError() has been called and an error occured. | |
|
485 | bool hadError()const; | |
|
486 | ||
|
487 | //! reset error flag. After calling this, hadError() will return false. | |
|
488 | //! \sa hadError() | |
|
489 | void clearError(); | |
|
490 | ||
|
491 | //! if set to true, the systemExitExceptionRaised signal will be emitted if exception SystemExit is caught | |
|
492 | //! \sa handleError() | |
|
493 | void setSystemExitExceptionHandlerEnabled(bool value); | |
|
483 | 494 | |
|
484 | //! set a callback that is called when a QObject with parent == NULL is wrapped by pythonqt | |
|
495 | //! return \a true if SystemExit exception is handled by PythonQt | |
|
496 | //! \sa setSystemExitExceptionHandlerEnabled() | |
|
497 | bool systemExitExceptionHandlerEnabled() const; | |
|
498 | ||
|
499 | //! set a callback that is called when a QObject with parent == NULL is wrapped by PythonQt | |
|
485 | 500 | void setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb); |
|
486 |
//! set a callback that is called when a QObject with parent == NULL is no longer wrapped by |
|
|
501 | //! set a callback that is called when a QObject with parent == NULL is no longer wrapped by PythonQt | |
|
487 | 502 | void setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb); |
|
488 | 503 | |
|
489 | 504 | //! call the callback if it is set |
@@ -510,6 +525,11 signals: | |||
|
510 | 525 | //! emitted when help() is called on a PythonQt object and \c ExternalHelp is enabled |
|
511 | 526 | void pythonHelpRequest(const QByteArray& cppClassName); |
|
512 | 527 | |
|
528 | //! emitted when both custom SystemExit exception handler is enabled and a SystemExit | |
|
529 | //! exception is raised. | |
|
530 | //! \sa setSystemExitExceptionHandlerEnabled(bool) | |
|
531 | void systemExitExceptionRaised(int exitCode); | |
|
532 | ||
|
513 | 533 | private: |
|
514 | 534 | void initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQtModuleName); |
|
515 | 535 | |
@@ -714,6 +734,9 private: | |||
|
714 | 734 | int _initFlags; |
|
715 | 735 | int _PythonQtObjectPtr_metaId; |
|
716 | 736 | |
|
737 | bool _hadError; | |
|
738 | bool _systemExitExceptionHandlerEnabled; | |
|
739 | ||
|
717 | 740 | friend class PythonQt; |
|
718 | 741 | }; |
|
719 | 742 |
@@ -45,6 +45,7 | |||
|
45 | 45 | #undef _DEBUG |
|
46 | 46 | #if defined(_MSC_VER) && _MSC_VER >= 1400 |
|
47 | 47 | #define _CRT_NOFORCE_MANIFEST 1 |
|
48 | #define _STL_NOFORCE_MANIFEST 1 | |
|
48 | 49 | #endif |
|
49 | 50 | #include <Python.h> |
|
50 | 51 | #define _DEBUG |
@@ -91,7 +91,11 static PyObject *PythonQtStdOutRedirect_flush(PyObject * /*self*/, PyObject * /* | |||
|
91 | 91 | return Py_BuildValue(""); |
|
92 | 92 | } |
|
93 | 93 | |
|
94 | ||
|
94 | static PyObject *PythonQtStdOutRedirect_isatty(PyObject * /*self*/, PyObject * /*args*/) | |
|
95 | { | |
|
96 | Py_INCREF(Py_False); | |
|
97 | return Py_False; | |
|
98 | } | |
|
95 | 99 | |
|
96 | 100 | static PyMethodDef PythonQtStdOutRedirect_methods[] = { |
|
97 | 101 | {"write", (PyCFunction)PythonQtStdOutRedirect_write, METH_VARARGS, |
@@ -99,6 +103,9 static PyMethodDef PythonQtStdOutRedirect_methods[] = { | |||
|
99 | 103 | {"flush", (PyCFunction)PythonQtStdOutRedirect_flush, METH_VARARGS, |
|
100 | 104 | "flush the output, currently not implemented but needed for logging framework" |
|
101 | 105 | }, |
|
106 | {"isatty", (PyCFunction)PythonQtStdOutRedirect_isatty, METH_NOARGS, | |
|
107 | "return False since this object is not a tty-like device. Needed for logging framework" | |
|
108 | }, | |
|
102 | 109 | {NULL, NULL, 0 , NULL} /* sentinel */ |
|
103 | 110 | }; |
|
104 | 111 |
General Comments 0
You need to be logged in to leave comments.
Login now