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
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
# License for the specific language governing permissions and limitations
# under the License.
+import abc
+
import mock
import routes
import webob
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):