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

svn_qgis at osgeo.org svn_qgis at osgeo.org
Wed May 21 17:09:38 EDT 2008


Author: wonder
Date: 2008-05-21 17:09:37 -0400 (Wed, 21 May 2008)
New Revision: 8491

Modified:
   trunk/qgis/src/app/qgspythondialog.cpp
   trunk/qgis/src/app/qgspythonutils.cpp
   trunk/qgis/src/app/qgspythonutils.h
Log:
better handling of python errors raised during initialization.


Modified: trunk/qgis/src/app/qgspythondialog.cpp
===================================================================
--- trunk/qgis/src/app/qgspythondialog.cpp	2008-05-21 17:48:06 UTC (rev 8490)
+++ trunk/qgis/src/app/qgspythondialog.cpp	2008-05-21 21:09:37 UTC (rev 8491)
@@ -43,7 +43,7 @@
   
   // when using Py_single_input the return value will be always null
   // we're using custom hooks for output and exceptions to show output in console
-  if (QgsPythonUtils::runString(command))
+  if (QgsPythonUtils::runStringUnsafe(command))
   {
     QgsPythonUtils::evalString("sys.stdout.data", output);
     QgsPythonUtils::runString("sys.stdout.data = ''");

Modified: trunk/qgis/src/app/qgspythonutils.cpp
===================================================================
--- trunk/qgis/src/app/qgspythonutils.cpp	2008-05-21 17:48:06 UTC (rev 8490)
+++ trunk/qgis/src/app/qgspythonutils.cpp	2008-05-21 21:09:37 UTC (rev 8491)
@@ -22,6 +22,7 @@
 
 #include "qgsapplication.h"
 #include "qgslogger.h"
+#include "qgsmessageoutput.h"
 
 #include <QMessageBox>
 #include <QStringList>
@@ -51,32 +52,25 @@
   runString("sys.path = [\"" + homePluginsPath()  + "\", \"" + pythonPath() + "\", \"" + pluginsPath() + "\"] + sys.path");
 
   // import SIP
-  if (!runString("from sip import wrapinstance, unwrapinstance"))
+  if (!runString("from sip import wrapinstance, unwrapinstance",
+       QObject::tr("Couldn't load SIP module.") + "\n" + QObject::tr("Python support will be disabled.")))
   {
-    QMessageBox::warning(0, QObject::tr("Python error"),
-                         QObject::tr("Couldn't load SIP module.\nPython support will be disabled."));
-    PyErr_Clear();
     exitPython();
     return;
   }
   
   // import Qt bindings
-  if (!runString("from PyQt4 import QtCore, QtGui"))
+  if (!runString("from PyQt4 import QtCore, QtGui",
+       QObject::tr("Couldn't load PyQt4.") + "\n" + QObject::tr("Python support will be disabled.")))
   {
-    QMessageBox::warning(0, QObject::tr("Python error"),
-                         QObject::tr("Couldn't load PyQt bindings.\nPython support will be disabled."));
-    PyErr_Clear();
     exitPython();
     return;
   }
   
   // import QGIS bindings
-  if (!runString("from qgis.core import *") ||
-      !runString("from qgis.gui import *"))
+  QString error_msg = QObject::tr("Couldn't load PyQGIS.") + "\n" + QObject::tr("Python support will be disabled.");
+  if (!runString("from qgis.core import *", error_msg) || !runString("from qgis.gui import *", error_msg))
   {
-    QMessageBox::warning(0, QObject::tr("Python error"),
-                         QObject::tr("Couldn't load QGIS bindings.\nPython support will be disabled."));
-    PyErr_Clear();
     exitPython();
     return;
   }
@@ -162,14 +156,44 @@
 }
 
 
-bool QgsPythonUtils::runString(const QString& command)
+bool QgsPythonUtils::runStringUnsafe(const QString& command)
 {
   PyRun_String(command.toLocal8Bit().data(), Py_single_input, mMainDict, mMainDict);
-  
   return (PyErr_Occurred() == 0);
 }
 
