2222
2323#include " qgsapplication.h"
2424#include " qgslogger.h"
25+ #include " qgsmessageoutput.h"
2526
2627#include < QMessageBox>
2728#include < QStringList>
@@ -51,32 +52,25 @@ void QgsPythonUtils::initPython(QgisInterface* interface)
5152 runString (" sys.path = [\" " + homePluginsPath () + " \" , \" " + pythonPath () + " \" , \" " + pluginsPath () + " \" ] + sys.path" );
5253
5354 // import SIP
54- if (!runString (" from sip import wrapinstance, unwrapinstance" ))
55+ if (!runString (" from sip import wrapinstance, unwrapinstance" ,
56+ QObject::tr (" Couldn't load SIP module." ) + " \n " + QObject::tr (" Python support will be disabled." )))
5557 {
56- QMessageBox::warning (0 , QObject::tr (" Python error" ),
57- QObject::tr (" Couldn't load SIP module.\n Python support will be disabled." ));
58- PyErr_Clear ();
5958 exitPython ();
6059 return ;
6160 }
6261
6362 // import Qt bindings
64- if (!runString (" from PyQt4 import QtCore, QtGui" ))
63+ if (!runString (" from PyQt4 import QtCore, QtGui" ,
64+ QObject::tr (" Couldn't load PyQt4." ) + " \n " + QObject::tr (" Python support will be disabled." )))
6565 {
66- QMessageBox::warning (0 , QObject::tr (" Python error" ),
67- QObject::tr (" Couldn't load PyQt bindings.\n Python support will be disabled." ));
68- PyErr_Clear ();
6966 exitPython ();
7067 return ;
7168 }
7269
7370 // import QGIS bindings
74- if (! runString ( " from qgis.core import * " ) ||
75- !runString (" from qgis.gui import *" ))
71+ QString error_msg = QObject::tr ( " Couldn't load PyQGIS. " ) + " \n " + QObject::tr ( " Python support will be disabled. " );
72+ if (! runString ( " from qgis.core import * " , error_msg) || !runString (" from qgis.gui import *" , error_msg ))
7673 {
77- QMessageBox::warning (0 , QObject::tr (" Python error" ),
78- QObject::tr (" Couldn't load QGIS bindings.\n Python support will be disabled." ));
79- PyErr_Clear ();
8074 exitPython ();
8175 return ;
8276 }
@@ -162,13 +156,43 @@ void QgsPythonUtils::uninstallConsoleHooks()
162156}
163157
164158
165- bool QgsPythonUtils::runString (const QString& command)
159+ bool QgsPythonUtils::runStringUnsafe (const QString& command)
166160{
167161 PyRun_String (command.toLocal8Bit ().data (), Py_single_input, mMainDict , mMainDict );
168-
169162 return (PyErr_Occurred () == 0 );
170163}
171164
165+ bool QgsPythonUtils::runString (const QString& command, QString msgOnError)
166+ {
167+ bool res = runStringUnsafe (command);
168+ if (res)
169+ return true ;
170+
171+ // an error occured
172+ // fetch error details and show it
173+ QString err_type, err_value;
174+ getError (err_type, err_value);
175+
176+ if (msgOnError.isEmpty ())
177+ {
178+ // use some default message if custom hasn't been specified
179+ msgOnError = QObject::tr (" An error occured during execution of following code:" ) + " \n <tt>" + command + " </tt>" ;
180+ }
181+ msgOnError.replace (" \n " , " <br>" );
182+ QString str = msgOnError + " <br><br>" + QObject::tr (" Error details:" ) + " <br>"
183+ + QObject::tr (" Type:" ) + " <b>" + err_type + " </b><br>"
184+ + QObject::tr (" Value:" ) + " <b>" + err_value + " </b>" ;
185+
186+ // TODO: show sys.path, local variables, traceback
187+
188+ QgsMessageOutput* msg = QgsMessageOutput::createMessageOutput ();
189+ msg->setTitle (QObject::tr (" Python error" ));
190+ msg->setMessage (str, QgsMessageOutput::MessageHtml);
191+ msg->showMessage ();
192+
193+ return res;
194+ }
195+
172196
173197QString QgsPythonUtils::getTypeAsString (PyObject* obj)
174198{
@@ -207,7 +231,7 @@ bool QgsPythonUtils::getError(QString& errorClassName, QString& errorText)
207231 PyObject* err_value;
208232 PyObject* err_tb;
209233
210- // get the exception information
234+ // get the exception information and clear error
211235 PyErr_Fetch (&err_type, &err_value, &err_tb);
212236
213237 // get exception's class name
@@ -223,8 +247,10 @@ bool QgsPythonUtils::getError(QString& errorClassName, QString& errorText)
223247 else
224248 errorText.clear ();
225249
226- // clear exception
227- PyErr_Clear ();
250+ // cleanup
251+ Py_XDECREF (err_type);
252+ Py_XDECREF (err_value);
253+ Py_XDECREF (err_tb);
228254
229255 return true ;
230256}
@@ -373,29 +399,16 @@ bool QgsPythonUtils::startPlugin(QString packageName)
373399{
374400 QString pluginPythonVar = " plugins['" + packageName + " ']" ;
375401
376- // create an instance of the plugin
377- if (!runString (pluginPythonVar + " = " + packageName + " .classFactory(iface)" ))
378- {
379- PyErr_Print (); // just print to console
380- PyErr_Clear ();
402+ QString errMsg = QObject::tr (" Couldn't load plugin " ) + packageName;
381403
382- QMessageBox::warning ( 0 , QObject::tr ( " Python error " ),
383- QObject::tr ( " Couldn't load plugin " ) + packageName +
384- QObject::tr (" due an error when calling its classFactory() method" ));
404+ // create an instance of the plugin
405+ if (! runString (pluginPythonVar + " = " + packageName + " .classFactory(iface) " ,
406+ errMsg + QObject::tr (" due an error when calling its classFactory() method" )))
385407 return false ;
386- }
387408
388409 // initGui
389- if (!runString (pluginPythonVar + " .initGui()" ))
390- {
391- PyErr_Print (); // just print to console
392- PyErr_Clear ();
393-
394- QMessageBox::warning (0 , QObject::tr (" Python error" ),
395- QObject::tr (" Couldn't load plugin " ) + packageName +
396- QObject::tr (" due an error when calling its initGui() method" ));
410+ if (!runString (pluginPythonVar + " .initGui()" , errMsg + QObject::tr (" due an error when calling its initGui() method" )))
397411 return false ;
398- }
399412
400413 return true ;
401414}
@@ -406,16 +419,12 @@ bool QgsPythonUtils::unloadPlugin(QString packageName)
406419 // unload and delete plugin!
407420 QString varName = " plugins['" + packageName + " ']" ;
408421
409- if (!runString (varName + " .unload()" ) ||
410- !runString (" del " + varName))
411- {
412- PyErr_Print (); // just print to console
413- PyErr_Clear ();
414-
415- QMessageBox::warning (0 , QObject::tr (" Python error" ),
416- QObject::tr (" Error while unloading plugin " ) + packageName);
422+ QString errMsg = QObject::tr (" Error while unloading plugin " ) + packageName;
423+
424+ if (!runString (varName + " .unload()" , errMsg))
425+ return false ;
426+ if (!runString (" del " + varName, errMsg))
417427 return false ;
418- }
419428
420429 return true ;
421430}
0 commit comments