diff --git a/releasenotes/notes/expose-entry-point-properties-6f2d868d4342fc0d.yaml b/releasenotes/notes/expose-entry-point-properties-6f2d868d4342fc0d.yaml new file mode 100644 index 0000000..22d7494 --- /dev/null +++ b/releasenotes/notes/expose-entry-point-properties-6f2d868d4342fc0d.yaml @@ -0,0 +1,6 @@ +--- +features: + - | + Add `extras` and `attr` properties to the `Extension` class to + make it easier for consumers to access the underlying properties, + regardless of the version of `importlib.metadata` being used. diff --git a/stevedore/extension.py b/stevedore/extension.py index abbc5c3..2ccdc27 100644 --- a/stevedore/extension.py +++ b/stevedore/extension.py @@ -58,6 +58,27 @@ class Extension(object): match = self.entry_point.pattern.match(self.entry_point.value) return match.group('module') + @property + def extras(self): + """The 'extras' settings for the plugin.""" + # NOTE: The underlying package returns re.Match objects for + # some reason. Translate those to the matched strings, which + # seem more useful. + return [ + # Python 3.6 returns _sre.SRE_Match objects. Later + # versions of python return re.Match objects. Both types + # have a 'string' attribute containing the text that + # matched the pattern. + getattr(e, 'string', e) + for e in self.entry_point.extras + ] + + @property + def attr(self): + """The attribute of the module to be loaded.""" + match = self.entry_point.pattern.match(self.entry_point.value) + return match.group('attr') + @property def entry_point_target(self): """The module and attribute referenced by this extension's entry_point. diff --git a/stevedore/tests/test_extension.py b/stevedore/tests/test_extension.py index 8fc9149..405fb88 100644 --- a/stevedore/tests/test_extension.py +++ b/stevedore/tests/test_extension.py @@ -16,6 +16,13 @@ import operator from unittest import mock +try: + # For python 3.8 and later + import importlib.metadata as importlib_metadata +except ImportError: + # For everyone else + import importlib_metadata + from stevedore import exception from stevedore import extension from stevedore.tests import utils @@ -241,3 +248,42 @@ class TestLoadRequirementsOldSetuptools(utils.TestCase): self.em._load_one_plugin(self.mock_ep, False, (), {}, verify_requirements=False) self.mock_ep.load.assert_called_once_with() + + +class TestExtensionProperties(utils.TestCase): + + def setUp(self): + self.ext1 = extension.Extension( + 'name', + importlib_metadata.EntryPoint( + 'name', 'module.name:attribute.name [extra]', 'group_name', + ), + mock.Mock(), + None, + ) + self.ext2 = extension.Extension( + 'name', + importlib_metadata.EntryPoint( + 'name', 'module:attribute', 'group_name', + ), + mock.Mock(), + None, + ) + + def test_module_name(self): + self.assertEqual('module.name', self.ext1.module_name) + self.assertEqual('module', self.ext2.module_name) + + def test_extras(self): + self.assertEqual(['[extra]'], self.ext1.extras) + self.assertEqual([], self.ext2.extras) + + def test_attr(self): + self.assertEqual('attribute.name', self.ext1.attr) + self.assertEqual('attribute', self.ext2.attr) + + def test_entry_point_target(self): + self.assertEqual('module.name:attribute.name [extra]', + self.ext1.entry_point_target) + self.assertEqual('module:attribute', + self.ext2.entry_point_target)