[QGIS Commit] r8530 - in trunk/qgis/src: . app python
svn_qgis at osgeo.org
svn_qgis at osgeo.org
Wed May 28 08:35:20 EDT 2008
Author: wonder
Date: 2008-05-28 08:35:20 -0400 (Wed, 28 May 2008)
New Revision: 8530
Added:
trunk/qgis/src/python/
trunk/qgis/src/python/CMakeLists.txt
trunk/qgis/src/python/qgispython.cpp
trunk/qgis/src/python/qgspythonutils.h
trunk/qgis/src/python/qgspythonutilsimpl.cpp
trunk/qgis/src/python/qgspythonutilsimpl.h
Removed:
trunk/qgis/src/app/qgspythonutils.cpp
trunk/qgis/src/app/qgspythonutils.h
trunk/qgis/src/app/qgspythonutilsimpl.h
Modified:
trunk/qgis/src/CMakeLists.txt
trunk/qgis/src/app/CMakeLists.txt
trunk/qgis/src/app/qgisapp.cpp
Log:
Moved python support to a library, QGIS app now during the initialization tries to load that library.
Modified: trunk/qgis/src/CMakeLists.txt
===================================================================
--- trunk/qgis/src/CMakeLists.txt 2008-05-28 07:46:59 UTC (rev 8529)
+++ trunk/qgis/src/CMakeLists.txt 2008-05-28 12:35:20 UTC (rev 8530)
@@ -1,6 +1,10 @@
SUBDIRS(core ui gui app providers plugins helpviewer)
+IF (HAVE_PYTHON AND WITH_BINDINGS)
+ SUBDIRS(python)
+ENDIF (HAVE_PYTHON AND WITH_BINDINGS)
+
IF (APPLE)
SUBDIRS(mac)
ENDIF(APPLE)
Modified: trunk/qgis/src/app/CMakeLists.txt
===================================================================
--- trunk/qgis/src/app/CMakeLists.txt 2008-05-28 07:46:59 UTC (rev 8529)
+++ trunk/qgis/src/app/CMakeLists.txt 2008-05-28 12:35:20 UTC (rev 8530)
@@ -153,10 +153,6 @@
)
ENDIF (POSTGRES_FOUND)
-# Python support
-IF (PYTHON_FOUND)
- SET (QGIS_APP_SRCS ${QGIS_APP_SRCS} qgspythonutils.cpp)
-ENDIF (PYTHON_FOUND)
QT4_WRAP_CPP(QGIS_APP_MOC_SRCS ${QGIS_APP_MOC_HDRS})
@@ -198,6 +194,7 @@
../core/raster ../core/renderer ../core/symbology
../gui
../plugins
+ ../python
${PROJ_INCLUDE_DIR}
${SQLITE3_INCLUDE_DIR}
${GEOS_INCLUDE_DIR}
@@ -208,10 +205,6 @@
INCLUDE_DIRECTORIES(${POSTGRES_INCLUDE_DIR})
ENDIF (POSTGRES_FOUND)
-IF (PYTHON_FOUND)
- INCLUDE_DIRECTORIES(${PYTHON_INCLUDE_PATH})
-ENDIF (PYTHON_FOUND)
-
#############
IF (WIN32)
@@ -250,10 +243,6 @@
INSTALL_RPATH_USE_LINK_PATH true
)
-IF (PYTHON_FOUND)
- TARGET_LINK_LIBRARIES(qgis ${PYTHON_LIBRARIES})
-ENDIF (PYTHON_FOUND)
-
IF (POSTGRES_FOUND)
TARGET_LINK_LIBRARIES (qgis ${POSTGRES_LIBRARY})
ENDIF (POSTGRES_FOUND)
Modified: trunk/qgis/src/app/qgisapp.cpp
===================================================================
--- trunk/qgis/src/app/qgisapp.cpp 2008-05-28 07:46:59 UTC (rev 8529)
+++ trunk/qgis/src/app/qgisapp.cpp 2008-05-28 12:35:20 UTC (rev 8530)
@@ -169,9 +169,6 @@
#include "qgspythondialog.h"
#include "qgspythonutils.h"
-#ifdef HAVE_PYTHON
-#include "qgspythonutilsimpl.h"
-#endif
#ifndef WIN32
#include <dlfcn.h>
@@ -360,17 +357,44 @@
qApp->processEvents();
QgsApplication::initQgis();
-#ifdef HAVE_PYTHON
mSplash->showMessage(tr("Starting Python"), Qt::AlignHCenter | Qt::AlignBottom);
qApp->processEvents();
+
+ // try to load python support
+ QLibrary pythonlib("qgispython");
+ // It's necessary to set these two load hints, otherwise Python library won't work correctly
+ // see http://lists.kde.org/?l=pykde&m=117190116820758&w=2
+ pythonlib.setLoadHints(QLibrary::ResolveAllSymbolsHint | QLibrary::ExportExternalSymbolsHint);
+ if (pythonlib.load())
+ {
+ QgsDebugMsg("Python support library loaded successfully.");
+ typedef QgsPythonUtils* (*inst)();
+ inst pythonlib_inst = (inst) pythonlib.resolve("instance");
+ if (pythonlib_inst)
+ {
+ QgsDebugMsg("Python support library's instance() symbol resolved.");
+ mPythonUtils = pythonlib_inst();
+ mPythonUtils->initPython(mQgisInterface);
+ }
+ else
+ {
+ QgsDebugMsg("Couldn't resolve python support library's instance() symbol.");
+ }
+ }
+ else
+ {
+ QgsDebugMsg("Couldn't load Python support library.");
+ }
- mPythonUtils = QgsPythonUtilsImpl::instance();
-
- mPythonUtils->initPython(mQgisInterface);
-#endif
-
- if (!mPythonUtils || !mPythonUtils->isEnabled())
+ if (mPythonUtils && mPythonUtils->isEnabled())
+ {
+ QgsDebugMsg("Python support ENABLED :-)");
+ }
+ else
+ {
mActionShowPythonDialog->setEnabled(false);
+ QgsDebugMsg("Python support DISABLED :-(");
+ }
// Create the plugin registry and load plugins
// load any plugins that were running in the last session
Deleted: trunk/qgis/src/app/qgspythonutils.cpp
===================================================================
--- trunk/qgis/src/app/qgspythonutils.cpp 2008-05-28 07:46:59 UTC (rev 8529)
+++ trunk/qgis/src/app/qgspythonutils.cpp 2008-05-28 12:35:20 UTC (rev 8530)
@@ -1,515 +0,0 @@
-/***************************************************************************
- qgspythonutils.cpp - routines for interfacing Python
- ---------------------
- begin : October 2006
- copyright : (C) 2006 by Martin Dobias
- email : wonder.sk at gmail dot com
- ***************************************************************************
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- ***************************************************************************/
-/* $Id$ */
-
-// python should be first include
-// otherwise issues some warnings
-#include <Python.h>
-
-#include "qgspythonutilsimpl.h"
-
-#include "qgsapplication.h"
-#include "qgslogger.h"
-#include "qgsmessageoutput.h"
-
-#include <QMessageBox>
-#include <QStringList>
-#include <QDir>
-
-QgsPythonUtilsImpl* QgsPythonUtilsImpl::mInstance = NULL;
-
-QgsPythonUtilsImpl::QgsPythonUtilsImpl()
-{
- mMainModule = NULL;
- mMainDict = NULL;
- mPythonEnabled = false;
-}
-
-QgsPythonUtilsImpl::~QgsPythonUtilsImpl()
-{
-}
-
-QgsPythonUtilsImpl* QgsPythonUtilsImpl::instance()
-{
- if (mInstance == NULL)
- mInstance = new QgsPythonUtilsImpl();
- return mInstance;
-}
-
-
-void QgsPythonUtilsImpl::initPython(QgisInterface* interface)
-{
- // initialize python
- Py_Initialize();
-
- mPythonEnabled = true;
-
- mMainModule = PyImport_AddModule("__main__"); // borrowed reference
- mMainDict = PyModule_GetDict(mMainModule); // borrowed reference
-
- 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 = [\"" + pythonPath() + "\", \"" + homePluginsPath() + "\", \"" + pluginsPath() + "\"] + sys.path");
-
- // import SIP
- if (!runString("from sip import wrapinstance, unwrapinstance",
- QObject::tr("Couldn't load SIP module.") + "\n" + QObject::tr("Python support will be disabled.")))
- {
- exitPython();
- return;
- }
-
- // import Qt bindings
- if (!runString("from PyQt4 import QtCore, QtGui",
- QObject::tr("Couldn't load PyQt4.") + "\n" + QObject::tr("Python support will be disabled.")))
- {
- exitPython();
- return;
- }
-
- // import QGIS bindings
- 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))
- {
- exitPython();
- return;
- }
-
- // 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 = '" + 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"
- " 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(' ', ' ')\n" // preserve whitespaces for nicer output
- " \n"
- " msg = QgsMessageOutput.createMessageOutput()\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"
- " qgis_except_hook_msg(type, value, tb, None)\n");
- runString(
- "class QgisOutputCatcher:\n"
- " def __init__(self):\n"
- " self.data = ''\n"
- " def write(self, stuff):\n"
- " self.data += stuff\n"
- " def get_and_clean_data(self):\n"
- " tmp = self.data\n"
- " self.data = ''\n"
- " return tmp\n");
-
- // hook for python console so all output will be redirected
- // and then shown in console
- runString(
- "def console_display_hook(obj):\n"
- " __main__.__result = obj\n");
-
- installErrorHook();
-
- // initialize 'iface' object
- runString("iface = wrapinstance(" + QString::number((unsigned long) interface) + ", QgisInterface)");
- runString("plugins = {}");
-
-}
-
-void QgsPythonUtilsImpl::exitPython()
-{
- Py_Finalize();
- mMainModule = NULL;
- mMainDict = NULL;
- mPythonEnabled = false;
-}
-
-
-bool QgsPythonUtilsImpl::isEnabled()
-{
- return mPythonEnabled;
-}
-
-void QgsPythonUtilsImpl::installErrorHook()
-{
- runString("sys.excepthook = qgis_except_hook");
-}
-
-void QgsPythonUtilsImpl::installConsoleHooks()
-{
- runString("sys.displayhook = console_display_hook\n");
-
- runString("_old_stdout = sys.stdout\n");
- runString("sys.stdout = QgisOutputCatcher()\n");
-}
-
-void QgsPythonUtilsImpl::uninstallConsoleHooks()
-{
- runString("sys.displayhook = sys.__displayhook__");
- runString("sys.stdout = _old_stdout");
-}
-
-
-bool QgsPythonUtilsImpl::runStringUnsafe(const QString& command)
-{
- PyRun_String(command.toLocal8Bit().data(), Py_single_input, mMainDict, mMainDict);
- return (PyErr_Occurred() == 0);
-}
-
-bool QgsPythonUtilsImpl::runString(const QString& command, QString msgOnError)
-{
- bool res = runStringUnsafe(command);
- if (res)
- return true;
-
- 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>";
- }
-
- 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(" ", " ");
-
- QgsMessageOutput* msg = QgsMessageOutput::createMessageOutput();
- msg->setTitle(QObject::tr("Python error"));
- msg->setMessage(str, QgsMessageOutput::MessageHtml);
- msg->showMessage();
-
- return res;
-}
-
-
-QString QgsPythonUtilsImpl::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 QgsPythonUtilsImpl::getTypeAsString(PyObject* obj)
-{
- if (obj == NULL)
- return NULL;
-
- if (PyClass_Check(obj))
- {
- QgsDebugMsg("got class");
- return QString(PyString_AsString(((PyClassObject*)obj)->cl_name));
- }
- else if (PyType_Check(obj))
- {
- QgsDebugMsg("got type");
- return QString(((PyTypeObject*)obj)->tp_name);
- }
- else
- {
- QgsDebugMsg("got object");
- PyObject* s = PyObject_Str(obj);
- QString str;
- if (s && PyString_Check(s))
- str = QString(PyString_AsString(s));
- Py_XDECREF(s);
- return str;
- }
-}
-
-bool QgsPythonUtilsImpl::getError(QString& errorClassName, QString& errorText)
-{
- if (!PyErr_Occurred())
- return false;
-
- PyObject* obj_str;
- PyObject* err_type;
- PyObject* err_value;
- PyObject* err_tb;
-
- // get the exception information and clear error
- PyErr_Fetch(&err_type, &err_value, &err_tb);
-
- // get exception's class name
- errorClassName = getTypeAsString(err_type);
-
- // get exception's text
- if (err_value != NULL && err_value != Py_None)
- {
- obj_str = PyObject_Str(err_value); // new reference
- errorText = PyString_AS_STRING(obj_str);
- Py_XDECREF(obj_str);
- }
- else
- errorText.clear();
-
- // cleanup
- Py_XDECREF(err_type);
- Py_XDECREF(err_value);
- Py_XDECREF(err_tb);
-
- return true;
-}
-
-QString QgsPythonUtilsImpl::getResult()
-{
- return getVariableFromMain("__result");
-}
-
-QString QgsPythonUtilsImpl::getVariableFromMain(QString name)
-{
- PyObject* obj;
- PyObject* obj_str;
-
- QString output;
-
- // get the result
- obj = PyDict_GetItemString(mMainDict, name.toUtf8()); // obj is borrowed reference
-
- if (obj != NULL && obj != Py_None)
- {
- obj_str = PyObject_Str(obj); // obj_str is new reference
- if (obj_str != NULL && obj_str != Py_None)
- {
- output = PyString_AsString(obj_str);
- }
- Py_XDECREF(obj_str);
- }
-
- // erase result
- PyDict_SetItemString(mMainDict, name.toUtf8(), Py_None);
-
- return output;
-}
-
-bool QgsPythonUtilsImpl::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 QgsPythonUtilsImpl::pythonPath()
-{
- return QgsApplication::pkgDataPath() + "/python";
-}
-
-QString QgsPythonUtilsImpl::pluginsPath()
-{
- return pythonPath() + "/plugins";
-}
-
-QString QgsPythonUtilsImpl::homePluginsPath()
-{
- return QgsApplication::qgisSettingsDirPath() + "/python/plugins";
-}
-
-QStringList QgsPythonUtilsImpl::pluginList()
-{
- QDir pluginDir(QgsPythonUtilsImpl::pluginsPath(), "*",
- QDir::Name | QDir::IgnoreCase, QDir::Dirs | QDir::NoDotAndDotDot);
-
- QDir homePluginDir(QgsPythonUtilsImpl::homePluginsPath(), "*",
- QDir::Name | QDir::IgnoreCase, QDir::Dirs | QDir::NoDotAndDotDot);
-
- QStringList pluginList = pluginDir.entryList();
-
- for (uint i = 0; i < homePluginDir.count(); i++)
- {
- QString packageName = homePluginDir[i];
- if(!pluginList.contains(packageName))
- pluginList.append(packageName);
-
- }
-
- return pluginList;
-}
-
-QString QgsPythonUtilsImpl::getPluginMetadata(QString pluginName, QString function)
-{
- QString command = pluginName + "." + function + "()";
- QString retval = "???";
-
- PyObject* obj = PyRun_String(command.toLocal8Bit().data(), Py_eval_input, mMainDict, mMainDict);
- if (PyErr_Occurred())
- {
- PyErr_Print(); // just print it to console
- PyErr_Clear();
- return "__error__";
- }
- else if (PyString_Check(obj))
- {
- retval = PyString_AS_STRING(obj);
- }
- else
- {
- // bad python return value
- retval = "__error__";
- }
- Py_XDECREF(obj);
- return retval;
-}
-
-
-bool QgsPythonUtilsImpl::loadPlugin(QString packageName)
-{
- // load plugin's package and ensure that plugin is reloaded when changed
- runString(
- "try:\n"
- " import " + packageName + "\n"
- " __main__.__plugin_result = 'OK'\n"
- "except:\n"
- " __main__.__plugin_result = 'ERROR'\n");
-
- if( getVariableFromMain("__plugin_result") == "OK" )
- return true;
-
- // snake in the grass, we know it's there
- runString("sys.path_importer_cache.clear()");
-
- // retry
- 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 + "\" from [\\'' + '\\', \\''.join(sys.path) + '\\']')\n"
- " __main__.__plugin_result = 'ERROR'\n");
-
- return getVariableFromMain("__plugin_result") == "OK";
-}
-
-
-bool QgsPythonUtilsImpl::startPlugin(QString packageName)
-{
- 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)",
- errMsg + QObject::tr(" due an error when calling its classFactory() method")))
- return false;
-
- // initGui
- if (!runString(pluginPythonVar + ".initGui()", errMsg + QObject::tr(" due an error when calling its initGui() method")))
- return false;
-
- return true;
-}
-
-
-bool QgsPythonUtilsImpl::unloadPlugin(QString packageName)
-{
- // unload and delete plugin!
- QString varName = "plugins['" + 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;
-}
Deleted: trunk/qgis/src/app/qgspythonutils.h
===================================================================
--- trunk/qgis/src/app/qgspythonutils.h 2008-05-28 07:46:59 UTC (rev 8529)
+++ trunk/qgis/src/app/qgspythonutils.h 2008-05-28 12:35:20 UTC (rev 8530)
@@ -1,93 +0,0 @@
-/***************************************************************************
- qgspythonutils.h - abstract interface for Python routines
- ---------------------
- begin : October 2006
- copyright : (C) 2006 by Martin Dobias
- email : wonder.sk at gmail dot com
- ***************************************************************************
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- ***************************************************************************/
-/* $Id$ */
-
-#ifndef QGSPYTHONUTILS_H
-#define QGSPYTHONUTILS_H
-
-#include <QString>
-#include <QStringList>
-
-
-class QgisInterface;
-
-/**
- All calls to Python functions in QGIS come here.
- This class is a singleton.
-
- Default path for python plugins is:
- - QgsApplication::qgisSettingsDirPath() + "/python/plugins"
- - QgsApplication::pkgDataPath() + "/python/plugins"
-
- */
-
-class QgsPythonUtils
-{
- public:
-
- virtual ~QgsPythonUtils() {}
-
- //! returns true if python support is ready to use (must be inited first)
- virtual bool isEnabled() = 0;
-
- //! initialize python and import bindings
- virtual void initPython(QgisInterface* interface) = 0;
-
- //! close python interpreter
- virtual void exitPython() = 0;
-
- /* console */
-
- //! run a statement, error reporting is not done
- //! @return true if no error occured
- virtual bool runStringUnsafe(const QString& command) = 0;
-
- virtual bool evalString(const QString& command, QString& result) = 0;
-
- //! change displayhook and excepthook
- //! our hooks will just save the result to special variables
- //! and those can be used in the program
- virtual void installConsoleHooks() = 0;
-
- //! get back to the original settings (i.e. write output to stdout)
- virtual void uninstallConsoleHooks() = 0;
-
- //! get result from the last statement as a string
- virtual QString getResult() = 0;
-
- //! get information about error to the supplied arguments
- //! @return false if there was no python error
- virtual bool getError(QString& errorClassName, QString& errorText) = 0;
-
- /* plugins */
-
- //! return list of all available python plugins
- virtual QStringList pluginList() = 0;
-
- //! load python plugin (import)
- virtual bool loadPlugin(QString packageName) = 0;
-
- //! start plugin: add to active plugins and call initGui()
- virtual bool startPlugin(QString packageName) = 0;
-
- //! helper function to get some information about plugin
- //! @param function one of these strings: name, tpye, version, description
- virtual QString getPluginMetadata(QString pluginName, QString function) = 0;
-
- //! unload plugin
- virtual bool unloadPlugin(QString packageName) = 0;
-};
-
-#endif
Deleted: trunk/qgis/src/app/qgspythonutilsimpl.h
===================================================================
--- trunk/qgis/src/app/qgspythonutilsimpl.h 2008-05-28 07:46:59 UTC (rev 8529)
+++ trunk/qgis/src/app/qgspythonutilsimpl.h 2008-05-28 12:35:20 UTC (rev 8530)
@@ -1,132 +0,0 @@
-/***************************************************************************
- qgspythonutilsimpl.h - routines for interfacing Python
- ---------------------
- begin : May 2008
- copyright : (C) 2008 by Martin Dobias
- email : wonder.sk at gmail dot com
- ***************************************************************************
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- ***************************************************************************/
-/* $Id$ */
-
-
-#ifndef QGSPYTHONUTILSIMPL_H
-#define QGSPYTHONUTILSIMPL_H
-
-#include "qgspythonutils.h"
-
-// forward declaration for PyObject
-#ifndef PyObject_HEAD
-struct _object;
-typedef _object PyObject;
-#endif
-
-
-class QgsPythonUtilsImpl : public QgsPythonUtils
-{
- public:
-
- QgsPythonUtilsImpl();
-
- virtual ~QgsPythonUtilsImpl();
-
- static QgsPythonUtilsImpl* instance();
-
- /* general purpose functions */
-
- //! initialize python and import bindings
- void initPython(QgisInterface* interface);
-
- //! close python interpreter
- void exitPython();
-
- //! returns true if python support is ready to use (must be inited first)
- bool isEnabled();
-
- //! returns path where QGIS python stuff is located
- QString pythonPath();
-
- //! 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
- bool runString(const QString& command, QString msgOnError = QString());
-
- //! run a statement, error reporting is not done
- //! @return true if no error occured
- bool runStringUnsafe(const QString& command);
-
- bool evalString(const QString& command, QString& result);
-
- //! @return object's type name as a string
- QString getTypeAsString(PyObject* obj);
-
- //! get information about error to the supplied arguments
- //! @return false if there was no python error
- bool getError(QString& errorClassName, QString& errorText);
-
- //! get variable from main dictionary
- QString getVariableFromMain(QString name);
-
- /* python console related functions */
-
- //! change displayhook and excepthook
- //! our hooks will just save the result to special variables
- //! and those can be used in the program
- void installConsoleHooks();
-
- //! get back to the original settings (i.e. write output to stdout)
- void uninstallConsoleHooks();
-
- //! get result from the last statement as a string
- QString getResult();
-
- /* plugins related functions */
-
- //! return current path for python plugins
- QString pluginsPath();
-
- //! return current path for home directory python plugins
- QString homePluginsPath();
-
- //! return list of all available python plugins
- QStringList pluginList();
-
- //! load python plugin (import)
- bool loadPlugin(QString packageName);
-
- //! start plugin: add to active plugins and call initGui()
- bool startPlugin(QString packageName);
-
- //! helper function to get some information about plugin
- //! @param function one of these strings: name, tpye, version, description
- QString getPluginMetadata(QString pluginName, QString function);
-
- //! unload plugin
- bool unloadPlugin(QString packageName);
-
- protected:
-
- void installErrorHook();
-
- QString getTraceback();
-
- //! reference to module __main__
- PyObject* mMainModule;
-
- //! dictionary of module __main__
- PyObject* mMainDict;
-
- //! flag determining that python support is enabled
- bool mPythonEnabled;
-
- static QgsPythonUtilsImpl* mInstance;
-};
-
-
-#endif
Added: trunk/qgis/src/python/CMakeLists.txt
===================================================================
--- trunk/qgis/src/python/CMakeLists.txt (rev 0)
+++ trunk/qgis/src/python/CMakeLists.txt 2008-05-28 12:35:20 UTC (rev 8530)
@@ -0,0 +1,25 @@
+
+SET(QGISPYTHON_SRCS qgispython.cpp qgspythonutilsimpl.cpp)
+
+INCLUDE_DIRECTORIES(
+ ../core
+ ../core/raster ../core/renderer ../core/symbology
+ ../gui
+ ${PYTHON_INCLUDE_PATH})
+
+ADD_LIBRARY (qgispython SHARED ${QGISPYTHON_SRCS})
+
+SET_TARGET_PROPERTIES(qgispython PROPERTIES
+ VERSION ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}
+ SOVERSION ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR})
+
+
+TARGET_LINK_LIBRARIES(qgispython
+ ${QT_QTCORE_LIBRARY}
+ ${QT_QTGUI_LIBRARY}
+ ${PYTHON_LIBRARIES}
+)
+
+INSTALL(TARGETS qgispython
+ RUNTIME DESTINATION ${QGIS_BIN_DIR}
+ LIBRARY DESTINATION ${QGIS_LIB_DIR})
Added: trunk/qgis/src/python/qgispython.cpp
===================================================================
--- trunk/qgis/src/python/qgispython.cpp (rev 0)
+++ trunk/qgis/src/python/qgispython.cpp 2008-05-28 12:35:20 UTC (rev 8530)
@@ -0,0 +1,23 @@
+/***************************************************************************
+ qgispython.cpp - python support in QGIS
+ ---------------------
+ begin : May 2008
+ copyright : (C) 2008 by Martin Dobias
+ email : wonder.sk at gmail dot com
+ ***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+/* $Id$ */
+
+#include "qgis.h"
+#include "qgspythonutilsimpl.h"
+
+QGISEXTERN QgsPythonUtils* instance()
+{
+ return new QgsPythonUtilsImpl();
+}
Copied: trunk/qgis/src/python/qgspythonutils.h (from rev 8517, trunk/qgis/src/app/qgspythonutils.h)
===================================================================
--- trunk/qgis/src/python/qgspythonutils.h (rev 0)
+++ trunk/qgis/src/python/qgspythonutils.h 2008-05-28 12:35:20 UTC (rev 8530)
@@ -0,0 +1,93 @@
+/***************************************************************************
+ qgspythonutils.h - abstract interface for Python routines
+ ---------------------
+ begin : October 2006
+ copyright : (C) 2006 by Martin Dobias
+ email : wonder.sk at gmail dot com
+ ***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+/* $Id$ */
+
+#ifndef QGSPYTHONUTILS_H
+#define QGSPYTHONUTILS_H
+
+#include <QString>
+#include <QStringList>
+
+
+class QgisInterface;
+
+/**
+ All calls to Python functions in QGIS come here.
+ This class is a singleton.
+
+ Default path for python plugins is:
+ - QgsApplication::qgisSettingsDirPath() + "/python/plugins"
+ - QgsApplication::pkgDataPath() + "/python/plugins"
+
+ */
+
+class QgsPythonUtils
+{
+ public:
+
+ virtual ~QgsPythonUtils() {}
+
+ //! returns true if python support is ready to use (must be inited first)
+ virtual bool isEnabled() = 0;
+
+ //! initialize python and import bindings
+ virtual void initPython(QgisInterface* interface) = 0;
+
+ //! close python interpreter
+ virtual void exitPython() = 0;
+
+ /* console */
+
+ //! run a statement, error reporting is not done
+ //! @return true if no error occured
+ virtual bool runStringUnsafe(const QString& command) = 0;
+
+ virtual bool evalString(const QString& command, QString& result) = 0;
+
+ //! change displayhook and excepthook
+ //! our hooks will just save the result to special variables
+ //! and those can be used in the program
+ virtual void installConsoleHooks() = 0;
+
+ //! get back to the original settings (i.e. write output to stdout)
+ virtual void uninstallConsoleHooks() = 0;
+
+ //! get result from the last statement as a string
+ virtual QString getResult() = 0;
+
+ //! get information about error to the supplied arguments
+ //! @return false if there was no python error
+ virtual bool getError(QString& errorClassName, QString& errorText) = 0;
+
+ /* plugins */
+
+ //! return list of all available python plugins
+ virtual QStringList pluginList() = 0;
+
+ //! load python plugin (import)
+ virtual bool loadPlugin(QString packageName) = 0;
+
+ //! start plugin: add to active plugins and call initGui()
+ virtual bool startPlugin(QString packageName) = 0;
+
+ //! helper function to get some information about plugin
+ //! @param function one of these strings: name, tpye, version, description
+ virtual QString getPluginMetadata(QString pluginName, QString function) = 0;
+
+ //! unload plugin
+ virtual bool unloadPlugin(QString packageName) = 0;
+};
+
+#endif
Copied: trunk/qgis/src/python/qgspythonutilsimpl.cpp (from rev 8517, trunk/qgis/src/app/qgspythonutils.cpp)
===================================================================
--- trunk/qgis/src/python/qgspythonutilsimpl.cpp (rev 0)
+++ trunk/qgis/src/python/qgspythonutilsimpl.cpp 2008-05-28 12:35:20 UTC (rev 8530)
@@ -0,0 +1,505 @@
+/***************************************************************************
+ qgspythonutils.cpp - routines for interfacing Python
+ ---------------------
+ begin : October 2006
+ copyright : (C) 2006 by Martin Dobias
+ email : wonder.sk at gmail dot com
+ ***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+/* $Id$ */
+
+// python should be first include
+// otherwise issues some warnings
+#include <Python.h>
+
+#include "qgspythonutilsimpl.h"
+
+#include "qgsapplication.h"
+#include "qgslogger.h"
+#include "qgsmessageoutput.h"
+
+#include <QMessageBox>
+#include <QStringList>
+#include <QDir>
+
+
+QgsPythonUtilsImpl::QgsPythonUtilsImpl()
+{
+ mMainModule = NULL;
+ mMainDict = NULL;
+ mPythonEnabled = false;
+}
+
+QgsPythonUtilsImpl::~QgsPythonUtilsImpl()
+{
+}
+
+void QgsPythonUtilsImpl::initPython(QgisInterface* interface)
+{
+ // initialize python
+ Py_Initialize();
+
+ mPythonEnabled = true;
+
+ mMainModule = PyImport_AddModule("__main__"); // borrowed reference
+ mMainDict = PyModule_GetDict(mMainModule); // borrowed reference
+
+ 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 = [\"" + pythonPath() + "\", \"" + homePluginsPath() + "\", \"" + pluginsPath() + "\"] + sys.path");
+
+ // import SIP
+ if (!runString("from sip import wrapinstance, unwrapinstance",
+ QObject::tr("Couldn't load SIP module.") + "\n" + QObject::tr("Python support will be disabled.")))
+ {
+ exitPython();
+ return;
+ }
+
+ // import Qt bindings
+ if (!runString("from PyQt4 import QtCore, QtGui",
+ QObject::tr("Couldn't load PyQt4.") + "\n" + QObject::tr("Python support will be disabled.")))
+ {
+ exitPython();
+ return;
+ }
+
+ // import QGIS bindings
+ 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))
+ {
+ exitPython();
+ return;
+ }
+
+ // 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 = '" + 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"
+ " 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(' ', ' ')\n" // preserve whitespaces for nicer output
+ " \n"
+ " msg = QgsMessageOutput.createMessageOutput()\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"
+ " qgis_except_hook_msg(type, value, tb, None)\n");
+ runString(
+ "class QgisOutputCatcher:\n"
+ " def __init__(self):\n"
+ " self.data = ''\n"
+ " def write(self, stuff):\n"
+ " self.data += stuff\n"
+ " def get_and_clean_data(self):\n"
+ " tmp = self.data\n"
+ " self.data = ''\n"
+ " return tmp\n");
+
+ // hook for python console so all output will be redirected
+ // and then shown in console
+ runString(
+ "def console_display_hook(obj):\n"
+ " __main__.__result = obj\n");
+
+ installErrorHook();
+
+ // initialize 'iface' object
+ runString("iface = wrapinstance(" + QString::number((unsigned long) interface) + ", QgisInterface)");
+ runString("plugins = {}");
+
+}
+
+void QgsPythonUtilsImpl::exitPython()
+{
+ Py_Finalize();
+ mMainModule = NULL;
+ mMainDict = NULL;
+ mPythonEnabled = false;
+}
+
+
+bool QgsPythonUtilsImpl::isEnabled()
+{
+ return mPythonEnabled;
+}
+
+void QgsPythonUtilsImpl::installErrorHook()
+{
+ runString("sys.excepthook = qgis_except_hook");
+}
+
+void QgsPythonUtilsImpl::installConsoleHooks()
+{
+ runString("sys.displayhook = console_display_hook\n");
+
+ runString("_old_stdout = sys.stdout\n");
+ runString("sys.stdout = QgisOutputCatcher()\n");
+}
+
+void QgsPythonUtilsImpl::uninstallConsoleHooks()
+{
+ runString("sys.displayhook = sys.__displayhook__");
+ runString("sys.stdout = _old_stdout");
+}
+
+
+bool QgsPythonUtilsImpl::runStringUnsafe(const QString& command)
+{
+ PyRun_String(command.toLocal8Bit().data(), Py_single_input, mMainDict, mMainDict);
+ return (PyErr_Occurred() == 0);
+}
+
+bool QgsPythonUtilsImpl::runString(const QString& command, QString msgOnError)
+{
+ bool res = runStringUnsafe(command);
+ if (res)
+ return true;
+
+ 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>";
+ }
+
+ 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(" ", " ");
+
+ QgsMessageOutput* msg = QgsMessageOutput::createMessageOutput();
+ msg->setTitle(QObject::tr("Python error"));
+ msg->setMessage(str, QgsMessageOutput::MessageHtml);
+ msg->showMessage();
+
+ return res;
+}
+
+
+QString QgsPythonUtilsImpl::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 QgsPythonUtilsImpl::getTypeAsString(PyObject* obj)
+{
+ if (obj == NULL)
+ return NULL;
+
+ if (PyClass_Check(obj))
+ {
+ QgsDebugMsg("got class");
+ return QString(PyString_AsString(((PyClassObject*)obj)->cl_name));
+ }
+ else if (PyType_Check(obj))
+ {
+ QgsDebugMsg("got type");
+ return QString(((PyTypeObject*)obj)->tp_name);
+ }
+ else
+ {
+ QgsDebugMsg("got object");
+ PyObject* s = PyObject_Str(obj);
+ QString str;
+ if (s && PyString_Check(s))
+ str = QString(PyString_AsString(s));
+ Py_XDECREF(s);
+ return str;
+ }
+}
+
+bool QgsPythonUtilsImpl::getError(QString& errorClassName, QString& errorText)
+{
+ if (!PyErr_Occurred())
+ return false;
+
+ PyObject* obj_str;
+ PyObject* err_type;
+ PyObject* err_value;
+ PyObject* err_tb;
+
+ // get the exception information and clear error
+ PyErr_Fetch(&err_type, &err_value, &err_tb);
+
+ // get exception's class name
+ errorClassName = getTypeAsString(err_type);
+
+ // get exception's text
+ if (err_value != NULL && err_value != Py_None)
+ {
+ obj_str = PyObject_Str(err_value); // new reference
+ errorText = PyString_AS_STRING(obj_str);
+ Py_XDECREF(obj_str);
+ }
+ else
+ errorText.clear();
+
+ // cleanup
+ Py_XDECREF(err_type);
+ Py_XDECREF(err_value);
+ Py_XDECREF(err_tb);
+
+ return true;
+}
+
+QString QgsPythonUtilsImpl::getResult()
+{
+ return getVariableFromMain("__result");
+}
+
+QString QgsPythonUtilsImpl::getVariableFromMain(QString name)
+{
+ PyObject* obj;
+ PyObject* obj_str;
+
+ QString output;
+
+ // get the result
+ obj = PyDict_GetItemString(mMainDict, name.toUtf8()); // obj is borrowed reference
+
+ if (obj != NULL && obj != Py_None)
+ {
+ obj_str = PyObject_Str(obj); // obj_str is new reference
+ if (obj_str != NULL && obj_str != Py_None)
+ {
+ output = PyString_AsString(obj_str);
+ }
+ Py_XDECREF(obj_str);
+ }
+
+ // erase result
+ PyDict_SetItemString(mMainDict, name.toUtf8(), Py_None);
+
+ return output;
+}
+
+bool QgsPythonUtilsImpl::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 QgsPythonUtilsImpl::pythonPath()
+{
+ return QgsApplication::pkgDataPath() + "/python";
+}
+
+QString QgsPythonUtilsImpl::pluginsPath()
+{
+ return pythonPath() + "/plugins";
+}
+
+QString QgsPythonUtilsImpl::homePluginsPath()
+{
+ return QgsApplication::qgisSettingsDirPath() + "/python/plugins";
+}
+
+QStringList QgsPythonUtilsImpl::pluginList()
+{
+ QDir pluginDir(QgsPythonUtilsImpl::pluginsPath(), "*",
+ QDir::Name | QDir::IgnoreCase, QDir::Dirs | QDir::NoDotAndDotDot);
+
+ QDir homePluginDir(QgsPythonUtilsImpl::homePluginsPath(), "*",
+ QDir::Name | QDir::IgnoreCase, QDir::Dirs | QDir::NoDotAndDotDot);
+
+ QStringList pluginList = pluginDir.entryList();
+
+ for (uint i = 0; i < homePluginDir.count(); i++)
+ {
+ QString packageName = homePluginDir[i];
+ if(!pluginList.contains(packageName))
+ pluginList.append(packageName);
+
+ }
+
+ return pluginList;
+}
+
+QString QgsPythonUtilsImpl::getPluginMetadata(QString pluginName, QString function)
+{
+ QString command = pluginName + "." + function + "()";
+ QString retval = "???";
+
+ PyObject* obj = PyRun_String(command.toLocal8Bit().data(), Py_eval_input, mMainDict, mMainDict);
+ if (PyErr_Occurred())
+ {
+ PyErr_Print(); // just print it to console
+ PyErr_Clear();
+ return "__error__";
+ }
+ else if (PyString_Check(obj))
+ {
+ retval = PyString_AS_STRING(obj);
+ }
+ else
+ {
+ // bad python return value
+ retval = "__error__";
+ }
+ Py_XDECREF(obj);
+ return retval;
+}
+
+
+bool QgsPythonUtilsImpl::loadPlugin(QString packageName)
+{
+ // load plugin's package and ensure that plugin is reloaded when changed
+ runString(
+ "try:\n"
+ " import " + packageName + "\n"
+ " __main__.__plugin_result = 'OK'\n"
+ "except:\n"
+ " __main__.__plugin_result = 'ERROR'\n");
+
+ if( getVariableFromMain("__plugin_result") == "OK" )
+ return true;
+
+ // snake in the grass, we know it's there
+ runString("sys.path_importer_cache.clear()");
+
+ // retry
+ 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 + "\" from [\\'' + '\\', \\''.join(sys.path) + '\\']')\n"
+ " __main__.__plugin_result = 'ERROR'\n");
+
+ return getVariableFromMain("__plugin_result") == "OK";
+}
+
+
+bool QgsPythonUtilsImpl::startPlugin(QString packageName)
+{
+ 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)",
+ errMsg + QObject::tr(" due an error when calling its classFactory() method")))
+ return false;
+
+ // initGui
+ if (!runString(pluginPythonVar + ".initGui()", errMsg + QObject::tr(" due an error when calling its initGui() method")))
+ return false;
+
+ return true;
+}
+
+
+bool QgsPythonUtilsImpl::unloadPlugin(QString packageName)
+{
+ // unload and delete plugin!
+ QString varName = "plugins['" + 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;
+}
Copied: trunk/qgis/src/python/qgspythonutilsimpl.h (from rev 8517, trunk/qgis/src/app/qgspythonutilsimpl.h)
===================================================================
--- trunk/qgis/src/python/qgspythonutilsimpl.h (rev 0)
+++ trunk/qgis/src/python/qgspythonutilsimpl.h 2008-05-28 12:35:20 UTC (rev 8530)
@@ -0,0 +1,128 @@
+/***************************************************************************
+ qgspythonutilsimpl.h - routines for interfacing Python
+ ---------------------
+ begin : May 2008
+ copyright : (C) 2008 by Martin Dobias
+ email : wonder.sk at gmail dot com
+ ***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+/* $Id$ */
+
+
+#ifndef QGSPYTHONUTILSIMPL_H
+#define QGSPYTHONUTILSIMPL_H
+
+#include "qgspythonutils.h"
+
+// forward declaration for PyObject
+#ifndef PyObject_HEAD
+struct _object;
+typedef _object PyObject;
+#endif
+
+
+class QgsPythonUtilsImpl : public QgsPythonUtils
+{
+ public:
+
+ QgsPythonUtilsImpl();
+
+ virtual ~QgsPythonUtilsImpl();
+
+ /* general purpose functions */
+
+ //! initialize python and import bindings
+ void initPython(QgisInterface* interface);
+
+ //! close python interpreter
+ void exitPython();
+
+ //! returns true if python support is ready to use (must be inited first)
+ bool isEnabled();
+
+ //! returns path where QGIS python stuff is located
+ QString pythonPath();
+
+ //! 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
+ bool runString(const QString& command, QString msgOnError = QString());
+
+ //! run a statement, error reporting is not done
+ //! @return true if no error occured
+ bool runStringUnsafe(const QString& command);
+
+ bool evalString(const QString& command, QString& result);
+
+ //! @return object's type name as a string
+ QString getTypeAsString(PyObject* obj);
+
+ //! get information about error to the supplied arguments
+ //! @return false if there was no python error
+ bool getError(QString& errorClassName, QString& errorText);
+
+ //! get variable from main dictionary
+ QString getVariableFromMain(QString name);
+
+ /* python console related functions */
+
+ //! change displayhook and excepthook
+ //! our hooks will just save the result to special variables
+ //! and those can be used in the program
+ void installConsoleHooks();
+
+ //! get back to the original settings (i.e. write output to stdout)
+ void uninstallConsoleHooks();
+
+ //! get result from the last statement as a string
+ QString getResult();
+
+ /* plugins related functions */
+
+ //! return current path for python plugins
+ QString pluginsPath();
+
+ //! return current path for home directory python plugins
+ QString homePluginsPath();
+
+ //! return list of all available python plugins
+ QStringList pluginList();
+
+ //! load python plugin (import)
+ bool loadPlugin(QString packageName);
+
+ //! start plugin: add to active plugins and call initGui()
+ bool startPlugin(QString packageName);
+
+ //! helper function to get some information about plugin
+ //! @param function one of these strings: name, tpye, version, description
+ QString getPluginMetadata(QString pluginName, QString function);
+
+ //! unload plugin
+ bool unloadPlugin(QString packageName);
+
+ protected:
+
+ void installErrorHook();
+
+ QString getTraceback();
+
+ //! reference to module __main__
+ PyObject* mMainModule;
+
+ //! dictionary of module __main__
+ PyObject* mMainDict;
+
+ //! flag determining that python support is enabled
+ bool mPythonEnabled;
+};
+
+
+#endif
More information about the QGIS-commit
mailing list