]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Fix issubclass() hook behavior in PluginInterface
authorRoman Podoliaka <rpodolyaka@mirantis.com>
Wed, 16 Apr 2014 10:59:33 +0000 (13:59 +0300)
committerRoman Podoliaka <rpodolyaka@mirantis.com>
Mon, 12 May 2014 18:59:12 +0000 (21:59 +0300)
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

neutron/api/extensions.py
neutron/tests/unit/test_extensions.py

index 666b2cede2e40262c202c86dfa70f4e644aed926..265249323846f404ff80e68d95cf111ef7323546 100644 (file)
@@ -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
index fc373709bbc48ffa32665dbbba57c98dd5e3aaf4..6ab310f75a6b70920aab88989a48cbe5983b2059 100644 (file)
@@ -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):