mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2024-12-23 15:40:01 -06:00
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
This commit is contained in:
parent
5ed58fdb42
commit
a24f2121d5
@ -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)
|
||||
super(Registrar, self).__init__(
|
||||
dict(self.__base_iter())
|
||||
)
|
||||
self.__d[val.name] = val
|
||||
setattr(self, val.name, val.dictproxy)
|
||||
lock(self)
|
||||
|
||||
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
|
||||
|
@ -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)
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user