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
This commit is contained in:
parent
76e571e18b
commit
2e70b01b28
2 changed files with 43 additions and 14 deletions
|
|
@ -54,6 +54,12 @@ class UnknownGroupError(Exception):
|
|||
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
|
||||
|
||||
|
|
|
|||
|
|
@ -151,8 +151,17 @@ class SAT(service.Service):
|
|||
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 @@ class SAT(service.Service):
|
|||
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 @@ class SAT(service.Service):
|
|||
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:
|
||||
|
|
|
|||
Loading…
Reference in a new issue