[QGIS Commit] r8496 - trunk/qgis/src/app

svn_qgis at osgeo.org svn_qgis at osgeo.org
Fri May 23 11:12:53 EDT 2008


Author: wonder
Date: 2008-05-23 11:12:53 -0400 (Fri, 23 May 2008)
New Revision: 8496

Modified:
   trunk/qgis/src/app/qgspythonutils.cpp
   trunk/qgis/src/app/qgspythonutils.h
Log:
Even better python errors handling: now displaying traceback, python version and python path.


Modified: trunk/qgis/src/app/qgspythonutils.cpp
===================================================================
--- trunk/qgis/src/app/qgspythonutils.cpp	2008-05-23 07:59:45 UTC (rev 8495)
+++ trunk/qgis/src/app/qgspythonutils.cpp	2008-05-23 15:12:53 UTC (rev 8496)
@@ -44,9 +44,11 @@
   mMainModule = PyImport_AddModule("__main__"); // borrowed reference
   mMainDict = PyModule_GetDict(mMainModule); // borrowed reference
   
-  // import sys module
-  runString("import sys");
+  runString("import sys"); // import sys module (for display / exception hooks)
+  runString("import traceback"); // for formatting stack traces
+  runString("import __main__"); // to access explicitly global variables
   
+  
   // expect that bindings are installed locally, so add the path to modules
   // also add path to plugins
   runString("sys.path = [\"" + homePluginsPath()  + "\", \"" + pythonPath() + "\", \"" + pluginsPath() + "\"] + sys.path");
@@ -75,23 +77,22 @@
     return;
   }
   
-  runString("import __main__");
-  runString("import traceback"); // for formatting stack traces
-  
   // hook that will show information and traceback in message box
   runString(
       "def qgis_except_hook_msg(type, value, tb, msg):\n"
       "  lst = traceback.format_exception(type, value, tb)\n"
-      "  if msg == None: msg = 'An error has occured while executing Python code:'\n"
-      "  str = '<font color=\"red\">'+msg+'</font><br><br>'\n"
+      "  if msg == None: msg = '" + QObject::tr("An error has occured while executing Python code:") + "'\n"
+      "  txt = '<font color=\"red\">'+msg+'</font><br><br>'\n"
       "  for s in lst:\n"
-      "    str += s\n"
-      "  str = str.replace('\\n', '<br>')\n"
-      "  str = str.replace('  ', '&nbsp;')\n" // preserve whitespaces for nicer output
+      "    txt += s\n"
+      "  txt += '<br>" + QObject::tr("Python version:") + "<br>' + sys.version + '<br><br>'\n"
+      "  txt += '"+QObject::tr("Python path:") + "' + str(sys.path)\n"
+      "  txt = txt.replace('\\n', '<br>')\n"
+      "  txt = txt.replace('  ', '&nbsp; ')\n" // preserve whitespaces for nicer output
       "  \n"
       "  msg = QgsMessageOutput.createMessageOutput()\n"
-      "  msg.setTitle('Error')\n"
-      "  msg.setMessage(str, QgsMessageOutput.MessageHtml)\n"
+      "  msg.setTitle('" + QObject::tr("Python error") + "')\n"
+      "  msg.setMessage(txt, QgsMessageOutput.MessageHtml)\n"
       "  msg.showMessage()\n");
   runString(
       "def qgis_except_hook(type, value, tb):\n"
@@ -168,23 +169,22 @@
   if (res)
     return true;
     
-  // an error occured
-  // fetch error details and show it
-  QString err_type, err_value;
-  getError(err_type, err_value);
-  
   if (msgOnError.isEmpty())
   {
     // use some default message if custom hasn't been specified
     msgOnError = QObject::tr("An error occured during execution of following code:") + "\n<tt>" + command + "</tt>";
   }
-  msgOnError.replace("\n", "<br>");
-  QString str = msgOnError + "<br><br>" + QObject::tr("Error details:") + "<br>"
-      + QObject::tr("Type:")  + " <b>" + err_type + "</b><br>"
-      + QObject::tr("Value:") + " <b>" + err_value + "</b>";
   
-  // TODO: show sys.path, local variables, traceback
+  QString traceback = getTraceback();
+  QString path, version;
+  evalString("str(sys.path)", path);
+  evalString("sys.version", version);
   
+  QString str = "<font color=\"red\">"+ msgOnError + "</font><br><br>" + traceback + "<br>" +
+      QObject::tr("Python version:") + "<br>" + version + "<br><br>" +
+      QObject::tr("Python path:") + "<br>" + path;
+  str.replace("\n","<br>").replace("  ", "&nbsp; ");
+  
   QgsMessageOutput* msg = QgsMessageOutput::createMessageOutput();
   msg->setTitle(QObject::tr("Python error"));
   msg->setMessage(str, QgsMessageOutput::MessageHtml);
@@ -194,6 +194,78 @@
 }
 
 
+QString QgsPythonUtils::getTraceback()
+{
+#define TRACEBACK_FETCH_ERROR(what) {errMsg = what; goto done;}
+
+
+    QString errMsg;
+    QString result;
+
+    PyObject *modStringIO = NULL;
+    PyObject *modTB = NULL;
+    PyObject *obStringIO = NULL;
+    PyObject *obResult = NULL;
+
+    PyObject *type, *value, *traceback;
+
+    PyErr_Fetch(&type, &value, &traceback);
+    PyErr_NormalizeException(&type, &value, &traceback);
+        
+    modStringIO = PyImport_ImportModule("cStringIO");
+    if (modStringIO==NULL)
+      TRACEBACK_FETCH_ERROR("can't import cStringIO");
+
+    obStringIO = PyObject_CallMethod(modStringIO, (char*) "StringIO", NULL);
+
+    /* Construct a cStringIO object */
+    if (obStringIO==NULL)
+      TRACEBACK_FETCH_ERROR("cStringIO.StringIO() failed");
+
+    modTB = PyImport_ImportModule("traceback");
+    if (modTB==NULL)
+      TRACEBACK_FETCH_ERROR("can't import traceback");
+
+    obResult = PyObject_CallMethod(modTB, (char*) "print_exception",
+                                   (char*) "OOOOO",
+                                   type, value ? value : Py_None,
+                                   traceback ? traceback : Py_None,
+                                   Py_None,
+                                   obStringIO);
+                                    
+    if (obResult==NULL) 
+      TRACEBACK_FETCH_ERROR("traceback.print_exception() failed");
+    Py_DECREF(obResult);
+
+    obResult = PyObject_CallMethod(obStringIO, (char*) "getvalue", NULL);
+    if (obResult==NULL) 
+      TRACEBACK_FETCH_ERROR("getvalue() failed.");
+
+    /* And it should be a string all ready to go - duplicate it. */
+    if (!PyString_Check(obResult))
+      TRACEBACK_FETCH_ERROR("getvalue() did not return a string");
+
+    result = PyString_AsString(obResult);
+    
+done:
+        
+  // All finished - first see if we encountered an error
+  if (result.isEmpty() && !errMsg.isEmpty())
+  {
+    result = errMsg;
+  }
+
+  Py_XDECREF(modStringIO);
+  Py_XDECREF(modTB);
+  Py_XDECREF(obStringIO);
+  Py_XDECREF(obResult);
+  Py_XDECREF(value);
+  Py_XDECREF(traceback);
+  Py_XDECREF(type);
+
+  return result;
+}
+
 QString QgsPythonUtils::getTypeAsString(PyObject* obj)
 {
   if (obj == NULL)

Modified: trunk/qgis/src/app/qgspythonutils.h
===================================================================
--- trunk/qgis/src/app/qgspythonutils.h	2008-05-23 07:59:45 UTC (rev 8495)
+++ trunk/qgis/src/app/qgspythonutils.h	2008-05-23 15:12:53 UTC (rev 8496)
@@ -114,7 +114,8 @@
     
     static void installErrorHook();
 
-    
+    static QString getTraceback();
+
     //! path where 
     static QString mPluginsPath;
     



More information about the QGIS-commit mailing list