+bool QgsPythonUtils::runString(const QString& command, QString msgOnError)
+{
+  bool res = runStringUnsafe(command);
+  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
+  
+  QgsMessageOutput* msg = QgsMessageOutput::createMessageOutput();
+  msg->setTitle(QObject::tr("Python error"));
+  msg->setMessage(str, QgsMessageOutput::MessageHtml);
+  msg->showMessage();
+  
+  return res;
+}
 
+
 QString QgsPythonUtils::getTypeAsString(PyObject* obj)
 {
   if (obj == NULL)
@@ -207,7 +231,7 @@
   PyObject* err_value;
   PyObject* err_tb;
   
-  // get the exception information
+  // get the exception information and clear error
   PyErr_Fetch(&err_type, &err_value, &err_tb);
   
   // get exception's class name
@@ -223,8 +247,10 @@
   else
     errorText.clear();
   
-  // clear exception
-  PyErr_Clear();
+  // cleanup
+  Py_XDECREF(err_type);
+  Py_XDECREF(err_value);
+  Py_XDECREF(err_tb);
   
   return true;
 }
@@ -373,29 +399,16 @@
 {
   QString pluginPythonVar = "plugins['" + packageName + "']";
   
+  QString errMsg = QObject::tr("Couldn't load plugin ") + packageName;
+    
   // create an instance of the plugin
-  if (!runString(pluginPythonVar + " = " + packageName + ".classFactory(iface)"))
-  {
-    PyErr_Print(); // just print to console
-    PyErr_Clear();
-    
-    QMessageBox::warning(0, QObject::tr("Python error"),
-                         QObject::tr("Couldn't load plugin ") + packageName +
-                         QObject::tr(" due an error when calling its classFactory() method"));
+  if (!runString(pluginPythonVar + " = " + packageName + ".classFactory(iface)",
+                 errMsg + QObject::tr(" due an error when calling its classFactory() method")))
     return false;
-  }
   
   // initGui
-  if (!runString(pluginPythonVar + ".initGui()"))
-  {
-    PyErr_Print(); // just print to console
-    PyErr_Clear();
-    
-    QMessageBox::warning(0, QObject::tr("Python error"),
-                         QObject::tr("Couldn't load plugin ") + packageName +
-                         QObject::tr(" due an error when calling its initGui() method"));
+  if (!runString(pluginPythonVar + ".initGui()", errMsg + QObject::tr(" due an error when calling its initGui() method")))
     return false;
-  }
   
   return true;
 }
@@ -406,16 +419,12 @@
   // unload and delete plugin!
   QString varName = "plugins['" + packageName + "']";
   
-  if (!runString(varName + ".unload()") ||
-      !runString("del " + varName))
-  {
-    PyErr_Print(); // just print to console
-    PyErr_Clear();
-    
-    QMessageBox::warning(0, QObject::tr("Python error"),
-                         QObject::tr("Error while unloading plugin ") + packageName);
+  QString errMsg = QObject::tr("Error while unloading plugin ") + packageName;
+  
+  if (!runString(varName + ".unload()", errMsg))
     return false;
-  }
+  if (!runString("del " + varName, errMsg))
+    return false;
   
   return true;
 }

Modified: trunk/qgis/src/app/qgspythonutils.h
===================================================================
--- trunk/qgis/src/app/qgspythonutils.h	2008-05-21 17:48:06 UTC (rev 8490)
+++ trunk/qgis/src/app/qgspythonutils.h	2008-05-21 21:09:37 UTC (rev 8491)
@@ -53,9 +53,14 @@
     
     //! run a statement (wrapper for PyRun_String)
     //! this command is more advanced as enables error checking etc.
+    //! when an exception is raised, it shows dialog with exception details
     //! @return true if no error occured
-    static bool runString(const QString& command);
+    static bool runString(const QString& command, QString msgOnError = QString());
     
+    //! run a statement, error reporting is not done
+    //! @return true if no error occured
+    static bool runStringUnsafe(const QString& command);
+    
     static bool evalString(const QString& command, QString& result);
     
     //! @return object's type name as a string



More information about the QGIS-commit mailing list