mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-15 00:04:00 -04:00
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) git-svn-id: http://svn.osgeo.org/qgis/trunk@12690 c8812cc2-4d05-0410-92ff-de0c093fc19c
This commit is contained in:
parent
01e993cf4c
commit
bb5f4139ab
@ -1,3 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
QGIS utilities module
|
||||
|
||||
@ -6,6 +7,9 @@ QGIS utilities module
|
||||
from PyQt4.QtCore import QCoreApplication
|
||||
import sys
|
||||
import traceback
|
||||
import glob
|
||||
import os.path
|
||||
import re
|
||||
|
||||
|
||||
#######################
|
||||
@ -94,6 +98,30 @@ plugins = {}
|
||||
# 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 @@ def pluginMetadata(packageName, fct):
|
||||
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 @@ def loadPlugin(packageName):
|
||||
# retry
|
||||
try:
|
||||
__import__(packageName)
|
||||
reload(packageName)
|
||||
return True
|
||||
except:
|
||||
msgTemplate = QCoreApplication.translate("Python", "Couldn't load plugin '%1' from ['%2']")
|
||||
@ -140,6 +167,7 @@ def startPlugin(packageName):
|
||||
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 @@ def startPlugin(packageName):
|
||||
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 @@ def unloadPlugin(packageName):
|
||||
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
|
||||
|
@ -424,23 +424,11 @@ QString QgsPythonUtilsImpl::homePluginsPath()
|
||||
|
||||
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 )
|
||||
|
Loading…
x
Reference in New Issue
Block a user