# HG changeset patch # User Goffi # Date 1443542063 -7200 # Node ID c9ef16de3f136e27cbe24e052dc68264170ea4f9 # Parent a5e0393a06cd4763fa889c1d630d6c13cd90f53a core: more robust plugins loading: - avoid stopping loading remaining plugins when a plugin raise an error - new error exceptions.MissingModule allows to detect a missing third party module, and to give instructions to get it - error during instanciation are catched too diff -r a5e0393a06cd -r c9ef16de3f13 src/core/exceptions.py --- a/src/core/exceptions.py Tue Sep 29 17:54:22 2015 +0200 +++ b/src/core/exceptions.py Tue Sep 29 17:54:23 2015 +0200 @@ -54,6 +54,12 @@ pass +class MissingModule(Exception): + # Used to indicate when a plugin dependence is not found + # it's nice to indicate when to find the dependence in argument string + pass + + class NotFound(Exception): pass diff -r a5e0393a06cd -r c9ef16de3f13 src/core/sat_main.py --- a/src/core/sat_main.py Tue Sep 29 17:54:22 2015 +0200 +++ b/src/core/sat_main.py Tue Sep 29 17:54:23 2015 +0200 @@ -151,8 +151,17 @@ plugin_path = 'sat.plugins.' + plug try: __import__(plugin_path) - except ImportError as e: - log.error(_(u"Can't import plugin [%(path)s]: %(error)s") % {'path': plugin_path, 'error':e}) + except exceptions.MissingModule as e: + try: + del sys.modules[plugin_path] + except KeyError: + pass + log.warning(u"Can't import plugin [{path}] because of an unavailale third party module:\n{msg}".format( + path=plugin_path, msg=e)) + continue + except Exception as e: + import traceback + log.error(_(u"Can't import plugin [{path}]:\n{error}").format(path=plugin_path, error=traceback.format_exc())) continue mod = sys.modules[plugin_path] plugin_info = mod.PLUGIN_INFO @@ -162,29 +171,33 @@ continue plugins_to_import[import_name] = (plugin_path, mod, plugin_info) while True: - self._import_plugins_from_dict(plugins_to_import) + try: + self._import_plugins_from_dict(plugins_to_import) + except ImportError: + pass if not plugins_to_import: break def _import_plugins_from_dict(self, plugins_to_import, import_name=None, optional=False): """Recursively import and their dependencies in the right order - @param plugins_to_import: dict where key=import_name and values= (plugin_path, module, plugin_info) - @param import_name: name of the plugin to import as found in PLUGIN_INFO['import_name'] - @param optional: if False and plugin is not found, an ImportError exception is raised + @param plugins_to_import(dict): key=import_name and values=(plugin_path, module, plugin_info) + @param import_name(unicode, None): name of the plugin to import as found in PLUGIN_INFO['import_name'] + @param optional(bool): if False and plugin is not found, an ImportError exception is raised """ if import_name in self.plugins: - log.debug(u'Plugin [%s] already imported, passing' % import_name) + log.debug(u'Plugin {} already imported, passing'.format(import_name)) return if not import_name: import_name, (plugin_path, mod, plugin_info) = plugins_to_import.popitem() else: if not import_name in plugins_to_import: if optional: - log.warning(_(u"Recommended plugin not found: %s") % import_name) + log.warning(_(u"Recommended plugin not found: {}").format(import_name)) return - log.error(_(u"Dependency not found: %s") % import_name) - raise ImportError(_('Dependency plugin not found: [%s]') % import_name) + msg = u"Dependency not found: {}".format(import_name) + log.error(msg) + raise ImportError(msg) plugin_path, mod, plugin_info = plugins_to_import.pop(import_name) dependencies = plugin_info.setdefault("dependencies", []) recommendations = plugin_info.setdefault("recommendations", []) @@ -194,10 +207,20 @@ try: self._import_plugins_from_dict(plugins_to_import, to_import, to_import not in dependencies) except ImportError as e: - log.error(_(u"Can't import plugin %(name)s: %(error)s") % {'name':plugin_info['name'], 'error':e}) - return - log.info(_("importing plugin: %s") % plugin_info['name']) - self.plugins[import_name] = getattr(mod, plugin_info['main'])(self) + log.warning(_(u"Can't import plugin {name}: {error}").format(name=plugin_info['name'], error=e)) + if optional: + return + raise e + log.info("importing plugin: {}".format(plugin_info['name'])) + # we instanciate the plugin here + try: + self.plugins[import_name] = getattr(mod, plugin_info['main'])(self) + except Exception as e: + log.warning(u'Error while loading plugin "{name}", ignoring it: {error}' + .format(name=plugin_info['name'], error=e)) + if optional: + return + raise ImportError(u"Error during initiation") if 'handler' in plugin_info and plugin_info['handler'] == 'yes': self.plugins[import_name].is_handler = True else: