Source code for tuiview.pluginmanager


"""
Contains the PluginManager class.
"""
# This file is part of 'TuiView' - a simple Raster viewer
# Copyright (C) 2012  Sam Gillingham
#
# 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.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

from __future__ import print_function
import os
import sys
import imp

PLUGINS_ENV = 'TUIVIEW_PLUGINS_PATH'
PLUGINS_SUBDIR = 'plugins'

PLUGIN_NAME_FN = 'name'
PLUGIN_ACTION_FN = 'action'
PLUGIN_AUTHOR_FN = 'author'
PLUGIN_DESC_FN = 'description'

PLUGIN_REQUIRED_FNS = (PLUGIN_NAME_FN, PLUGIN_ACTION_FN, PLUGIN_AUTHOR_FN, 
                        PLUGIN_DESC_FN)

PLUGIN_ACTION_INIT = 0
PLUGIN_ACTION_NEWVIEWER = 1
PLUGIN_ACTION_NEWQUERY = 2

[docs]class PluginManager(object): def __init__(self): self.plugins = {} self.pysuffixes = self.getSuffixes() self.pluginNameIndex = 1
[docs] def callAction(self, actioncode, param): """ Calls PLUGIN_ACTION_FN on each of the loaded plugins with the supplit PLUGIN_ACTION_* constant and a parameter """ for name in self.plugins.keys(): mod = self.plugins[name] try: action = getattr(mod, PLUGIN_ACTION_FN) action(actioncode, param) except Exception as e: self.printTraceback(mod)
[docs] @staticmethod def printTraceback(name): import traceback print('Exception raised when calling plugin %s:' % name) (ttype, value, tb) = sys.exc_info() stack = traceback.extract_tb(tb) trace = '\n'.join(traceback.format_list(stack)) print(trace, ttype.__name__, ':', value)
[docs] @staticmethod def getSuffixes(): suffixes = None for (suffix, mode, type) in imp.get_suffixes(): if type == imp.PY_SOURCE: suffixes = (suffix, mode, type) break if suffixes is None: raise ValueError('Unable to find suffix for Python source') return suffixes
[docs] def loadPlugins(self): """ Order is: 1. If there is a plugins directory under where we are running 2. Any directories listed in os.getenv(PLUGINS_ENV) 3. Under ~/.tuiview/plugins Reads any Python file that has the required entries """ # check where we are running appDir = os.path.dirname(os.path.abspath(sys.argv[0])) subdir = os.path.join(appDir, PLUGINS_SUBDIR) if os.path.isdir(subdir): self.loadPluginsFromDir(subdir) # now do the environment variable pluginPath = os.getenv(PLUGINS_ENV) if pluginPath is not None: for subdir in pluginPath.split(os.pathsep): if os.path.isdir(subdir): self.loadPluginsFromDir(subdir) # now home directory homeDir = os.path.expanduser('~') subdir = os.path.join(homeDir, '.tuiview', PLUGINS_SUBDIR) if os.path.isdir(subdir): self.loadPluginsFromDir(subdir)
[docs] def loadPluginsFromDir(self, directory): """ Attempt to load all the files in the given directory that match the Python suffix (.py) """ for fname in os.listdir(directory): if fname.endswith(self.pysuffixes[0]): path = os.path.join(directory, fname) self.loadPluginFromPath(path)
[docs] def loadPluginFromPath(self, path): """ Try loading a plugin given a path to it. Module put into self.plugins with the key being the name the module describes itself as """ try: fileobj = open(path, self.pysuffixes[1]) # make up a name to keep Python happy name = 'tuiview.plugin%d' % self.pluginNameIndex self.pluginNameIndex += 1 try: mod = imp.load_module(name, fileobj, path, self.pysuffixes) # all required fns? for fn in PLUGIN_REQUIRED_FNS: if not hasattr(mod, fn): msg = 'Plugin %s does not have required functions' print(msg % path) return # must be ok. Get name and save it try: name = getattr(mod, PLUGIN_NAME_FN) modname = name() except Exception as e: self.printTraceback(modname) return self.plugins[modname] = mod print('loaded plugin %s' % modname) except ImportError as e: print('Unable to import %s' % path) print(str(e)) finally: fileobj.close() except IOError: print('Unable to read %s' % path)