示例#1
0
    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
示例#3
0
 def test_NormalizePluginNameForModuleName_on_name_with_nonalphanum(self):
     self.assertEqual("mouf__glop_a_é",
                      NormalizePluginNameForModuleName("mouf+?glop:a/é"))
示例#4
0
 def test_NormalizePluginNameForModuleName_on_name_with_space(self):
     self.assertEqual("mouf_glop",
                      NormalizePluginNameForModuleName("mouf glop"))
示例#5
0
 def test_NormalizePluginNameForModuleName_on_empty_name(self):
     self.assertEqual("_", NormalizePluginNameForModuleName(""))
示例#6
0
 def test_NormalizePluginNameForModuleName_on_ok_name(self):
     self.assertEqual("moufGlop2",
                      NormalizePluginNameForModuleName("moufGlop2"))
示例#7
0
    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