From 2de192bb4621601f75172378340be057b9673554 Mon Sep 17 00:00:00 2001 From: Deepak N Date: Tue, 19 Jul 2011 11:25:31 +0530 Subject: [PATCH] Deepak/Vinkesh | Added an base abstract class which can be inherited by PluginInterface class which defines the contract expected by extension. --- quantum/common/extensions.py | 40 +++++++++++++++++++++++++++++------ tests/unit/test_extensions.py | 22 ++++++++++++++++--- 2 files changed, 52 insertions(+), 10 deletions(-) diff --git a/quantum/common/extensions.py b/quantum/common/extensions.py index 1d9d38bbb..5d24a3d81 100644 --- a/quantum/common/extensions.py +++ b/quantum/common/extensions.py @@ -23,15 +23,36 @@ import routes import logging import webob.dec import webob.exc +from gettext import gettext as _ +from abc import ABCMeta, abstractmethod from quantum.manager import QuantumManager from quantum.common import exceptions from quantum.common import wsgi -from gettext import gettext as _ LOG = logging.getLogger('quantum.common.extensions') +class PluginInterface(object): + __metaclass__ = ABCMeta + + @classmethod + def __subclasshook__(cls, klass): + """ + The __subclasshook__ method is a class method + that will be called everytime 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. + """ + for method in cls.__abstractmethods__: + if any(method in base.__dict__ for base in klass.__mro__): + continue + return NotImplemented + return True + + class ExtensionDescriptor(object): """Base class that defines the contract for extensions. @@ -108,6 +129,14 @@ class ExtensionDescriptor(object): request_exts = [] return request_exts + def get_plugin_interface(self): + """ + Returns an abstract class which defines contract for the plugin. + The abstract class should inherit from extesnions.PluginInterface, + Methods in this abstract class should be decorated as abstractmethod + """ + return None + class ActionExtensionController(wsgi.Controller): @@ -363,13 +392,10 @@ class ExtensionManager(object): self.plugin.supports_extension(extension)) def _plugin_implements_interface(self, extension): - if not hasattr(extension, "get_plugin_interface"): + if(not hasattr(extension, "get_plugin_interface") or + extension.get_plugin_interface() is None): return True - interface = extension.get_plugin_interface() - expected_methods = self._get_public_methods(interface) - implemented_methods = self._get_public_methods(self.plugin.__class__) - missing_methods = set(expected_methods) - set(implemented_methods) - return not missing_methods + return isinstance(self.plugin, extension.get_plugin_interface()) def _get_public_methods(self, klass): return filter(lambda name: not(name.startswith("_")), diff --git a/tests/unit/test_extensions.py b/tests/unit/test_extensions.py index 591a49416..4472d2377 100644 --- a/tests/unit/test_extensions.py +++ b/tests/unit/test_extensions.py @@ -18,6 +18,7 @@ import unittest import routes import os.path from tests.unit import BaseTest +from abc import abstractmethod from webtest import TestApp from quantum.common import extensions @@ -104,15 +105,16 @@ class StubPlugin(object): class ExtensionExpectingPluginInterface(StubExtension): """ This extension expects plugin to implement all the methods defined - in PluginInterface + in StubPluginInterface """ def get_plugin_interface(self): - return PluginInterface + return StubPluginInterface -class PluginInterface(object): +class StubPluginInterface(extensions.PluginInterface): + @abstractmethod def get_foo(self, bar=None): pass @@ -207,6 +209,20 @@ class ExtensionManagerTest(unittest.TestCase): self.assertTrue("e1" in self.ext_mgr.extensions) + def test_extensions_without_need_for__plugin_interface_are_loaded(self): + class ExtensionWithNoNeedForPluginInterface(StubExtension): + """ + This Extension does not need any plugin interface. + This will work with any plugin implementing QuantumPluginBase + """ + def get_plugin_interface(self): + return None + + self.ext_mgr.plugin = StubPlugin(supported_extensions=["e1"]) + self.ext_mgr.add_extension(ExtensionWithNoNeedForPluginInterface("e1")) + + self.assertTrue("e1" in self.ext_mgr.extensions) + class ActionExtensionTest(unittest.TestCase): -- 2.45.2