##// END OF EJS Templates
florianlink -
r201:4443fddf8142
parent child
Show More
@@ -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 pythonqt
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