#/*##########################################################################
#
# The PyMca X-Ray Fluorescence Toolkit
#
# Copyright (c) 2004-2014 European Synchrotron Radiation Facility
#
# This file is part of the PyMca X-ray Fluorescence Toolkit developed at
# the ESRF by the Software group.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
#############################################################################*/
__author__ = "V.A. Sole - ESRF Data Analysis"
__contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
__doc__ = """
Class to handle loading of plugins according to target method.
On instantiation, this clase imports all the plugins found in the PLUGINS_DIR
directory and stores them into the attributes pluginList and pluginInstanceDict
"""
import os
import sys
import glob
PLUGINS_DIR = None
DEBUG = 0
[docs]class PluginLoader(object):
def __init__(self, method=None, directoryList=None):
self._pluginDirList = []
self.pluginList = []
self.pluginInstanceDict = {}
self.getPlugins(method=method, directoryList=directoryList)
[docs] def setPluginDirectoryList(self, dirlist):
"""
:param dirlist: Set directories to search for plugins
:type dirlist: list
"""
for directory in dirlist:
if not os.path.exists(directory):
raise IOError("Directory:\n%s\ndoes not exist." % directory)
self._pluginDirList = dirlist
[docs] def getPluginDirectoryList(self):
"""
:return dirlist: List of directories for searching plugins
"""
return self._pluginDirList
[docs] def getPlugins(self, method=None, directoryList=None, exceptions=False):
"""
Import or reloads all the available plugins with the target method
:param method: The method to be searched for.
:type method: string, default "getPlugin1DInstance"
:param directoryList: The list of directories for the search.
:type directoryList: list or None (default).
:param exceptions: If True, return the list of error messages
:type exceptions: boolean (default False)
:return: The number of plugins loaded. If exceptions is True, also the
text with the error encountered.
"""
if method is None:
method = 'getPlugin1DInstance'
targetMethod = method
if directoryList in [None, [] ]:
directoryList = self._pluginDirList
if directoryList in [None, []]:
directoryList = [PLUGINS_DIR]
if DEBUG:
print("method: %s" % targetMethod)
print("directoryList: %s" % directoryList)
exceptionMessage = ""
self._pluginDirList = directoryList
self.pluginList = []
for directory in self._pluginDirList:
if directory is None:
continue
if not os.path.exists(directory):
raise IOError("Directory:\n%s\ndoes not exist." % directory)
fileList = glob.glob(os.path.join(directory, "*.py"))
# prevent unnecessary imports
moduleList = []
for fname in fileList:
# in Python 3, rb implies bytes and not strings
f = open(fname, 'r')
lines = f.readlines()
f.close()
f = None
for line in lines:
if line.startswith("def"):
if line.split(" ")[1].startswith(targetMethod):
moduleList.append(fname)
break
for module in moduleList:
try:
pluginName = os.path.basename(module)[:-3]
if DEBUG:
print("pluginName %s" % pluginName)
plugin = pluginName
if directory not in sys.path:
sys.path.insert(0, directory)
if pluginName in self.pluginList:
idx = self.pluginList.index(pluginName)
del self.pluginList[idx]
if plugin in self.pluginInstanceDict.keys():
del self.pluginInstanceDict[plugin]
if plugin in sys.modules:
if hasattr(sys.modules[plugin], targetMethod):
if sys.version.startswith('3'):
import imp
imp.reload(sys.modules[plugin])
else:
reload(sys.modules[plugin])
else:
__import__(plugin)
if hasattr(sys.modules[plugin], targetMethod):
theCall = getattr(sys.modules[plugin], targetMethod)
self.pluginInstanceDict[plugin] = theCall(self)
self.pluginList.append(plugin)
except:
exceptionMessage += \
"Problem importing module %s\n" % plugin
exceptionMessage += "%s\n" % sys.exc_info()[0]
exceptionMessage += "%s\n" % sys.exc_info()[1]
exceptionMessage += "%s\n" % sys.exc_info()[2]
if len(exceptionMessage):
if DEBUG:
raise IOError(exceptionMessage)
if exceptions:
return len(self.pluginList), exceptionMessage
else:
return len(self.pluginList)
[docs]def main(targetMethod, directoryList):
loader = PluginLoader()
n = loader.getPlugins(targetMethod, directoryList)
print("Loaded %d plugins" % n)
for m in loader.pluginList:
print("Module %s" % m)
module = sys.modules[m]
if hasattr(module, 'MENU_TEXT'):
text = module.MENU_TEXT
else:
text = os.path.basename(module.__file__)
if text.endswith('.pyc'):
text = text[:-4]
elif text.endswith('.py'):
text = text[:-3]
print("\tMENU TEXT: %s" % text)
methods = loader.pluginInstanceDict[m].getMethods()
if not len(methods):
continue
for method in methods:
print("\t\t %s" % method)
if __name__ == "__main__":
if len(sys.argv) > 2:
targetMethod = sys.argv[1]
directoryList = sys.argv[2:len(sys.argv)]
elif len(sys.argv) > 1:
targetMethod = None
directoryList = sys.argv[1:len(sys.argv)]
else:
print("Usage: python PluginLoader.py [targetMethod] directory")
main(targetMethod, directoryList)