[QGIS Commit] r12690 - in trunk/qgis: python src/python
svn_qgis at osgeo.org
svn_qgis at osgeo.org
Thu Jan 7 09:59:28 EST 2010
Author: wonder
Date: 2010-01-07 09:59:27 -0500 (Thu, 07 Jan 2010)
New Revision: 12690
Modified:
trunk/qgis/python/utils.py
trunk/qgis/src/python/qgspythonutilsimpl.cpp
Log:
Python support: use a wrapper for import statement that tracks modules of plugins.
This enables complete unload and reload of plugins:
- qgis.utils.unloadPlugin(name) - now removes also plugin's modules (files) from python
- qgis.utils.reloadPlugin(name) - unloads and starts the plugin again (using fresh source files)
Modified: trunk/qgis/python/utils.py
===================================================================
--- trunk/qgis/python/utils.py 2010-01-07 13:49:33 UTC (rev 12689)
+++ trunk/qgis/python/utils.py 2010-01-07 14:59:27 UTC (rev 12690)
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
"""
QGIS utilities module
@@ -6,6 +7,9 @@
from PyQt4.QtCore import QCoreApplication
import sys
import traceback
+import glob
+import os.path
+import re
#######################
@@ -94,6 +98,30 @@
# list of active (started) plugins
active_plugins = []
+# list of plugins in plugin directory and home plugin directory
+available_plugins = []
+
+
+def updateAvailablePlugins():
+ from qgis.core import QgsApplication
+ pythonPath = unicode(QgsApplication.pkgDataPath()) + "/python"
+ homePythonPath = unicode(QgsApplication.qgisSettingsDirPath()) + "/python"
+
+ plugins = map(os.path.basename, glob.glob(pythonPath + "/plugins/*"))
+ homePlugins = map(os.path.basename, glob.glob(homePythonPath + "/plugins/*"))
+
+ # merge the lists
+ for p in homePlugins:
+ if p not in plugins:
+ plugins.append(p)
+
+ global available_plugins
+ available_plugins = plugins
+
+# update list on start
+updateAvailablePlugins()
+
+
def pluginMetadata(packageName, fct):
""" fetch metadata from a plugin """
try:
@@ -103,7 +131,7 @@
return "__error__"
def loadPlugin(packageName):
- """ load plugin's package and ensure that plugin is reloaded when changed """
+ """ load plugin's package """
try:
__import__(packageName)
@@ -117,7 +145,6 @@
# retry
try:
__import__(packageName)
- reload(packageName)
return True
except:
msgTemplate = QCoreApplication.translate("Python", "Couldn't load plugin '%1' from ['%2']")
@@ -140,6 +167,7 @@
try:
plugins[packageName] = package.classFactory(iface)
except:
+ _unloadPluginModules(packageName)
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
@@ -148,6 +176,8 @@
try:
plugins[packageName].initGui()
except:
+ del plugins[packageName]
+ _unloadPluginModules(packageName)
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
@@ -169,15 +199,77 @@
plugins[packageName].unload()
del plugins[packageName]
active_plugins.remove(packageName)
+ _unloadPluginModules(packageName)
return True
except Exception, e:
msg = QCoreApplication.translate("Python", "Error while unloading plugin %1").arg(packageName)
showException(sys.exc_type, sys.exc_value, sys.exc_traceback, msg)
return False
+
+def _unloadPluginModules(packageName):
+ """ unload plugin package with all its modules (files) """
+ global _plugin_modules
+ mods = _plugin_modules[packageName]
+
+ for mod in mods:
+ # if it looks like a Qt resource file, try to do a cleanup
+ # otherwise we might experience a segfault next time the plugin is loaded
+ # because Qt will try to access invalid plugin resource data
+ if "resources" in mod:
+ try:
+ sys.modules[mod].qCleanupResources()
+ except:
+ pass
+ # try to remove the module from python
+ try:
+ del sys.modules[mod]
+ except:
+ pass
+ # remove the plugin entry
+ del _plugin_modules[packageName]
+
+
def isPluginLoaded(packageName):
""" find out whether a plugin is active (i.e. has been started) """
global plugins, active_plugins
if not plugins.has_key(packageName): return False
return (packageName in active_plugins)
+
+
+def reloadPlugin(packageName):
+ """ unload and start again a plugin """
+ global active_plugins
+ if packageName not in active_plugins:
+ return # it's not active
+
+ unloadPlugin(packageName)
+ loadPlugin(packageName)
+ startPlugin(packageName)
+
+
+#######################
+# IMPORT wrapper
+
+import __builtin__
+
+_builtin_import = __builtin__.__import__
+_plugin_modules = { }
+
+def _import(name, globals={}, locals={}, fromlist=[], level=-1):
+ """ wrapper around builtin import that keeps track of loaded plugin modules """
+ mod = _builtin_import(name, globals, locals, fromlist, level)
+
+ if mod and '__file__' in mod.__dict__:
+ module_name = mod.__name__
+ package_name = module_name.split('.')[0]
+ # check whether the module belongs to one of our plugins
+ if package_name in available_plugins:
+ if package_name not in _plugin_modules:
+ _plugin_modules[package_name] = set()
+ _plugin_modules[package_name].add(module_name)
+
+ return mod
+
+__builtin__.__import__ = _import
Modified: trunk/qgis/src/python/qgspythonutilsimpl.cpp
===================================================================
--- trunk/qgis/src/python/qgspythonutilsimpl.cpp 2010-01-07 13:49:33 UTC (rev 12689)
+++ trunk/qgis/src/python/qgspythonutilsimpl.cpp 2010-01-07 14:59:27 UTC (rev 12690)
@@ -424,23 +424,11 @@
QStringList QgsPythonUtilsImpl::pluginList()
{
- QDir pluginDir( QgsPythonUtilsImpl::pluginsPath(), "*",
- QDir::Name | QDir::IgnoreCase, QDir::Dirs | QDir::NoDotAndDotDot );
+ runString( "qgis.utils.updateAvailablePlugins()" );
- 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 output;
+ evalString( "'\\n'.join(qgis.utils.available_plugins)", output );
+ return output.split( QChar( '\n' ) );
}
QString QgsPythonUtilsImpl::getPluginMetadata( QString pluginName, QString function )
More information about the QGIS-commit
mailing list