def loadPlugins(self, callback=None, callback_after=None): """ Load the candidate plugins that have been identified through a previous call to locatePlugins. For each plugin candidate look for its category, load it and store it in the appropriate slot of the ``category_mapping``. You can specify 2 callbacks: callback, and callback_after. If either of these are passed a function, (in the case of callback), it will get called before each plugin load attempt and (for callback_after), after each attempt. The ``plugin_info`` instance is passed as an argument to each callback. This is meant to facilitate code that needs to run for each plugin, such as adding the directory it resides in to sys.path (so imports of other files in the plugin's directory work correctly). You can use callback_after to remove anything you added to the path. """ # print "%s.loadPlugins" % self.__class__ if not hasattr(self, '_candidates'): raise ValueError("locatePlugins must be called before loadPlugins") processed_plugins = [] for candidate_infofile, candidate_filepath, plugin_info in self._candidates: # make sure to attribute a unique module name to the one # that is about to be loaded plugin_module_name_template = NormalizePluginNameForModuleName( "yapsy_loaded_plugin_" + plugin_info.name) + "_%d" for plugin_name_suffix in range(len(sys.modules)): plugin_module_name = plugin_module_name_template % plugin_name_suffix if plugin_module_name not in sys.modules: break # tolerance on the presence (or not) of the py extensions if candidate_filepath.endswith(".py"): candidate_filepath = candidate_filepath[:-3] # if a callback exists, call it before attempting to load # the plugin so that a message can be displayed to the # user if callback is not None: callback(plugin_info) # cover the case when the __init__ of a package has been # explicitely indicated if "__init__" in os.path.basename(candidate_filepath): candidate_filepath = os.path.dirname(candidate_filepath) try: candidate_module = PluginManager._importModule( plugin_module_name, candidate_filepath) except Exception: exc_info = sys.exc_info() log.error("Unable to import plugin: %s" % candidate_filepath, exc_info=exc_info) plugin_info.error = exc_info processed_plugins.append(plugin_info) continue processed_plugins.append(plugin_info) if "__init__" in os.path.basename(candidate_filepath): sys.path.remove(plugin_info.path) # now try to find and initialise the first subclass of the correct plugin interface last_failed_attempt_message = None for element, element_name in ((getattr(candidate_module, name), name) for name in dir(candidate_module)): plugin_info_reference = None for category_name in self.categories_interfaces: try: is_correct_subclass = issubclass( element, self.categories_interfaces[category_name]) except Exception: exc_info = sys.exc_info() log.debug( "correct subclass tests failed for: %s in %s" % (element_name, candidate_filepath), exc_info=exc_info) continue if is_correct_subclass and element is not self.categories_interfaces[ category_name]: current_category = category_name if candidate_infofile not in self._category_file_mapping[ current_category]: # we found a new plugin: initialise it and search for the next one if not plugin_info_reference: try: plugin_info.plugin_object = self.instanciateElementWithImportInfo( element, element_name, plugin_module_name, candidate_filepath) plugin_info_reference = plugin_info except Exception: exc_info = sys.exc_info() last_failed_attempt_message = "Unable to create plugin object: %s" % candidate_filepath log.debug(last_failed_attempt_message, exc_info=exc_info) plugin_info.error = exc_info break # If it didn't work once it wont again else: last_failed_attempt_message = None plugin_info.categories.append(current_category) self.category_mapping[current_category].append( plugin_info_reference) self._category_file_mapping[ current_category].append(candidate_infofile) #Everything is loaded and instantiated for this plugin now if callback_after is not None: callback_after(plugin_info) else: if last_failed_attempt_message: log.error(last_failed_attempt_message, exc_info=plugin_info.error) # Remove candidates list since we don't need them any more and # don't need to take up the space delattr(self, '_candidates') return processed_plugins
def loadPlugins(self, callback=None): """ Load the candidate plugins that have been identified through a previous call to locatePlugins. For each plugin candidate look for its category, load it and store it in the appropriate slot of the ``category_mapping``. If a callback function is specified, call it before every load attempt. The ``plugin_info`` instance is passed as an argument to the callback. """ # print "%s.loadPlugins" % self.__class__ if not hasattr(self, '_candidates'): raise ValueError("locatePlugins must be called before loadPlugins") processed_plugins = [] for candidate_infofile, candidate_filepath, plugin_info in self._candidates: # make sure to attribute a unique module name to the one # that is about to be loaded plugin_module_name_template = NormalizePluginNameForModuleName("yapsy_loaded_plugin_" + plugin_info.name) + "_%d" for plugin_name_suffix in range(len(sys.modules)): plugin_module_name = plugin_module_name_template % plugin_name_suffix if plugin_module_name not in sys.modules: break # tolerance on the presence (or not) of the py extensions if candidate_filepath.endswith(".py"): candidate_filepath = candidate_filepath[:-3] # if a callback exists, call it before attempting to load # the plugin so that a message can be displayed to the # user if callback is not None: callback(plugin_info) # cover the case when the __init__ of a package has been # explicitely indicated if "__init__" in os.path.basename(candidate_filepath): candidate_filepath = os.path.dirname(candidate_filepath) try: # use imp to correctly load the plugin as a module if os.path.isdir(candidate_filepath): candidate_module = imp.load_module(plugin_module_name,None,candidate_filepath,("py","r",imp.PKG_DIRECTORY)) else: with open(candidate_filepath+".py","r") as plugin_file: candidate_module = imp.load_module(plugin_module_name,plugin_file,candidate_filepath+".py",("py","r",imp.PY_SOURCE)) except Exception: exc_info = sys.exc_info() log.error("Unable to import plugin: %s" % candidate_filepath, exc_info=exc_info) plugin_info.error = exc_info processed_plugins.append(plugin_info) continue processed_plugins.append(plugin_info) if "__init__" in os.path.basename(candidate_filepath): sys.path.remove(plugin_info.path) # now try to find and initialise the first subclass of the correct plugin interface for element in (getattr(candidate_module,name) for name in dir(candidate_module)): plugin_info_reference = None for category_name in self.categories_interfaces: try: is_correct_subclass = issubclass(element, self.categories_interfaces[category_name]) except Exception: continue if is_correct_subclass and element is not self.categories_interfaces[category_name]: current_category = category_name if candidate_infofile not in self._category_file_mapping[current_category]: # we found a new plugin: initialise it and search for the next one if not plugin_info_reference: try: plugin_info.plugin_object = self.instanciateElement(element) plugin_info_reference = plugin_info except Exception: exc_info = sys.exc_info() log.error("Unable to create plugin object: %s" % candidate_filepath, exc_info=exc_info) plugin_info.error = exc_info break # If it didn't work once it wont again plugin_info.categories.append(current_category) self.category_mapping[current_category].append(plugin_info_reference) self._category_file_mapping[current_category].append(candidate_infofile) # Remove candidates list since we don't need them any more and # don't need to take up the space delattr(self, '_candidates') return processed_plugins
def test_NormalizePluginNameForModuleName_on_name_with_nonalphanum(self): self.assertEqual("mouf__glop_a_é", NormalizePluginNameForModuleName("mouf+?glop:a/é"))
def test_NormalizePluginNameForModuleName_on_name_with_space(self): self.assertEqual("mouf_glop", NormalizePluginNameForModuleName("mouf glop"))
def test_NormalizePluginNameForModuleName_on_empty_name(self): self.assertEqual("_", NormalizePluginNameForModuleName(""))
def test_NormalizePluginNameForModuleName_on_ok_name(self): self.assertEqual("moufGlop2", NormalizePluginNameForModuleName("moufGlop2"))
def loadPlugins(self, callback=None): if not hasattr(self, '_candidates'): raise ValueError("locatePlugins must be called before loadPlugins") sys.path.extend(self.getPluginLocator().plugins_places) processed_plugins = [] for candidate_infofile, candidate_filepath, plugin_info in self._candidates: # make sure to attribute a unique module name to the one # that is about to be loaded plugin_module_name_template = NormalizePluginNameForModuleName( "yapsy_loaded_plugin_" + plugin_info.name) + "_%d" for plugin_name_suffix in range(len(sys.modules)): plugin_module_name = plugin_module_name_template % plugin_name_suffix if plugin_module_name not in sys.modules: break # tolerance on the presence (or not) of the py extensions if candidate_filepath.endswith(".py"): candidate_filepath = candidate_filepath[:-3] # if a callback exists, call it before attempting to load # the plugin so that a message can be displayed to the # user if callback is not None: callback(plugin_info) # cover the case when the __init__ of a package has been # explicitly indicated if "__init__" in os.path.basename(candidate_filepath): candidate_filepath = os.path.dirname(candidate_filepath) try: # use imp to correctly load the plugin as a module if os.path.isdir(candidate_filepath): candidate_module = imp.load_module( plugin_module_name, None, candidate_filepath, ("py", "r", imp.PKG_DIRECTORY)) else: with open(candidate_filepath + ".py", "r") as plugin_file: candidate_module = imp.load_module( plugin_module_name, plugin_file, candidate_filepath + ".py", ("py", "r", imp.PY_SOURCE)) except Exception: exc_info = sys.exc_info() log.error("Unable to import plugin: %s" % candidate_filepath, exc_info=exc_info) plugin_info.error = exc_info processed_plugins.append(plugin_info) continue processed_plugins.append(plugin_info) if "__init__" in os.path.basename(candidate_filepath): sys.path.remove(plugin_info.path) # now try to find and initialise the first subclass of the correct plugin interface for element in (getattr(candidate_module, name) for name in dir(candidate_module)): plugin_info_reference = None for category_name in self.categories_interfaces: try: is_correct_subclass = issubclass( element, self.categories_interfaces[category_name]) except Exception: continue if is_correct_subclass and element is not self.categories_interfaces[ category_name]: current_category = category_name if candidate_infofile not in self._category_file_mapping[ current_category]: # we found a new plugin: initialise it and search for the next one plugins = self.config.get('plugins', {}) plugin_mode = plugins.get('mode', 'blacklist') if plugin_mode == 'whitelist' and plugin_info.name not in plugins.get( current_category, []): break elif plugin_mode == 'blacklist' and plugin_info.name in plugins.get( current_category, []): break if not plugin_info_reference: try: plugin_constructer_args = self.config.get( 'plugin_config', {}).get(current_category, {}).get(plugin_info.name, {}) if isinstance(plugin_constructer_args, (list, set)): plugin_info.plugin_object = element( *plugin_constructer_args) elif isinstance(plugin_constructer_args, dict): plugin_info.plugin_object = element( **plugin_constructer_args) else: plugin_info.plugin_object = element() plugin_info_reference = plugin_info except Exception: exc_info = sys.exc_info() log.error( "Unable to create plugin object: {}". format(candidate_filepath), exc_info=exc_info) plugin_info.error = exc_info break # If it didn't work once it wont again plugin_info.categories.append(current_category) self.category_mapping[current_category].append( plugin_info_reference) self._category_file_mapping[ current_category].append(candidate_infofile) # Remove candidates list since we don't need them any more and # don't need to take up the space delattr(self, '_candidates') # Sort Plugins for category_name, plugin_infos in self.category_mapping.items(): plugin_names = self.config.get('plugin_order', {}).get(category_name, []) plugin_rankings = { plugin_name: plugin_ranking for plugin_name, plugin_ranking in zip( plugin_names, range(0, len(plugin_names))) } plugin_infos.sort(key=lambda plugin_info: plugin_rankings.get( plugin_info.name, len(plugin_names) + 1)) return processed_plugins