From a24f2121d553644513dc90d423b9ac968de34bc2 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Fri, 15 Aug 2008 05:07:17 +0000 Subject: 178: Registrar now subclasses from DictProxy; made Registrar.__iter__ behave same as the other container emulation in plugable.py, and made the dictorary interface return the base and the attribute interface return the MagicDict; updated API class and unit tests --- ipalib/plugable.py | 85 +++++++++++++------------------------------ ipalib/tests/test_plugable.py | 49 +++++++++++-------------- 2 files changed, 47 insertions(+), 87 deletions(-) (limited to 'ipalib') diff --git a/ipalib/plugable.py b/ipalib/plugable.py index b8d2b3906..57ab8bc74 100644 --- a/ipalib/plugable.py +++ b/ipalib/plugable.py @@ -546,7 +546,7 @@ class NameSpace(DictProxy): return '%s(<%d members>)' % (self.__class__.__name__, len(self)) -class Registrar(ReadOnly): +class Registrar(DictProxy): """ Collects plugin classes as they are registered. @@ -561,30 +561,19 @@ class Registrar(ReadOnly): :param allowed: Base classes from which plugins accepted by this Registrar must subclass. """ - - class Val(ReadOnly): - """ - Internal class used so that only one mapping is needed. - """ - def __init__(self, base): - assert inspect.isclass(base) - self.base = base - self.name = base.__name__ - self.sub_d = dict() - self.dictproxy = MagicDict(self.sub_d) - lock(self) - - self.__allowed = allowed - self.__d = {} + self.__allowed = dict((base, {}) for base in allowed) self.__registered = set() - for base in self.__allowed: - val = Val(base) - assert not ( - val.name in self.__d or hasattr(self, val.name) - ) - self.__d[val.name] = val - setattr(self, val.name, val.dictproxy) - lock(self) + super(Registrar, self).__init__( + dict(self.__base_iter()) + ) + + def __base_iter(self): + for (base, sub_d) in self.__allowed.iteritems(): + assert inspect.isclass(base) + name = base.__name__ + assert not hasattr(self, name) + setattr(self, name, MagicDict(sub_d)) + yield (name, base) def __findbases(self, klass): """ @@ -597,12 +586,12 @@ class Registrar(ReadOnly): """ assert inspect.isclass(klass) found = False - for base in self.__allowed: + for (base, sub_d) in self.__allowed.iteritems(): if issubclass(klass, base): found = True - yield base + yield (base, sub_d) if not found: - raise errors.SubclassError(klass, self.__allowed) + raise errors.SubclassError(klass, self.__allowed.keys()) def __call__(self, klass, override=False): """ @@ -619,17 +608,15 @@ class Registrar(ReadOnly): raise errors.DuplicateError(klass) # Find the base class or raise SubclassError: - for base in self.__findbases(klass): - sub_d = self.__d[base.__name__].sub_d - + for (base, sub_d) in self.__findbases(klass): # Check override: if klass.__name__ in sub_d: - # Must use override=True to override: if not override: + # Must use override=True to override: raise errors.OverrideError(base, klass) else: - # There was nothing already registered to override: if override: + # There was nothing already registered to override: raise errors.MissingOverrideError(base, klass) # The plugin is okay, add to sub_d: @@ -638,29 +625,6 @@ class Registrar(ReadOnly): # The plugin is okay, add to __registered: self.__registered.add(klass) - def __getitem__(self, key): - """ - Returns the MagicDict for plugins subclassed from the base named ``key``. - """ - if key not in self.__d: - raise KeyError('no base class named %r' % key) - return self.__d[key].dictproxy - - def __contains__(self, key): - """ - Returns True if a base class named ``key`` is in this Registrar. - """ - return key in self.__d - - def __iter__(self): - """ - Iterates through a (base, registered_plugins) tuple for each allowed - base. - """ - for base in self.__allowed: - sub_d = self.__d[base.__name__].sub_d - yield (base, tuple(sub_d[k] for k in sorted(sub_d))) - class API(DictProxy): """ @@ -687,16 +651,19 @@ class API(DictProxy): plugin = instances[klass] yield PluginProxy(base, plugin) - for (base, classes) in self.register: - namespace = NameSpace(plugin_iter(base, classes)) - name = base.__name__ + for name in self.register: + base = self.register[name] + magic = getattr(self.register, name) + namespace = NameSpace( + plugin_iter(base, (magic[k] for k in magic)) + ) assert not ( name in self.__d or hasattr(self, name) ) self.__d[name] = namespace object.__setattr__(self, name, namespace) - for plugin in instances.values(): + for plugin in instances.itervalues(): plugin.finalize(self) lock(plugin) assert plugin.api is self diff --git a/ipalib/tests/test_plugable.py b/ipalib/tests/test_plugable.py index aeb3ddf6e..aece3fb81 100644 --- a/ipalib/tests/test_plugable.py +++ b/ipalib/tests/test_plugable.py @@ -643,12 +643,17 @@ def test_Registrar(): # Test creation of Registrar: r = plugable.Registrar(Base1, Base2) + # Test __iter__: + assert list(r) == ['Base1', 'Base2'] + # Test __hasitem__, __getitem__: for base in [Base1, Base2]: - assert base.__name__ in r - dp = r[base.__name__] - assert type(dp) is plugable.MagicDict - assert len(dp) == 0 + name = base.__name__ + assert name in r + assert r[name] is base + magic = getattr(r, name) + assert type(magic) is plugable.MagicDict + assert len(magic) == 0 # Check that TypeError is raised trying to register something that isn't # a class: @@ -660,12 +665,9 @@ def test_Registrar(): # Check that registration works r(plugin1) - dp = r['Base1'] - assert type(dp) is plugable.MagicDict - assert len(dp) == 1 - assert r.Base1 is dp - assert dp['plugin1'] is plugin1 - assert dp.plugin1 is plugin1 + assert len(r.Base1) == 1 + assert r.Base1['plugin1'] is plugin1 + assert r.Base1.plugin1 is plugin1 # Check that DuplicateError is raised trying to register exact class # again: @@ -696,7 +698,7 @@ def test_Registrar(): assert len(r.Base2) == 1 assert r.Base2.plugin2 is plugin2 - # Setup to test __iter__: + # Setup to test more registration: class plugin1a(Base1): pass r(plugin1a) @@ -713,25 +715,16 @@ def test_Registrar(): pass r(plugin2b) - m = { - 'Base1': set([plugin1, plugin1a, plugin1b]), - 'Base2': set([plugin2, plugin2a, plugin2b]), - } - - # Now test __iter__: - for (base, plugins) in r: - assert base in [Base1, Base2] - assert set(plugins) == m[base.__name__] - assert len(list(r)) == 2 - # Again test __hasitem__, __getitem__: for base in [Base1, Base2]: - assert base.__name__ in r - dp = r[base.__name__] - assert len(dp) == 3 - for key in dp: - klass = dp[key] - assert getattr(dp, key) is klass + name = base.__name__ + assert name in r + assert r[name] is base + magic = getattr(r, name) + assert len(magic) == 3 + for key in magic: + klass = magic[key] + assert getattr(magic, key) is klass assert issubclass(klass, base) -- cgit