diff --git a/ipalib/plugable.py b/ipalib/plugable.py index 32cbe0334..cafb8c506 100644 --- a/ipalib/plugable.py +++ b/ipalib/plugable.py @@ -49,16 +49,27 @@ class Plugin(object): Base class for all plugins. """ - def __init__(self, api): - self.__api = api + __api = None def __get_api(self): """ - Returns the plugable.API object this plugin has been instatiated in. + Returns the plugable.API instance passed to Plugin.finalize(), or + or returns None if finalize() has not yet been called. """ return self.__api api = property(__get_api) + def finalize(self, api): + """ + After all the plugins are instantiated, the plugable.API calls this + method, passing itself as the only argument. This is where plugins + should check that other plugins they depend upon have actually be + loaded. + """ + assert self.__api is None, 'finalize() can only be called once' + assert api is not None, 'finalize() argument cannot be None' + self.__api = api + def __get_name(self): """ Returns the class name of this instance. @@ -280,14 +291,18 @@ class Registrar(object): class API(ReadOnly): def __init__(self, registrar): + object.__setattr__(self, '_API__plugins', []) for (base, plugins) in registrar: ns = NameSpace(self.__plugin_iter(base, plugins)) assert not hasattr(self, base.__name__) object.__setattr__(self, base.__name__, ns) + for plugin in self.__plugins: + plugin.finalize(self) + assert plugin.api is self def __plugin_iter(self, base, plugins): assert issubclass(base.proxy, Proxy) for cls in plugins: - plugin = cls(self) - assert plugin.api is self + plugin = cls() + self.__plugins.append(plugin) yield base.proxy(plugin) diff --git a/ipalib/tests/test_plugable.py b/ipalib/tests/test_plugable.py index f5d469af2..27841e2e2 100644 --- a/ipalib/tests/test_plugable.py +++ b/ipalib/tests/test_plugable.py @@ -43,17 +43,25 @@ def test_from_cli(): def test_Plugin(): api = 'the api instance' - p = plugable.Plugin(api) - assert read_only(p, 'api') is api + p = plugable.Plugin() assert read_only(p, 'name') == 'Plugin' assert repr(p) == '%s.Plugin()' % plugable.__name__ + assert read_only(p, 'api') is None + raises(AssertionError, p.finalize, None) + p.finalize(api) + assert read_only(p, 'api') is api + raises(AssertionError, p.finalize, api) class some_plugin(plugable.Plugin): pass - p = some_plugin(api) - assert read_only(p, 'api') is api + p = some_plugin() assert read_only(p, 'name') == 'some_plugin' assert repr(p) == '%s.some_plugin()' % __name__ + assert read_only(p, 'api') is None + raises(AssertionError, p.finalize, None) + p.finalize(api) + assert read_only(p, 'api') is api + raises(AssertionError, p.finalize, api) def test_ReadOnly():