[QGIS Commit] r11950 - in trunk/qgis: python src/python
svn_qgis at osgeo.org
svn_qgis at osgeo.org
Sat Nov 7 07:04:42 EST 2009
Author: wonder
Date: 2009-11-07 07:04:42 -0500 (Sat, 07 Nov 2009)
New Revision: 11950
Added:
trunk/qgis/python/utils.py
Modified:
trunk/qgis/python/CMakeLists.txt
trunk/qgis/src/python/qgspythonutilsimpl.cpp
Log:
Moved most of the python support code to a new module qgis.utils
This will enable more flexibility in plugins handling
Hopefully it doesn't break anything :-)
Modified: trunk/qgis/python/CMakeLists.txt
===================================================================
--- trunk/qgis/python/CMakeLists.txt 2009-11-07 11:41:45 UTC (rev 11949)
+++ trunk/qgis/python/CMakeLists.txt 2009-11-07 12:04:42 UTC (rev 11950)
@@ -89,5 +89,5 @@
# Step 4: install built libs to python's site packages
-INSTALL(FILES __init__.py ${CMAKE_CURRENT_BINARY_DIR}/qgisconfig.py ${BINDINGS_LIBS} DESTINATION ${SITE_PKG_PATH}/qgis)
+INSTALL(FILES __init__.py utils.py ${CMAKE_CURRENT_BINARY_DIR}/qgisconfig.py ${BINDINGS_LIBS} DESTINATION ${SITE_PKG_PATH}/qgis)
Added: trunk/qgis/python/utils.py
===================================================================
--- trunk/qgis/python/utils.py (rev 0)
+++ trunk/qgis/python/utils.py 2009-11-07 12:04:42 UTC (rev 11950)
@@ -0,0 +1,160 @@
+"""
+QGIS utilities module
+
+"""
+
+from PyQt4.QtCore import QCoreApplication
+import sys
+import traceback
+
+
+#######################
+# ERROR HANDLING
+
+def showException(type, value, tb, msg):
+ lst = traceback.format_exception(type, value, tb)
+ if msg == None:
+ msg = QCoreApplication.translate('Python', 'An error has occured while executing Python code:')
+ txt = '<font color="red">%s</font><br><br>' % msg
+ for s in lst:
+ txt += s
+ txt += '<br>%s<br>%s<br><br>' % (QCoreApplication.translate('Python','Python version:'), sys.version)
+ txt += '%s %s' % (QCoreApplication.translate('Python','Python path:'), str(sys.path))
+ txt = txt.replace('\n', '<br>')
+ txt = txt.replace(' ', ' ') # preserve whitespaces for nicer output
+
+ from qgis.core import QgsMessageOutput
+ msg = QgsMessageOutput.createMessageOutput()
+ msg.setTitle(QCoreApplication.translate('Python', 'Python error'))
+ msg.setMessage(txt, QgsMessageOutput.MessageHtml)
+ msg.showMessage()
+
+def qgis_excepthook(type, value, tb):
+ showException(type, value, tb, None)
+
+def installErrorHook():
+ sys.excepthook = qgis_excepthook
+
+def uninstallErrorHook():
+ sys.excepthook = sys.__excepthook__
+
+# install error hook() on module load
+installErrorHook()
+
+# initialize 'iface' object
+iface = None
+
+def initInterface(pointer):
+ from qgis.gui import QgisInterface
+ from sip import wrapinstance
+ global iface
+ iface = wrapinstance(pointer, QgisInterface)
+
+
+#######################
+# CONSOLE OUTPUT
+
+old_stdout = sys.stdout
+console_output = None
+
+# hook for python console so all output will be redirected
+# and then shown in console
+def console_displayhook(obj):
+ console_output = obj
+
+class QgisOutputCatcher:
+ def __init__(self):
+ self.data = ''
+ def write(self, stuff):
+ self.data += stuff
+ def get_and_clean_data(self):
+ tmp = self.data
+ self.data = ''
+ return tmp
+
+def installConsoleHooks():
+ sys.displayhook = console_displayhook
+ sys.stdout = QgisOutputCatcher()
+
+def uninstallConsoleHooks():
+ sys.displayhook = sys.__displayhook__
+ sys.stdout = old_stdout
+
+
+#######################
+# PLUGINS
+
+# dictionary of plugins
+plugins = {}
+
+def pluginMetadata(packageName, fct):
+ """ fetch metadata from a plugin """
+ try:
+ package = sys.modules[packageName]
+ return getattr(package, fct)()
+ except:
+ return "__error__"
+
+def loadPlugin(packageName):
+ """ load plugin's package and ensure that plugin is reloaded when changed """
+
+ try:
+ __import__(packageName)
+ return True
+ except:
+ pass # continue...
+
+ # snake in the grass, we know it's there
+ sys.path_importer_cache.clear()
+
+ # retry
+ try:
+ __import__(packageName)
+ reload(packageName)
+ return True
+ except:
+ msgTemplate = QCoreApplication.translate("Python", "Couldn't load plugin '%1' from ['%2']")
+ msg = msgTemplate.arg(packageName).arg("', '".join(sys.path))
+ showException(sys.exc_type, sys.exc_value, sys.exc_traceback, msg)
+ return False
+
+
+def startPlugin(packageName):
+ """ initialize the plugin """
+ global plugins, iface
+
+ package = sys.modules[packageName]
+
+ errMsg = QCoreApplication.translate("Python", "Couldn't load plugin %1" ).arg(packageName)
+
+ # create an instance of the plugin
+ try:
+ plugins[packageName] = package.classFactory(iface)
+ except:
+ msg = QCoreApplication.translate("Python", "%1 due an error when calling its classFactory() method").arg(errMsg)
+ showException(sys.exc_type, sys.exc_value, sys.exc_traceback, msg)
+ return False
+
+ # initGui
+ try:
+ plugins[packageName].initGui()
+ except:
+ msg = QCoreApplication.translate("Python", "%1 due an error when calling its initGui() method" ).arg( errMsg )
+ showException(sys.exc_type, sys.exc_value, sys.exc_traceback, msg)
+ return False
+
+ return True
+
+
+def unloadPlugin(packageName):
+ """ unload and delete plugin! """
+ global plugins
+
+ try:
+ plugins[packageName].unload()
+ del plugins[packageName]
+ return True
+ except Exception, e:
+ errMsg = QCoreApplication.translate("Python", "Error while unloading plugin %1").arg(packageName)
+ showException(sys.exc_type, sys.exc_value, sys.exc_traceback, msg)
+ return False
Modified: trunk/qgis/src/python/qgspythonutilsimpl.cpp
===================================================================
--- trunk/qgis/src/python/qgspythonutilsimpl.cpp 2009-11-07 11:41:45 UTC (rev 11949)
+++ trunk/qgis/src/python/qgspythonutilsimpl.cpp 2009-11-07 12:04:42 UTC (rev 11950)
@@ -61,9 +61,6 @@
// also add path to plugins
runString( "sys.path = [\"" + pythonPath() + "\", \"" + homePluginsPath() + "\", \"" + pluginsPath() + "\"] + sys.path" );
- runString( "import traceback" ); // for formatting stack traces
- runString( "import __main__" ); // to access explicitly global variables
-
// import SIP
if ( !runString( "from sip import wrapinstance, unwrapinstance",
QObject::tr( "Couldn't load SIP module." ) + "\n" + QObject::tr( "Python support will be disabled." ) ) )
@@ -88,49 +85,16 @@
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:" ).replace( "'", "\\'" ) + "'\n"
- " txt = '<font color=\"red\">'+msg+'</font><br><br>'\n"
- " for s in lst:\n"
- " txt += s\n"
- " txt += '<br>" + QObject::tr( "Python version:" ).replace( "'", "\\'" ) + "<br>' + sys.version + '<br><br>'\n"
- " txt += '" + QObject::tr( "Python path:" ).replace( "'", "\\'" ) + "' + 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" ).replace( "'", "\\'" ) + "')\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" );
+ // import QGIS utils
+ error_msg = QObject::tr( "Couldn't load QGIS utils." ) + "\n" + QObject::tr( "Python support will be disabled." );
+ if ( !runString("import qgis.utils", error_msg) )
+ {
+ exitPython();
+ return;
+ }
- // 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 = {}" );
-
+ runString( "qgis.utils.initInterface(" + QString::number(( unsigned long ) interface ) + ")" );
}
void QgsPythonUtilsImpl::exitPython()
@@ -149,26 +113,22 @@
void QgsPythonUtilsImpl::installErrorHook()
{
- runString( "sys.excepthook = qgis_except_hook" );
+ runString( "qgis.utils.installErrorHook()" );
}
void QgsPythonUtilsImpl::uninstallErrorHook()
{
- runString( "sys.excepthook = sys.__excepthook__" );
+ runString( "qgis.utils.uninstallErrorHook()" );
}
void QgsPythonUtilsImpl::installConsoleHooks()
{
- runString( "sys.displayhook = console_display_hook\n" );
-
- runString( "_old_stdout = sys.stdout\n" );
- runString( "sys.stdout = QgisOutputCatcher()\n" );
+ runString( "qgis.utils.installConsoleHooks()" );
}
void QgsPythonUtilsImpl::uninstallConsoleHooks()
{
- runString( "sys.displayhook = sys.__displayhook__" );
- runString( "sys.stdout = _old_stdout" );
+ runString( "qgis.utils.uninstallConsoleHooks()" );
}
@@ -193,6 +153,8 @@
msgOnError = QObject::tr( "An error occured during execution of following code:" ) + "\n<tt>" + command + "</tt>";
}
+ // TODO: use python implementation
+
QString traceback = getTraceback();
QString path, version;
evalString( "str(sys.path)", path );
@@ -339,7 +301,7 @@
QString QgsPythonUtilsImpl::getResult()
{
- return getVariableFromMain( "__result" );
+ return getVariableFromMain( "qgis.utils.console_output" );
}
QString QgsPythonUtilsImpl::PyObjectToQString( PyObject* obj )
@@ -425,6 +387,8 @@
{
PyObject* res = PyRun_String( command.toUtf8().data(), Py_eval_input, mMainDict, mMainDict );
+ // TODO: error handling
+
if ( res != NULL )
{
result = PyObjectToQString( res );
@@ -472,106 +436,33 @@
QString QgsPythonUtilsImpl::getPluginMetadata( QString pluginName, QString function )
{
- QString command = pluginName + "." + function + "()";
- QString retval = "???";
-
- // temporary disable error hook - UI will handle this gracefully
- uninstallErrorHook();
- PyObject* obj = PyRun_String( command.toUtf8().data(), Py_eval_input, mMainDict, mMainDict );
-
- if ( PyErr_Occurred() )
- {
- PyErr_Print(); // just print it to console
- PyErr_Clear();
- retval = "__error__";
- }
- else if ( PyUnicode_Check( obj ) )
- {
- PyObject* utf8 = PyUnicode_AsUTF8String( obj );
- if ( utf8 )
- retval = QString::fromUtf8( PyString_AS_STRING( utf8 ) );
- else
- retval = "__error__";
- Py_XDECREF( utf8 );
- }
- else if ( PyString_Check( obj ) )
- {
- retval = PyString_AS_STRING( obj );
- }
- else
- {
- // bad python return value
- retval = "__error__";
- }
- Py_XDECREF( obj );
-
- installErrorHook();
- return retval;
+ QString res;
+ QString str = "qgis.utils.pluginMetadata('" + pluginName + "', '"+function+"')";
+ evalString(str, res);
+ //QgsDebugMsg("metadata "+pluginName+" - '"+function+"' = "+res);
+ return res;
}
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";
+ QString output;
+ evalString("qgis.utils.loadPlugin('" + packageName + "')", output);
+ return (output == "True");
}
bool QgsPythonUtilsImpl::startPlugin( QString packageName )
{
- QString pluginPythonVar = "plugins['" + packageName + "']";
-
- QString errMsg = QObject::tr( "Couldn't load plugin %1" ).arg( packageName );
-
- // create an instance of the plugin
- if ( !runString( pluginPythonVar + " = " + packageName + ".classFactory(iface)",
- QObject::tr( "%1 due an error when calling its classFactory() method" ).arg( errMsg ) ) )
- return false;
-
- // initGui
- if ( !runString( pluginPythonVar + ".initGui()",
- QObject::tr( "%1 due an error when calling its initGui() method" ).arg( errMsg ) ) )
- return false;
-
- return true;
+ QString output;
+ evalString("qgis.utils.startPlugin('" + packageName + "')", output);
+ return (output == "True");
}
bool QgsPythonUtilsImpl::unloadPlugin( QString packageName )
{
- // unload and delete plugin!
- QString varName = "plugins['" + packageName + "']";
-
- QString errMsg = QObject::tr( "Error while unloading plugin %1" ).arg( packageName );
-
- if ( !runString( varName + ".unload()", errMsg ) )
- return false;
- if ( !runString( "del " + varName, errMsg ) )
- return false;
-
- return true;
+ QString output;
+ evalString("qgis.utils.unloadPlugin('" + packageName + "')", output);
+ return (output == "True");
}
More information about the QGIS-commit
mailing list