Fix issubclass() hook behavior in PluginInterface
Currently, PluginInterface provides an issubclass() hook that returns True for issubclass(A, B) call, if all abstract methods of B (stored in B.__abstractmethods__) can be found in the A.__mro__ tuple of classes. But there is an edge case, when B doesn't have any abstract methods, which leads to issubclass(A, B) call returning True even if A and B are not related all. E.g. issubclass(NeutronPluginPLUMgridV2, NsxPlugin) returns True, while these two are different core plugins. And it gets even more trickier when superclasses are involved: e.g. SecurityGroupDbMixin is a superclass of NsxPlugin, so depending on the fact whether the python module with NsxPlugin class is imported or not, issubclass(NeutronPluginPLUMgridV2, SecurityGroupDbMixin) will return either False or True accordingly. Closes-Bug: #1308489 Change-Id: I92711a00a19b89729ccdba9cbd8a2e7a2d2868ed
This commit is contained in:
parent
43561d4e6d
commit
237f058396
@ -51,6 +51,10 @@ class PluginInterface(object):
|
||||
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
|
||||
|
@ -15,6 +15,8 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import abc
|
||||
|
||||
import mock
|
||||
import routes
|
||||
import webob
|
||||
@ -57,6 +59,47 @@ class FakePluginWithExtension(db_base_plugin_v2.NeutronDbPluginV2):
|
||||
self._log("method_to_support_foxnsox_extension", context)
|
||||
|
||||
|
||||
class PluginInterfaceTest(base.BaseTestCase):
|
||||
def test_issubclass_hook(self):
|
||||
class A(object):
|
||||
def f(self):
|
||||
pass
|
||||
|
||||
class B(extensions.PluginInterface):
|
||||
@abc.abstractmethod
|
||||
def f(self):
|
||||
pass
|
||||
|
||||
self.assertTrue(issubclass(A, B))
|
||||
|
||||
def test_issubclass_hook_class_without_abstract_methods(self):
|
||||
class A(object):
|
||||
def f(self):
|
||||
pass
|
||||
|
||||
class B(extensions.PluginInterface):
|
||||
def f(self):
|
||||
pass
|
||||
|
||||
self.assertFalse(issubclass(A, B))
|
||||
|
||||
def test_issubclass_hook_not_all_methods_implemented(self):
|
||||
class A(object):
|
||||
def f(self):
|
||||
pass
|
||||
|
||||
class B(extensions.PluginInterface):
|
||||
@abc.abstractmethod
|
||||
def f(self):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def g(self):
|
||||
pass
|
||||
|
||||
self.assertFalse(issubclass(A, B))
|
||||
|
||||
|
||||
class ResourceExtensionTest(base.BaseTestCase):
|
||||
|
||||
class ResourceExtensionController(wsgi.Controller):
|
||||
|
Loading…
x
Reference in New Issue
Block a user