NamedExtensionManager: call a callback when some names cannot be found

This will allow users to find out errors in their code that are currently
silently ignored.

Change-Id: I405511f9acc5319b1e4373be084f6a7c97556acf
This commit is contained in:
Cyril Roelandt 2016-06-24 19:37:16 +02:00
parent f33b810403
commit 6f81f6f1c1
2 changed files with 34 additions and 0 deletions

View File

@ -1,5 +1,9 @@
import logging
from .extension import ExtensionManager from .extension import ExtensionManager
LOG = logging.getLogger(__name__)
class NamedExtensionManager(ExtensionManager): class NamedExtensionManager(ExtensionManager):
"""Loads only the named extensions. """Loads only the named extensions.
@ -34,6 +38,10 @@ class NamedExtensionManager(ExtensionManager):
when this is called (when an entrypoint fails to load) are when this is called (when an entrypoint fails to load) are
(manager, entrypoint, exception) (manager, entrypoint, exception)
:type on_load_failure_callback: function :type on_load_failure_callback: function
:param on_missing_entrypoints_callback: Callback function that will be
called when one or more names cannot be found. The provided argument
will be a subset of the 'names' parameter.
:type on_missing_entrypoints_callback: function
:param verify_requirements: Use setuptools to enforce the :param verify_requirements: Use setuptools to enforce the
dependencies of the plugin(s) being loaded. Defaults to False. dependencies of the plugin(s) being loaded. Defaults to False.
:type verify_requirements: bool :type verify_requirements: bool
@ -44,6 +52,7 @@ class NamedExtensionManager(ExtensionManager):
invoke_on_load=False, invoke_args=(), invoke_kwds={}, invoke_on_load=False, invoke_args=(), invoke_kwds={},
name_order=False, propagate_map_exceptions=False, name_order=False, propagate_map_exceptions=False,
on_load_failure_callback=None, on_load_failure_callback=None,
on_missing_entrypoints_callback=None,
verify_requirements=False): verify_requirements=False):
self._init_attributes( self._init_attributes(
namespace, names, name_order=name_order, namespace, names, name_order=name_order,
@ -53,6 +62,13 @@ class NamedExtensionManager(ExtensionManager):
invoke_args, invoke_args,
invoke_kwds, invoke_kwds,
verify_requirements) verify_requirements)
missing_entrypoints = set(names) - set([e.name for e in extensions])
if missing_entrypoints:
if on_missing_entrypoints_callback:
on_missing_entrypoints_callback(missing_entrypoints)
else:
LOG.warning('Could not load %s' %
', '.join(missing_entrypoints))
self._init_plugins(extensions) self._init_plugins(extensions)
@classmethod @classmethod

View File

@ -1,8 +1,10 @@
"""Tests for failure loading callback """Tests for failure loading callback
""" """
from testtools.matchers import GreaterThan from testtools.matchers import GreaterThan
import mock
from stevedore import extension from stevedore import extension
from stevedore import named
from stevedore.tests import utils from stevedore.tests import utils
@ -23,3 +25,19 @@ class TestCallback(utils.TestCase):
for manager, entrypoint, error in errors: for manager, entrypoint, error in errors:
self.assertIs(manager, em) self.assertIs(manager, em)
self.assertIsInstance(error, (IOError, ImportError)) self.assertIsInstance(error, (IOError, ImportError))
@mock.patch('stevedore.named.NamedExtensionManager._load_plugins')
def test_missing_entrypoints_callback(self, load_fn):
errors = set()
def callback(names):
errors.update(names)
load_fn.return_value = [
extension.Extension('foo', None, None, None)
]
named.NamedExtensionManager('stevedore.test.extension',
names=['foo', 'bar'],
invoke_on_load=True,
on_missing_entrypoints_callback=callback)
self.assertEqual(errors, {'bar'})