diff options
author | Jason Gerard DeRose <jderose@redhat.com> | 2008-08-01 20:42:35 +0000 |
---|---|---|
committer | Jason Gerard DeRose <jderose@redhat.com> | 2008-08-01 20:42:35 +0000 |
commit | f3762a76c0824296e90385eac27455aaf06af32d (patch) | |
tree | a4683b6b4b19a49882cc810799c7cb6f8515b0af | |
parent | 4fe8e52ecb61088bcff2a7c91db454621d6755f1 (diff) | |
download | freeipa.git-f3762a76c0824296e90385eac27455aaf06af32d.tar.gz freeipa.git-f3762a76c0824296e90385eac27455aaf06af32d.tar.xz freeipa.git-f3762a76c0824296e90385eac27455aaf06af32d.zip |
40: Rewrote dictionary interface for plugable.NameSpace to better suite new architecture
-rw-r--r-- | ipalib/plugable.py | 89 | ||||
-rw-r--r-- | ipalib/tests/test_plugable.py | 62 | ||||
-rw-r--r-- | ipalib/tests/tstutil.py | 8 |
3 files changed, 104 insertions, 55 deletions
diff --git a/ipalib/plugable.py b/ipalib/plugable.py index 9e94e96b..4923c621 100644 --- a/ipalib/plugable.py +++ b/ipalib/plugable.py @@ -130,75 +130,56 @@ class NameSpace(ReadOnly): both as instance attributes and as dictionary items. """ - def __init__(self, kw): - """ - The `kw` argument is a dict of the (key, value) pairs to be in this - NameSpace instance. The optional `order` keyword argument specifies - the order of the keys in this namespace; if omitted, the default is - to sort the keys in ascending order. - """ - assert isinstance(kw, dict) - self.__kw = dict(kw) - for (key, value) in self.__kw.items(): - assert not key.startswith('_') - setattr(self, key, value) - if order is None: - self.__keys = sorted(self.__kw) - else: - self.__keys = list(order) - assert set(self.__keys) == set(self.__kw) - self.__locked = True - - def __setattr__(self, name, value): + def __init__(self, items): """ - Raises an exception if trying to set an attribute after the - NameSpace has been locked; otherwise calls object.__setattr__(). """ - if self.__locked: - raise errors.SetError(name) - super(NameSpace, self).__setattr__(name, value) + object.__setattr__(self, '_NameSpace__items', tuple(items)) - def __getitem__(self, key): - """ - Returns item from namespace named `key`. - """ - return self.__kw[key] + # dict mapping Python name to item: + object.__setattr__(self, '_NameSpace__pname', {}) - def __hasitem__(self, key): - """ - Returns True if namespace has an item named `key`. - """ - return bool(key in self.__kw) + # dict mapping human-readibly name to item: + object.__setattr__(self, '_NameSpace__hname', {}) + + for item in self.__items: + for (key, d) in [ + (item.name, self.__pname), + (str(item), self.__hname), + ]: + assert key not in d + d[key] = item def __iter__(self): """ - Yields the names in this NameSpace in ascending order, or in the - the order specified in `order` kw arg. - - For example: + Iterates through the items in this NameSpace in the same order they + were passed in the contructor. + """ + for item in self.__items: + yield item - >>> ns = NameSpace(dict(attr_b='world', attr_a='hello')) - >>> list(ns) - ['attr_a', 'attr_b'] - >>> [ns[k] for k in ns] - ['hello', 'world'] + def __len__(self): + """ + Returns number of items in this NameSpace. """ - for key in self.__keys: - yield key + return len(self.__items) - def __call__(self): + def __contains__(self, key): """ - Iterates through the values in this NameSpace in the same order as - the keys. + Returns True if an item with pname or hname `key` is in this + NameSpace. """ - for key in self.__keys: - yield self.__kw[key] + return (key in self.__pname) or (key in self.__hname) - def __len__(self): + def __getitem__(self, key): """ - Returns number of items in this NameSpace. + Returns item with pname or hname `key`; otherwise raises KeyError. """ - return len(self.__keys) + if key in self.__pname: + return self.__pname[key] + if key in self.__hname: + return self.__hname[key] + raise KeyError('NameSpace has no item for key %r' % key) + class Registrar(object): diff --git a/ipalib/tests/test_plugable.py b/ipalib/tests/test_plugable.py index 99c9a4f6..4f92889c 100644 --- a/ipalib/tests/test_plugable.py +++ b/ipalib/tests/test_plugable.py @@ -21,7 +21,7 @@ Unit tests for `ipalib.plugable` module. """ -from tstutil import raises, no_set, no_del, read_only +from tstutil import raises, getitem, no_set, no_del, read_only from ipalib import plugable, errors @@ -236,3 +236,63 @@ def test_Registrar(): assert len(d) == 3 assert r[base] == d assert r[base.__name__] == d + + +def test_NameSpace(): + assert issubclass(plugable.NameSpace, plugable.ReadOnly) + + class DummyProxy(object): + def __init__(self, name): + self.__name = name + + def __get_name(self): + return self.__name + name = property(__get_name) + + def __str__(self): + return plugable.to_cli(self.__name) + + def get_name(i): + return 'noun_verb%d' % i + + def get_cli(i): + return 'noun-verb%d' % i + + def get_proxies(n): + for i in xrange(n): + yield DummyProxy(get_name(i)) + + cnt = 20 + ns = plugable.NameSpace(get_proxies(cnt)) + + # Test __len__ + assert len(ns) == cnt + + # Test __iter__ + i = None + for (i, item) in enumerate(ns): + assert type(item) is DummyProxy + assert item.name == get_name(i) + assert str(item) == get_cli(i) + assert i == cnt - 1 + + # Test __contains__, __getitem__: + for i in xrange(cnt): + name = get_name(i) + cli = get_cli(i) + assert name in ns + assert cli in ns + item = ns[name] + assert isinstance(item, DummyProxy) + assert item.name == name + assert str(item) == cli + assert ns[name] is item + assert ns[cli] is item + + # Check that KeyError is raised: + name = get_name(cnt) + cli = get_cli(cnt) + assert name not in ns + assert cli not in ns + raises(KeyError, getitem, ns, name) + raises(KeyError, getitem, ns, cli) diff --git a/ipalib/tests/tstutil.py b/ipalib/tests/tstutil.py index 37b7745f..12ca119d 100644 --- a/ipalib/tests/tstutil.py +++ b/ipalib/tests/tstutil.py @@ -49,6 +49,14 @@ def raises(exception, callback, *args, **kw): raise ExceptionNotRaised(exception) +def getitem(obj, key): + """ + Works like getattr but for dictionary interface. Uses this in combination + with raises() to test that, for example, KeyError is raised. + """ + return obj[key] + + def no_set(obj, name, value='some_new_obj'): """ Tests that attribute cannot be set. |