Skip to content

Commit

Permalink
- improved error handling when loading python plugins
Browse files Browse the repository at this point in the history
- redirection of output to python console, i.e. print command works


git-svn-id: http://svn.osgeo.org/qgis/trunk@6767 c8812cc2-4d05-0410-92ff-de0c093fc19c
  • Loading branch information
wonder committed Mar 4, 2007
1 parent d6a1948 commit 0f1f6a0
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 35 deletions.
15 changes: 11 additions & 4 deletions src/app/qgisapp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1531,6 +1531,7 @@ void QgisApp::restoreSessionPlugins(QString thePluginDirString)
}

#ifdef HAVE_PYTHON
QString pluginName, description, version;

if (QgsPythonUtils::isEnabled())
{
Expand All @@ -1544,12 +1545,18 @@ void QgisApp::restoreSessionPlugins(QString thePluginDirString)
QString packageName = pluginDir[i];

// import plugin's package
QgsPythonUtils::loadPlugin(packageName);
if (!QgsPythonUtils::loadPlugin(packageName))
continue;

// get information from the plugin
QString pluginName = QgsPythonUtils::getPluginMetadata(packageName, "name");
QString description = QgsPythonUtils::getPluginMetadata(packageName, "description");
QString version = QgsPythonUtils::getPluginMetadata(packageName, "version");
// if there are some problems, don't continue with metadata retreival
pluginName = QgsPythonUtils::getPluginMetadata(packageName, "name");
if (pluginName != "__error__")
{
description = QgsPythonUtils::getPluginMetadata(packageName, "description");
if (description != "__error__")
version = QgsPythonUtils::getPluginMetadata(packageName, "version");
}

if (pluginName == "__error__" || description == "__error__" || version == "__error__")
{
Expand Down
7 changes: 4 additions & 3 deletions src/app/qgspythondialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@
#include "qgspythondialog.h"
#include "qgspythonutils.h"

#include <iostream> // %%%


QgsPythonDialog::QgsPythonDialog(QgisInterface* pIface, QWidget *parent)
: QDialog(parent)
Expand All @@ -43,7 +41,10 @@ void QgsPythonDialog::on_edtCmdLine_returnPressed()
// we're using custom hooks for output and exceptions to show output in console
if (QgsPythonUtils::runString(command))
{
output = QgsPythonUtils::getResult();
QgsPythonUtils::evalString("sys.stdout.data", output);
QgsPythonUtils::runString("sys.stdout.data = ''");

output += QgsPythonUtils::getResult();

if (!output.isEmpty())
output += "<br>";
Expand Down
78 changes: 56 additions & 22 deletions src/app/qgspythonutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@

#include "qgsapplication.h"


#include <QMessageBox>

QString QgsPythonUtils::mPluginsPath;
Expand Down Expand Up @@ -84,9 +83,10 @@ void QgsPythonUtils::initPython(QgisInterface* interface)

// hook that will show information and traceback in message box
runString(
"def qgis_except_hook(type, value, tb):\n"
"def qgis_except_hook_msg(type, value, tb, msg):\n"
" lst = traceback.format_exception(type, value, tb)\n"
" str = '<font color=\"red\">An error has occured while executing Python code:</font><br><br>'\n"
" if msg == None: msg = 'An error has occured while executing Python code:'\n"
" str = '<font color=\"red\">'+msg+'</font><br><br>'\n"
" for s in lst:\n"
" str += s\n"
" str = str.replace('\\n', '<br>')\n"
Expand All @@ -96,6 +96,9 @@ void QgsPythonUtils::initPython(QgisInterface* interface)
" msg.setTitle('Error')\n"
" msg.setMessage(str, QgsMessageOutput.MessageHtml)\n"
" msg.showMessage()\n");
runString(
"def qgis_except_hook(type, value, tb):\n"
" qgis_except_hook_msg(type, value, tb, None)\n");

// hook for python console so all output will be redirected
// and then shown in console
Expand Down Expand Up @@ -132,17 +135,31 @@ void QgsPythonUtils::installErrorHook()

void QgsPythonUtils::installConsoleHooks()
{
runString("sys.displayhook = console_display_hook");
runString("sys.displayhook = console_display_hook\n");

runString(
"class MyOutputCatcher:\n"
" def __init__(self):\n"
" self.data = ''\n"
" def write(self, stuff):\n"
" self.data += stuff\n");
runString("_old_stdout = sys.stdout\n");
runString("sys.stdout = MyOutputCatcher()\n");

}

void QgsPythonUtils::uninstallConsoleHooks()
{
runString("sys.displayhook = sys.__displayhook__");
runString("sys.stdout = _old_stdout");

// TODO: uninstalling stdout redirection doesn't work

//installErrorHook();
}


bool QgsPythonUtils::runString(QString command)
bool QgsPythonUtils::runString(const QString& command)
{
PyRun_String(command.toLocal8Bit().data(), Py_single_input, mMainDict, mMainDict);

Expand Down Expand Up @@ -183,15 +200,20 @@ bool QgsPythonUtils::getError(QString& errorClassName, QString& errorText)
}

QString QgsPythonUtils::getResult()
{
return getVariableFromMain("__result");
}

QString QgsPythonUtils::getVariableFromMain(QString name)
{
PyObject* obj;
PyObject* obj_str;

QString output;

// get the result
obj = PyDict_GetItemString(mMainDict, "__result"); // obj is borrowed reference
obj = PyDict_GetItemString(mMainDict, name); // obj is borrowed reference

if (obj != NULL && obj != Py_None)
{
obj_str = PyObject_Str(obj); // obj_str is new reference
Expand All @@ -203,11 +225,25 @@ QString QgsPythonUtils::getResult()
}

// erase result
PyDict_SetItemString(mMainDict, "__result", Py_None);

PyDict_SetItemString(mMainDict, name, Py_None);
return output;
}

bool QgsPythonUtils::evalString(const QString& command, QString& result)
{
PyObject* res = PyRun_String(command.toLocal8Bit().data(), Py_eval_input, mMainDict, mMainDict);

if (res != NULL && PyString_Check(res))
{
result = PyString_AsString(res);
Py_XDECREF(res);
return true;
}
Py_XDECREF(res);
return false;
}


QString QgsPythonUtils::pythonPath()
{
Expand Down Expand Up @@ -248,19 +284,17 @@ QString QgsPythonUtils::getPluginMetadata(QString pluginName, QString function)
bool QgsPythonUtils::loadPlugin(QString packageName)
{
// load plugin's package and ensure that plugin is reloaded when changed
if (!runString("import " + packageName) ||
!runString("reload(" + packageName + ")"))
{
QString className, errorText;
getError(className, errorText);
QString str = className + ": " + errorText;

QMessageBox::warning(0, QObject::tr("Python error"),
QObject::tr("Couldn't load plugin due this error:\n") + str);
return false;
}

return true;
runString(
"try:\n"
" import " + packageName + "\n"
" reload(" + packageName + ")\n"
" __main__.__plugin_result = 'OK'\n"
"except:\n"
" qgis_except_hook_msg(sys.exc_type, sys.exc_value, sys.exc_traceback, "
" 'Couldn\\'t load plugin \"" + packageName + "\"')\n"
" __main__.__plugin_result = 'ERROR'\n");

return (getVariableFromMain("__plugin_result") == "OK");
}


Expand Down
7 changes: 6 additions & 1 deletion src/app/qgspythonutils.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,17 @@ class QgsPythonUtils
//! run a statement (wrapper for PyRun_String)
//! this command is more advanced as enables error checking etc.
//! @return true if no error occured
static bool runString(QString command);
static bool runString(const QString& command);

static bool evalString(const QString& command, QString& result);

//! get information about error to the supplied arguments
//! @return false if there was no python error
static bool getError(QString& errorClassName, QString& errorText);

//! get variable from main dictionary
static QString getVariableFromMain(QString name);

/* python console related functions */

//! change displayhook and excepthook
Expand Down
13 changes: 8 additions & 5 deletions src/ui/qgspythondialog.ui
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
<ui version="4.0" >
<author></author>
<comment></comment>
<exportmacro></exportmacro>
<class>QgsPythonDialog</class>
<widget class="QDialog" name="QgsPythonDialog" >
<property name="geometry" >
Expand Down Expand Up @@ -47,7 +44,10 @@ p, li { white-space: pre-wrap; }
<item>
<widget class="QTextBrowser" name="txtHistory" >
<property name="html" >
<string>&lt;html>&lt;head>&lt;meta name="qrichtext" content="1" />&lt;/head>&lt;body style=" white-space: pre-wrap; font-family:DejaVu Sans Condensed; font-size:10pt; font-weight:400; font-style:normal; text-decoration:none;">&lt;p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">&lt;/p>&lt;/body>&lt;/html></string>
<string>&lt;html>&lt;head>&lt;meta name="qrichtext" content="1" />&lt;style type="text/css">
p, li { white-space: pre-wrap; }
&lt;/style>&lt;/head>&lt;body style=" font-family:'DejaVu Sans Condensed'; font-size:9pt; font-weight:400; font-style:normal; text-decoration:none;">
&lt;p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt;">&lt;/p>&lt;/body>&lt;/html></string>
</property>
</widget>
</item>
Expand All @@ -73,7 +73,10 @@ p, li { white-space: pre-wrap; }
</item>
</layout>
</widget>
<pixmapfunction></pixmapfunction>
<tabstops>
<tabstop>edtCmdLine</tabstop>
<tabstop>txtHistory</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>

0 comments on commit 0f1f6a0

Please sign in to comment.