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
This commit is contained in:
parent
65fc1a49af
commit
c2756c3d98
neutron_lib
releasenotes/notes
@ -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
|
||||
"""
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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``.
|
Loading…
Reference in New Issue
Block a user