mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
Add missing dict methods to CIDict
Make the CIDict interface match standard dict (except view* methods). Add __contains__, __iter__, clear. Add keyword and iterable support for __init__, update. Also add values() and itervalues(). Previously the dict versions were used; the new ones guarantee that the order matches keys(). Mark view* methods as not implemented. CIDict.copy() now returns a CIDict. Test the above additions, and fromkeys() which worked but wasn't tested.
This commit is contained in:
parent
468e5e40cc
commit
0226064bac
@ -444,10 +444,13 @@ class CIDict(dict):
|
|||||||
If you extend UserDict, isinstance(foo, dict) returns false.
|
If you extend UserDict, isinstance(foo, dict) returns false.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, default=None):
|
def __init__(self, default=None, **kwargs):
|
||||||
super(CIDict, self).__init__()
|
super(CIDict, self).__init__()
|
||||||
self._keys = {}
|
self._keys = {} # mapping of lowercased keys to proper case
|
||||||
self.update(default or {})
|
if default:
|
||||||
|
self.update(default)
|
||||||
|
if kwargs:
|
||||||
|
self.update(kwargs)
|
||||||
|
|
||||||
def __getitem__(self, key):
|
def __getitem__(self, key):
|
||||||
return super(CIDict, self).__getitem__(key.lower())
|
return super(CIDict, self).__getitem__(key.lower())
|
||||||
@ -460,11 +463,22 @@ class CIDict(dict):
|
|||||||
def __delitem__(self, key):
|
def __delitem__(self, key):
|
||||||
lower_key = key.lower()
|
lower_key = key.lower()
|
||||||
del self._keys[lower_key]
|
del self._keys[lower_key]
|
||||||
return super(CIDict, self).__delitem__(key.lower())
|
return super(CIDict, self).__delitem__(lower_key)
|
||||||
|
|
||||||
def update(self, dict):
|
def update(self, new=None, **kwargs):
|
||||||
for key in dict.keys():
|
if new:
|
||||||
self[key] = dict[key]
|
try:
|
||||||
|
keys = new.keys
|
||||||
|
except AttributeError:
|
||||||
|
self.update(dict(new))
|
||||||
|
else:
|
||||||
|
for key in keys():
|
||||||
|
self[key] = new[key]
|
||||||
|
for key, value in kwargs.iteritems():
|
||||||
|
self[key] = value
|
||||||
|
|
||||||
|
def __contains__(self, key):
|
||||||
|
return super(CIDict, self).__contains__(key.lower())
|
||||||
|
|
||||||
def has_key(self, key):
|
def has_key(self, key):
|
||||||
return super(CIDict, self).has_key(key.lower())
|
return super(CIDict, self).has_key(key.lower())
|
||||||
@ -475,26 +489,30 @@ class CIDict(dict):
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
return failobj
|
return failobj
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return self._keys.itervalues()
|
||||||
|
|
||||||
def keys(self):
|
def keys(self):
|
||||||
return self._keys.values()
|
return list(self.iterkeys())
|
||||||
|
|
||||||
def items(self):
|
def items(self):
|
||||||
result = []
|
return list(self.iteritems())
|
||||||
for k in self._keys.values():
|
|
||||||
result.append((k, self[k]))
|
def values(self):
|
||||||
return result
|
return list(self.itervalues())
|
||||||
|
|
||||||
def copy(self):
|
def copy(self):
|
||||||
copy = {}
|
"""Returns a shallow copy of this CIDict"""
|
||||||
for k in self._keys.values():
|
return CIDict(self.items())
|
||||||
copy[k] = self[k]
|
|
||||||
return copy
|
|
||||||
|
|
||||||
def iteritems(self):
|
def iteritems(self):
|
||||||
return self.copy().iteritems()
|
return ((k, self[k]) for k in self._keys.itervalues())
|
||||||
|
|
||||||
def iterkeys(self):
|
def iterkeys(self):
|
||||||
return self.copy().iterkeys()
|
return self._keys.itervalues()
|
||||||
|
|
||||||
|
def itervalues(self):
|
||||||
|
return (v for k, v in self.iteritems())
|
||||||
|
|
||||||
def setdefault(self, key, value=None):
|
def setdefault(self, key, value=None):
|
||||||
try:
|
try:
|
||||||
@ -520,6 +538,19 @@ class CIDict(dict):
|
|||||||
|
|
||||||
return (key, value)
|
return (key, value)
|
||||||
|
|
||||||
|
def clear(self):
|
||||||
|
self._keys.clear()
|
||||||
|
return super(CIDict, self).clear()
|
||||||
|
|
||||||
|
def viewitems(self):
|
||||||
|
raise NotImplementedError('CIDict.viewitems is not implemented')
|
||||||
|
|
||||||
|
def viewkeys(self):
|
||||||
|
raise NotImplementedError('CIDict.viewkeys is not implemented')
|
||||||
|
|
||||||
|
def viewvvalues(self):
|
||||||
|
raise NotImplementedError('CIDict.viewvvalues is not implemented')
|
||||||
|
|
||||||
|
|
||||||
class GeneralizedTimeZone(datetime.tzinfo):
|
class GeneralizedTimeZone(datetime.tzinfo):
|
||||||
"""This class is a basic timezone wrapper for the offset specified
|
"""This class is a basic timezone wrapper for the offset specified
|
||||||
|
@ -76,6 +76,18 @@ class TestCIDict(object):
|
|||||||
self.cidict["key2"] = "val2"
|
self.cidict["key2"] = "val2"
|
||||||
self.cidict["KEY3"] = "VAL3"
|
self.cidict["KEY3"] = "VAL3"
|
||||||
|
|
||||||
|
def test_init(self):
|
||||||
|
cidict = ipautil.CIDict()
|
||||||
|
assert dict(cidict.items()) == {}
|
||||||
|
cidict = ipautil.CIDict([('a', 2), ('b', 3), ('C', 4)])
|
||||||
|
assert dict(cidict.items()) == {'a': 2, 'b': 3, 'C': 4}
|
||||||
|
cidict = ipautil.CIDict([('a', 2), ('b', None)], b=3, C=4)
|
||||||
|
assert dict(cidict.items()) == {'a': 2, 'b': 3, 'C': 4}
|
||||||
|
cidict = ipautil.CIDict({'a': 2, 'b': None}, b=3, C=4)
|
||||||
|
assert dict(cidict.items()) == {'a': 2, 'b': 3, 'C': 4}
|
||||||
|
cidict = ipautil.CIDict(a=2, b=3, C=4)
|
||||||
|
assert dict(cidict.items()) == {'a': 2, 'b': 3, 'C': 4}
|
||||||
|
|
||||||
def test_len(self):
|
def test_len(self):
|
||||||
nose.tools.assert_equal(3, len(self.cidict))
|
nose.tools.assert_equal(3, len(self.cidict))
|
||||||
|
|
||||||
@ -117,19 +129,27 @@ class TestCIDict(object):
|
|||||||
nose.tools.assert_equal(0, len(self.cidict))
|
nose.tools.assert_equal(0, len(self.cidict))
|
||||||
|
|
||||||
def test_copy(self):
|
def test_copy(self):
|
||||||
"""A copy is no longer a CIDict, but should preserve the case of
|
|
||||||
the keys as they were inserted."""
|
|
||||||
copy = self.cidict.copy()
|
copy = self.cidict.copy()
|
||||||
|
assert copy == self.cidict
|
||||||
nose.tools.assert_equal(3, len(copy))
|
nose.tools.assert_equal(3, len(copy))
|
||||||
assert copy.has_key("Key1")
|
assert copy.has_key("Key1")
|
||||||
|
assert copy.has_key("key1")
|
||||||
nose.tools.assert_equal("val1", copy["Key1"])
|
nose.tools.assert_equal("val1", copy["Key1"])
|
||||||
assert not copy.has_key("key1")
|
|
||||||
|
|
||||||
def test_haskey(self):
|
def test_haskey(self):
|
||||||
assert self.cidict.has_key("KEY1")
|
assert self.cidict.has_key("KEY1")
|
||||||
assert self.cidict.has_key("key2")
|
assert self.cidict.has_key("key2")
|
||||||
assert self.cidict.has_key("key3")
|
assert self.cidict.has_key("key3")
|
||||||
|
|
||||||
|
assert not self.cidict.has_key("Key4")
|
||||||
|
|
||||||
|
def test_contains(self):
|
||||||
|
assert "KEY1" in self.cidict
|
||||||
|
assert "key2" in self.cidict
|
||||||
|
assert "key3" in self.cidict
|
||||||
|
|
||||||
|
assert "Key4" not in self.cidict
|
||||||
|
|
||||||
def test_items(self):
|
def test_items(self):
|
||||||
items = self.cidict.items()
|
items = self.cidict.items()
|
||||||
nose.tools.assert_equal(3, len(items))
|
nose.tools.assert_equal(3, len(items))
|
||||||
@ -138,6 +158,14 @@ class TestCIDict(object):
|
|||||||
assert ("key2", "val2") in items_set
|
assert ("key2", "val2") in items_set
|
||||||
assert ("KEY3", "VAL3") in items_set
|
assert ("KEY3", "VAL3") in items_set
|
||||||
|
|
||||||
|
assert self.cidict.items() == list(self.cidict.iteritems()) == zip(
|
||||||
|
self.cidict.iterkeys(), self.cidict.itervalues())
|
||||||
|
|
||||||
|
def test_iter(self):
|
||||||
|
items = []
|
||||||
|
assert list(self.cidict) == list(self.cidict.keys())
|
||||||
|
assert sorted(self.cidict) == sorted(['Key1', 'key2', 'KEY3'])
|
||||||
|
|
||||||
def test_iteritems(self):
|
def test_iteritems(self):
|
||||||
items = []
|
items = []
|
||||||
for (k,v) in self.cidict.iteritems():
|
for (k,v) in self.cidict.iteritems():
|
||||||
@ -176,6 +204,8 @@ class TestCIDict(object):
|
|||||||
assert "key2" in keys_set
|
assert "key2" in keys_set
|
||||||
assert "KEY3" in keys_set
|
assert "KEY3" in keys_set
|
||||||
|
|
||||||
|
assert self.cidict.keys() == list(self.cidict.iterkeys())
|
||||||
|
|
||||||
def test_values(self):
|
def test_values(self):
|
||||||
values = self.cidict.values()
|
values = self.cidict.values()
|
||||||
nose.tools.assert_equal(3, len(values))
|
nose.tools.assert_equal(3, len(values))
|
||||||
@ -184,6 +214,8 @@ class TestCIDict(object):
|
|||||||
assert "val2" in values_set
|
assert "val2" in values_set
|
||||||
assert "VAL3" in values_set
|
assert "VAL3" in values_set
|
||||||
|
|
||||||
|
assert self.cidict.values() == list(self.cidict.itervalues())
|
||||||
|
|
||||||
def test_update(self):
|
def test_update(self):
|
||||||
newdict = { "KEY2": "newval2",
|
newdict = { "KEY2": "newval2",
|
||||||
"key4": "val4" }
|
"key4": "val4" }
|
||||||
@ -199,6 +231,23 @@ class TestCIDict(object):
|
|||||||
assert ("KEY3", "VAL3") in items_set
|
assert ("KEY3", "VAL3") in items_set
|
||||||
assert ("key4", "val4") in items_set
|
assert ("key4", "val4") in items_set
|
||||||
|
|
||||||
|
def test_update_dict_and_kwargs(self):
|
||||||
|
self.cidict.update({'a': 'va', 'b': None}, b='vb', key2='v2')
|
||||||
|
assert dict(self.cidict.items()) == {
|
||||||
|
'a': 'va', 'b': 'vb',
|
||||||
|
'Key1': 'val1', 'key2': 'v2', 'KEY3': 'VAL3'}
|
||||||
|
|
||||||
|
def test_update_list_and_kwargs(self):
|
||||||
|
self.cidict.update([('a', 'va'), ('b', None)], b='vb', key2='val2')
|
||||||
|
assert dict(self.cidict.items()) == {
|
||||||
|
'a': 'va', 'b': 'vb',
|
||||||
|
'Key1': 'val1', 'key2': 'val2', 'KEY3': 'VAL3'}
|
||||||
|
|
||||||
|
def test_update_kwargs(self):
|
||||||
|
self.cidict.update(b='vb', key2='val2')
|
||||||
|
assert dict(self.cidict.items()) == {
|
||||||
|
'b': 'vb', 'Key1': 'val1', 'key2': 'val2', 'KEY3': 'VAL3'}
|
||||||
|
|
||||||
def test_setdefault(self):
|
def test_setdefault(self):
|
||||||
nose.tools.assert_equal("val1", self.cidict.setdefault("KEY1", "default"))
|
nose.tools.assert_equal("val1", self.cidict.setdefault("KEY1", "default"))
|
||||||
|
|
||||||
@ -242,6 +291,20 @@ class TestCIDict(object):
|
|||||||
assert item in items
|
assert item in items
|
||||||
items.discard(item)
|
items.discard(item)
|
||||||
|
|
||||||
|
def test_fromkeys(self):
|
||||||
|
dct = ipautil.CIDict.fromkeys(('A', 'b', 'C'))
|
||||||
|
assert sorted(dct.keys()) == sorted(['A', 'b', 'C'])
|
||||||
|
assert sorted(dct.values()) == [None] * 3
|
||||||
|
|
||||||
|
def test_clear(self):
|
||||||
|
self.cidict.clear()
|
||||||
|
assert self.cidict == {}
|
||||||
|
assert self.cidict.keys() == []
|
||||||
|
assert self.cidict.values() == []
|
||||||
|
assert self.cidict.items() == []
|
||||||
|
assert self.cidict._keys == {}
|
||||||
|
|
||||||
|
|
||||||
class TestTimeParser(object):
|
class TestTimeParser(object):
|
||||||
def test_simple(self):
|
def test_simple(self):
|
||||||
timestr = "20070803"
|
timestr = "20070803"
|
||||||
|
Loading…
Reference in New Issue
Block a user