@@ -687,6 +687,7 PythonQtObjectPtr PythonQt::importModule(const QString& name) | |||||
687 |
|
687 | |||
688 | QVariant PythonQt::evalCode(PyObject* object, PyObject* pycode) { |
|
688 | QVariant PythonQt::evalCode(PyObject* object, PyObject* pycode) { | |
689 | QVariant result; |
|
689 | QVariant result; | |
|
690 | clearError(); | |||
690 | if (pycode) { |
|
691 | if (pycode) { | |
691 | PyObject* dict = NULL; |
|
692 | PyObject* dict = NULL; | |
692 | PyObject* globals = NULL; |
|
693 | PyObject* globals = NULL; | |
@@ -721,6 +722,7 QVariant PythonQt::evalScript(PyObject* object, const QString& script, int start | |||||
721 | QVariant result; |
|
722 | QVariant result; | |
722 | PythonQtObjectPtr p; |
|
723 | PythonQtObjectPtr p; | |
723 | PyObject* dict = NULL; |
|
724 | PyObject* dict = NULL; | |
|
725 | clearError(); | |||
724 | if (PyModule_Check(object)) { |
|
726 | if (PyModule_Check(object)) { | |
725 | dict = PyModule_GetDict(object); |
|
727 | dict = PyModule_GetDict(object); | |
726 | } else if (PyDict_Check(object)) { |
|
728 | } else if (PyDict_Check(object)) { | |
@@ -740,6 +742,7 QVariant PythonQt::evalScript(PyObject* object, const QString& script, int start | |||||
740 | void PythonQt::evalFile(PyObject* module, const QString& filename) |
|
742 | void PythonQt::evalFile(PyObject* module, const QString& filename) | |
741 | { |
|
743 | { | |
742 | PythonQtObjectPtr code = parseFile(filename); |
|
744 | PythonQtObjectPtr code = parseFile(filename); | |
|
745 | clearError(); | |||
743 | if (code) { |
|
746 | if (code) { | |
744 | evalCode(module, code); |
|
747 | evalCode(module, code); | |
745 | } else { |
|
748 | } else { | |
@@ -751,6 +754,7 PythonQtObjectPtr PythonQt::parseFile(const QString& filename) | |||||
751 | { |
|
754 | { | |
752 | PythonQtObjectPtr p; |
|
755 | PythonQtObjectPtr p; | |
753 | p.setNewRef(PythonQtImport::getCodeFromPyc(filename)); |
|
756 | p.setNewRef(PythonQtImport::getCodeFromPyc(filename)); | |
|
757 | clearError(); | |||
754 | if (!p) { |
|
758 | if (!p) { | |
755 | handleError(); |
|
759 | handleError(); | |
756 | } |
|
760 | } | |
@@ -1040,6 +1044,7 QVariant PythonQt::call(PyObject* callable, const QVariantList& args, const QVar | |||||
1040 | QVariant r; |
|
1044 | QVariant r; | |
1041 | PythonQtObjectPtr result; |
|
1045 | PythonQtObjectPtr result; | |
1042 | result.setNewRef(callAndReturnPyObject(callable, args, kwargs)); |
|
1046 | result.setNewRef(callAndReturnPyObject(callable, args, kwargs)); | |
|
1047 | clearError(); | |||
1043 | if (result) { |
|
1048 | if (result) { | |
1044 | r = PythonQtConv::PyObjToQVariant(result); |
|
1049 | r = PythonQtConv::PyObjToQVariant(result); | |
1045 | } else { |
|
1050 | } else { | |
@@ -1156,6 +1161,8 PythonQtPrivate::PythonQtPrivate() | |||||
1156 | _wrappedCB = NULL; |
|
1161 | _wrappedCB = NULL; | |
1157 | _currentClassInfoForClassWrapperCreation = NULL; |
|
1162 | _currentClassInfoForClassWrapperCreation = NULL; | |
1158 | _profilingCB = NULL; |
|
1163 | _profilingCB = NULL; | |
|
1164 | _hadError = false; | |||
|
1165 | _systemExitExceptionHandlerEnabled = false; | |||
1159 | } |
|
1166 | } | |
1160 |
|
1167 | |||
1161 | void PythonQtPrivate::setupSharedLibrarySuffixes() |
|
1168 | void PythonQtPrivate::setupSharedLibrarySuffixes() | |
@@ -1252,11 +1259,77 void PythonQtPrivate::removeSignalEmitter(QObject* obj) | |||||
1252 | _signalReceivers.remove(obj); |
|
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 | bool PythonQt::handleError() |
|
1321 | bool PythonQt::handleError() | |
1256 | { |
|
1322 | { | |
1257 | bool flag = false; |
|
1323 | bool flag = false; | |
1258 | if (PyErr_Occurred()) { |
|
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 | // currently we just print the error and the stderr handler parses the errors |
|
1333 | // currently we just print the error and the stderr handler parses the errors | |
1261 | PyErr_Print(); |
|
1334 | PyErr_Print(); | |
1262 |
|
1335 | |||
@@ -1272,11 +1345,33 bool PythonQt::handleError() | |||||
1272 | Py_XDECREF(ptraceback); |
|
1345 | Py_XDECREF(ptraceback); | |
1273 | */ |
|
1346 | */ | |
1274 | PyErr_Clear(); |
|
1347 | PyErr_Clear(); | |
|
1348 | } | |||
1275 | flag = true; |
|
1349 | flag = true; | |
1276 | } |
|
1350 | } | |
|
1351 | _p->_hadError = flag; | |||
1277 | return flag; |
|
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 | void PythonQt::addSysPath(const QString& path) |
|
1375 | void PythonQt::addSysPath(const QString& path) | |
1281 | { |
|
1376 | { | |
1282 | PythonQtObjectPtr sys; |
|
1377 | PythonQtObjectPtr sys; | |
@@ -1602,6 +1697,7 PythonQtInstanceWrapper* PythonQtPrivate::findWrapperAndRemoveUnused(void* obj) | |||||
1602 | PythonQtObjectPtr PythonQtPrivate::createModule(const QString& name, PyObject* pycode) |
|
1697 | PythonQtObjectPtr PythonQtPrivate::createModule(const QString& name, PyObject* pycode) | |
1603 | { |
|
1698 | { | |
1604 | PythonQtObjectPtr result; |
|
1699 | PythonQtObjectPtr result; | |
|
1700 | PythonQt::self()->clearError(); | |||
1605 | if (pycode) { |
|
1701 | if (pycode) { | |
1606 | result.setNewRef(PyImport_ExecCodeModule((char*)name.toLatin1().data(), pycode)); |
|
1702 | result.setNewRef(PyImport_ExecCodeModule((char*)name.toLatin1().data(), pycode)); | |
1607 | } else { |
|
1703 | } else { |
@@ -473,17 +473,32 public: | |||||
473 | //! get access to internal data (should not be used on the public API, but is used by some C functions) |
|
473 | //! get access to internal data (should not be used on the public API, but is used by some C functions) | |
474 | static PythonQtPrivate* priv() { return _self->_p; } |
|
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 | //! handle a python error, call this when a python function fails. If no error occurred, it returns false. |
|
480 | //! handle a python error, call this when a python function fails. If no error occurred, it returns false. | |
477 | //! The error is currently just output to the python stderr, future version might implement better trace printing |
|
481 | //! The error is currently just output to the python stderr, future version might implement better trace printing | |
478 | bool handleError(); |
|
482 | bool handleError(); | |
479 |
|
483 | |||
480 | //! clear all NotFound entries on all class infos, to ensure that |
|
484 | //! return \a true if \a handleError() has been called and an error occured. | |
481 | //! newly loaded wrappers can add methods even when the object was wrapped by PythonQt before the wrapper was loaded |
|
485 | bool hadError()const; | |
482 | void clearNotFoundCachedMembers(); |
|
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 | void setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb); |
|
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 | void setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb); |
|
502 | void setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb); | |
488 |
|
503 | |||
489 | //! call the callback if it is set |
|
504 | //! call the callback if it is set | |
@@ -510,6 +525,11 signals: | |||||
510 | //! emitted when help() is called on a PythonQt object and \c ExternalHelp is enabled |
|
525 | //! emitted when help() is called on a PythonQt object and \c ExternalHelp is enabled | |
511 | void pythonHelpRequest(const QByteArray& cppClassName); |
|
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 | private: |
|
533 | private: | |
514 | void initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQtModuleName); |
|
534 | void initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQtModuleName); | |
515 |
|
535 | |||
@@ -714,6 +734,9 private: | |||||
714 | int _initFlags; |
|
734 | int _initFlags; | |
715 | int _PythonQtObjectPtr_metaId; |
|
735 | int _PythonQtObjectPtr_metaId; | |
716 |
|
736 | |||
|
737 | bool _hadError; | |||
|
738 | bool _systemExitExceptionHandlerEnabled; | |||
|
739 | ||||
717 | friend class PythonQt; |
|
740 | friend class PythonQt; | |
718 | }; |
|
741 | }; | |
719 |
|
742 |
@@ -45,6 +45,7 | |||||
45 | #undef _DEBUG |
|
45 | #undef _DEBUG | |
46 | #if defined(_MSC_VER) && _MSC_VER >= 1400 |
|
46 | #if defined(_MSC_VER) && _MSC_VER >= 1400 | |
47 | #define _CRT_NOFORCE_MANIFEST 1 |
|
47 | #define _CRT_NOFORCE_MANIFEST 1 | |
|
48 | #define _STL_NOFORCE_MANIFEST 1 | |||
48 | #endif |
|
49 | #endif | |
49 | #include <Python.h> |
|
50 | #include <Python.h> | |
50 | #define _DEBUG |
|
51 | #define _DEBUG |
@@ -91,7 +91,11 static PyObject *PythonQtStdOutRedirect_flush(PyObject * /*self*/, PyObject * /* | |||||
91 | return Py_BuildValue(""); |
|
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 | static PyMethodDef PythonQtStdOutRedirect_methods[] = { |
|
100 | static PyMethodDef PythonQtStdOutRedirect_methods[] = { | |
97 | {"write", (PyCFunction)PythonQtStdOutRedirect_write, METH_VARARGS, |
|
101 | {"write", (PyCFunction)PythonQtStdOutRedirect_write, METH_VARARGS, | |
@@ -99,6 +103,9 static PyMethodDef PythonQtStdOutRedirect_methods[] = { | |||||
99 | {"flush", (PyCFunction)PythonQtStdOutRedirect_flush, METH_VARARGS, |
|
103 | {"flush", (PyCFunction)PythonQtStdOutRedirect_flush, METH_VARARGS, | |
100 | "flush the output, currently not implemented but needed for logging framework" |
|
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 | {NULL, NULL, 0 , NULL} /* sentinel */ |
|
109 | {NULL, NULL, 0 , NULL} /* sentinel */ | |
103 | }; |
|
110 | }; | |
104 |
|
111 |
General Comments 0
You need to be logged in to leave comments.
Login now