##// END OF EJS Templates
florianlink -
r201:4443fddf8142
parent child
Show More
@@ -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,31 +1259,119 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
1260 // currently we just print the error and the stderr handler parses the errors
1261 PyErr_Print();
1262
1263 /*
1264 // EXTRA: the format of the ptype and ptraceback is not really documented, so I use PyErr_Print() above
1265 PyObject *ptype;
1266 PyObject *pvalue;
1267 PyObject *ptraceback;
1268 PyErr_Fetch( &ptype, &pvalue, &ptraceback);
1269
1270 Py_XDECREF(ptype);
1271 Py_XDECREF(pvalue);
1272 Py_XDECREF(ptraceback);
1273 */
1274 PyErr_Clear();
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 {
1333 // currently we just print the error and the stderr handler parses the errors
1334 PyErr_Print();
1335
1336 /*
1337 // EXTRA: the format of the ptype and ptraceback is not really documented, so I use PyErr_Print() above
1338 PyObject *ptype;
1339 PyObject *pvalue;
1340 PyObject *ptraceback;
1341 PyErr_Fetch( &ptype, &pvalue, &ptraceback);
1342
1343 Py_XDECREF(ptype);
1344 Py_XDECREF(pvalue);
1345 Py_XDECREF(ptraceback);
1346 */
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 {
@@ -1793,4 +1889,4 PyObject* PythonQtPrivate::wrapMemoryAsBuffer( void* data, Py_ssize_t size )
1793 1889 {
1794 1890 // P3K port needed later on!
1795 1891 return PyBuffer_FromReadWriteMemory(data, size);
1796 } No newline at end of file
1892 }
@@ -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 pythonqt
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