Source code for lib_openmolar.common.qt4.plugin_tools.plugin_handler

#! /usr/bin/env python
# -*- coding: utf-8 -*-

###############################################################################
##                                                                           ##
##  Copyright 2010, Neil Wallace <rowinggolfer@googlemail.com>               ##
##                                                                           ##
##  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 3 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, see <http://www.gnu.org/licenses/>.    ##
##                                                                           ##
###############################################################################

import inspect
import logging
import os
import sys
import zipfile
import zipimport

from lib_openmolar.common.qt4.plugin_tools import Plugin

from PyQt4.QtCore import QResource, QString

[docs]class PluginHandler(object): ''' A class to verify and install plugins ''' #: locations of directories where plugins reside PLUGIN_DIRS = [] #: locations of directories where naked plugins reside NAKED_PLUGIN_DIRS = [] #: ACTIVE_PLUGINS = set([]) _plugins = [] _fee_scales = []
[docs] def get_pluggable_classes(self, module, target=None): ''' Args: module (module object) generates a list of all classes which are subclassed from lib_openmolar.client.Plugin in the module "module" ''' for name in dir(module): obj = getattr(module, name) ## check is this object is a class.. and that it inherits ## from Plugin.. (but is not the Plugin base class itself!) ## hence issubclass wouldn't work if inspect.isclass(obj) and Plugin in obj.mro()[1:]: try: LOGGER.debug("initiating plugin object %s"% obj) klass = obj() except Exception: # shouldn't happen!! LOGGER.exception( "Unable to instantiate Plugin %s from %s"% (obj, module)) continue if target is None or klass.TARGET == target: yield klass else: LOGGER.error("Plugin %s has target '%s' ignoring"% ( klass.name, klass.TARGET))
[docs] def get_modules(self, plugin_dir): ''' finds all modules in plugin_dir ''' sys.path.insert(0, str(plugin_dir)) for file_ in os.listdir(str(plugin_dir)): full_path = os.path.join(str(plugin_dir), file_) if file_.endswith(".py"): LOGGER.debug("found module '%s'"% full_path) if plugin_dir in self.NAKED_PLUGIN_DIRS: LOGGER.info("NAKED PLUGIN FOUND '%s'"% full_path) module = file_.replace('.py','') mod = __import__(module) yield mod else: LOGGER.info( 'IGNORING because %s is not a known store for naked plugins'% plugin_dir) elif zipfile.is_zipfile(full_path): LOGGER.info("POSSIBLE PLUGIN FOUND '%s'"% full_path) module = file_.replace('.zip','') try: z = zipimport.zipimporter(full_path) mod = z.load_module(module) yield mod except (zipimport.ZipImportError, zipfile.BadZipfile) as e: LOGGER.exception ("incompatible plugin '%s'"% full_path)
[docs] def get_plugins(self, plugin_dir, target=None): ''' peruses a directory and finds all plugins ''' for mod in self.get_modules(plugin_dir): plugins = self.get_pluggable_classes(mod, target) for plugin in plugins: plugin.set_unique_id(QString( "%s:%s"% (mod.__name__, os.path.abspath(str(plugin_dir))))) self._plugins.append(plugin)
[docs] def load_plugins(self, target=None): ''' this function is called by the client application to load plugins ''' LOGGER.info ("loading plugins...") for plugin_dir in self.PLUGIN_DIRS: LOGGER.info ("="*80) LOGGER.info ("looking for plugins in directory %s"% plugin_dir) LOGGER.info ("="*80) try: self.get_plugins(plugin_dir, target) except Exception as e: LOGGER.exception ("Exception loading plugin") LOGGER.info("%d plugin(s) loaded"% len(self.plugins))
[docs] def activate_plugins(self): ''' iterates over the loaded plugins and activates them. ''' LOGGER.info ("="*80) LOGGER.info("Activating plugins") LOGGER.info ("="*80) i = 0 for plugin in self.plugins: if plugin.unique_id in self.ACTIVE_PLUGINS: self.activate_plugin(plugin) i += 1 else: LOGGER.debug(".. NOT ACTIVATING %s"% plugin.unique_id) LOGGER.info("%d plugin(s) activated"% i)
[docs] def de_activate_plugins(self): ''' iterates over the activated plugins and de-activates them. ''' LOGGER.info ("="*80) LOGGER.info("De-Activating plugins") LOGGER.info ("="*80) i = 0 for plugin in self.plugins: if plugin.is_active: self.deactivate_plugin(plugin) i += 1 LOGGER.info("%d plugin(s) de-activated"% i)
[docs] def activate_plugin(self, plugin): LOGGER.info("..Activating %s '%s'"% (plugin.__module__, plugin.name)) try: if plugin.TYPE == plugin.FEE_SCALE: self.install_fee_scale(plugin) LOGGER.debug("setting up plugin %s"% plugin) plugin.setup_plugin() plugin.is_active = True except Exception, e: LOGGER.exception( "Exception during plugin.setup_plugin '%s'"% plugin.name) self.ACTIVE_PLUGINS.add(plugin.unique_id)
[docs] def deactivate_plugin(self, plugin): LOGGER.info("..Deactivating %s '%s'"% (plugin.__module__, plugin.name)) if plugin.TYPE == plugin.FEE_SCALE: self.remove_fee_scale(plugin) try: LOGGER.debug("calling teardoown plugin %s"% plugin) plugin.tear_down() except Exception, e: LOGGER.exception( "Exception during plugin.teardown '%s'"% plugin.name) self.ACTIVE_PLUGINS.remove(plugin.unique_id) plugin.is_active = False
@property
[docs] def plugins(self): ''' a list of all plugins (of type BasePlugin) ''' return self._plugins
[docs] def install_fee_scale(self, fee_scale): ''' installs a fee_scale (of type BasePlugin) ''' LOGGER.info ("installing fee_scale %s"% fee_scale) self._fee_scales.append(fee_scale)
[docs] def remove_fee_scale(self, fee_scale): ''' removes a fee_scale (of type BasePlugin) ''' LOGGER.info ("removing fee_scale %s"% fee_scale) self._fee_scales.remove(fee_scale)
@property
[docs] def fee_scales(self): ''' a list of all fee_scales installed (fee_scale = a type of BasePlugin) ''' return sorted(self._fee_scales)
if __name__ == "__main__": import lib_openmolar.client logging.basicConfig(level = logging.DEBUG) ph = PluginHandler() ph.PLUGIN_DIRS = [ "/home/neil/openmolar/hg_openmolar/plugins/src/import_om1", #"/home/neil/openmolar/hg_openmolar/plugins/src" ] ph.NAKED_PLUGIN_DIRS = [ "/home/neil/openmolar/hg_openmolar/plugins/src/import_om1", ] ph.ACTIVE_PLUGINS = set([QString( "import_om1_plugin:/home/neil/openmolar/hg_openmolar/plugins/src/import_om1" )]) ph.load_plugins("admin") ph.activate_plugins() ph.de_activate_plugins()