From c2756c3d988dc930376125a72359703de6417a6b Mon Sep 17 00:00:00 2001 From: Boden R Date: Mon, 23 Jan 2017 07:32:28 -0700 Subject: [PATCH] Formalize base service classes The PluginInterface and WorkerSupportServiceMixin classes were rehomed to neutron-lib recently [1] and included a private version of the respective classes. Based on the existing usages of such [2][3], this patch: - Renames WorkerSupportServiceMixin as WorkerBase making it public for consumption [2]. - Collapses _PluginInterface into ServicePluginBase making the definition more compact and understandable. - Formalizes the use of ServicePluginBase by updating the docstring in ExtensionDescriptor to indicate an instance of ServicePluginBase is used for plugin interfaces. This is kosher as existing uses today all return extension plugin interfaces that are subclasses of ServicePluginBase and not PluginInterface. Also see related neutron consumption patch [4]. [1] https://review.openstack.org/412519/ [2] http://codesearch.openstack.org/?q=WorkerSupportServiceMixin [3] http://codesearch.openstack.org/?q=PluginInterface [4] https://review.openstack.org/#/c/441129 Change-Id: I722252b845a4396f1b193459b22e4352c93241e6 --- neutron_lib/api/extensions.py | 3 +- neutron_lib/services/base.py | 51 +++++++++---------- neutron_lib/tests/unit/services/test_base.py | 21 +++++--- ...blic-service-classes-e52d7c79a075b799.yaml | 10 ++++ 4 files changed, 49 insertions(+), 36 deletions(-) create mode 100644 releasenotes/notes/public-service-classes-e52d7c79a075b799.yaml diff --git a/neutron_lib/api/extensions.py b/neutron_lib/api/extensions.py index ccd06762f..246d5505f 100644 --- a/neutron_lib/api/extensions.py +++ b/neutron_lib/api/extensions.py @@ -106,7 +106,8 @@ class ExtensionDescriptor(object): def get_plugin_interface(self): """Returns an abstract class which defines contract for the plugin. - The abstract class should inherit from extensions.PluginInterface, + The abstract class should inherit from + neutron_lib.services.base.ServicePluginBase. Methods in this abstract class should be decorated as abstractmethod """ diff --git a/neutron_lib/services/base.py b/neutron_lib/services/base.py index e6bd2fe0b..5c92cf867 100644 --- a/neutron_lib/services/base.py +++ b/neutron_lib/services/base.py @@ -15,32 +15,7 @@ import abc import six -@six.add_metaclass(abc.ABCMeta) -class _PluginInterface(object): - - @classmethod - def __subclasshook__(cls, klass): - """Checking plugin class. - - The __subclasshook__ method is a class method - that will be called every time a class is tested - using issubclass(klass, _PluginInterface). - In that case, it will check that every method - marked with the abstractmethod decorator is - provided by the plugin class. - """ - - if not cls.__abstractmethods__: - return NotImplemented - - for method in cls.__abstractmethods__: - if any(method in base.__dict__ for base in klass.__mro__): - continue - return NotImplemented - return True - - -class _WorkerSupportServiceMixin(object): +class WorkerBase(object): @property def _workers(self): @@ -74,11 +49,31 @@ class _WorkerSupportServiceMixin(object): @six.add_metaclass(abc.ABCMeta) -class ServicePluginBase(_PluginInterface, - _WorkerSupportServiceMixin): +class ServicePluginBase(WorkerBase): """Define base interface for any Advanced Service plugin.""" supported_extension_aliases = [] + @classmethod + def __subclasshook__(cls, klass): + """Checking plugin class. + + The __subclasshook__ method is a class method + that will be called every time a class is tested + using issubclass(klass, ServicePluginBase). + In that case, it will check that every method + marked with the abstractmethod decorator is + provided by the plugin class. + """ + + if not cls.__abstractmethods__: + return NotImplemented + + for method in cls.__abstractmethods__: + if any(method in base.__dict__ for base in klass.__mro__): + continue + return NotImplemented + return True + @abc.abstractmethod def get_plugin_type(self): """Return one of predefined service types. diff --git a/neutron_lib/tests/unit/services/test_base.py b/neutron_lib/tests/unit/services/test_base.py index d73c67efe..97d3dc88d 100644 --- a/neutron_lib/tests/unit/services/test_base.py +++ b/neutron_lib/tests/unit/services/test_base.py @@ -16,7 +16,7 @@ from neutron_lib.services import base from neutron_lib.tests import _base as test_base -class _Worker(base._WorkerSupportServiceMixin): +class _Worker(base.WorkerBase): pass @@ -43,14 +43,21 @@ class Test_WorkerSupportServiceMixin(test_base.BaseTestCase): self.assertSequenceEqual(workers, self.worker.get_workers()) -class Test_PluginInterface(test_base.BaseTestCase): +class TestPluginInterface(test_base.BaseTestCase): + + class ServicePluginStub(base.ServicePluginBase): + def get_plugin_type(self): + pass + + def get_plugin_description(self): + pass def test_issubclass_hook(self): - class A(object): + class A(TestPluginInterface.ServicePluginStub): def f(self): pass - class B(base._PluginInterface): + class B(base.ServicePluginBase): @abc.abstractmethod def f(self): pass @@ -62,18 +69,18 @@ class Test_PluginInterface(test_base.BaseTestCase): def f(self): pass - class B(base._PluginInterface): + class B(base.ServicePluginBase): def f(self): pass self.assertFalse(issubclass(A, B)) def test_issubclass_hook_not_all_methods_implemented(self): - class A(object): + class A(TestPluginInterface.ServicePluginStub): def f(self): pass - class B(base._PluginInterface): + class B(base.ServicePluginBase): @abc.abstractmethod def f(self): pass diff --git a/releasenotes/notes/public-service-classes-e52d7c79a075b799.yaml b/releasenotes/notes/public-service-classes-e52d7c79a075b799.yaml new file mode 100644 index 000000000..cfb3e4ce0 --- /dev/null +++ b/releasenotes/notes/public-service-classes-e52d7c79a075b799.yaml @@ -0,0 +1,10 @@ +--- +features: + - The ``neutron_lib.api.extensions.ExtensionDescriptor`` class's + ``get_plugin_interface`` method now formally only supports + ``neutron_lib.services.base.ServicePluginBase``. This change reflects + the existing usage by consumers as almost all are returning + instances of ``ServicePluginBase`` already. + - The class ``WorkerBase`` is now available and provides the same + functionality that's provided by + ``neutron.worker.WorkerSupportServiceMixin``.