diff options
author | Kevin McCarthy <kmccarth@redhat.com> | 2007-08-24 10:31:45 -0700 |
---|---|---|
committer | Kevin McCarthy <kmccarth@redhat.com> | 2007-08-24 10:31:45 -0700 |
commit | c7c8aa09269895a9cb9c02e87c5289a2461d647a (patch) | |
tree | e19ec58ad37ac691af0ad5f2f2567ec07183de8b /ipa-python | |
parent | 861cda3cb5256a177845029ddf1900f51271b56c (diff) | |
download | freeipa-c7c8aa09269895a9cb9c02e87c5289a2461d647a.tar.gz freeipa-c7c8aa09269895a9cb9c02e87c5289a2461d647a.tar.xz freeipa-c7c8aa09269895a9cb9c02e87c5289a2461d647a.zip |
Add ipautil, which contains CIDict - a case insensitive dict.
This version of the cidict extends the dict class, which allows it to
play nicely with turbogears.
Also includes extensive tests.
Diffstat (limited to 'ipa-python')
-rw-r--r-- | ipa-python/ipautil.py | 108 | ||||
-rw-r--r-- | ipa-python/test/test_ipautil.py | 207 |
2 files changed, 315 insertions, 0 deletions
diff --git a/ipa-python/ipautil.py b/ipa-python/ipautil.py new file mode 100644 index 000000000..51337a8eb --- /dev/null +++ b/ipa-python/ipautil.py @@ -0,0 +1,108 @@ +#! /usr/bin/python -E +# +# Copyright (C) 2007 Red Hat +# see file 'COPYING' for use and warranty information +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; version 2 or later +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +from string import lower + +class CIDict(dict): + """ + Case-insensitive but case-respecting dictionary. + + Idea from python-ldap cidict, however this version extends 'dict' + so it works properly with TurboGears. + + If you extend UserDict, isinstance(foo, dict) returns false. + """ + + def __init__(self,default=None): + super(CIDict, self).__init__() + self._keys = {} + self.update(default or {}) + + def __getitem__(self,key): + return super(CIDict,self).__getitem__(lower(key)) + + def __setitem__(self,key,value): + lower_key = lower(key) + self._keys[lower_key] = key + return super(CIDict,self).__setitem__(lower(key),value) + + def __delitem__(self,key): + lower_key = lower(key) + del self._keys[lower_key] + return super(CIDict,self).__delitem__(lower(key)) + + def update(self,dict): + for key in dict.keys(): + self[key] = dict[key] + + def has_key(self,key): + return super(CIDict, self).has_key(lower(key)) + + def get(self,key,failobj=None): + try: + return self[key] + except KeyError: + return failobj + + def keys(self): + return self._keys.values() + + def items(self): + result = [] + for k in self._keys.values(): + result.append((k,self[k])) + return result + + def copy(self): + copy = {} + for k in self._keys.values(): + copy[k] = self[k] + return copy + + def iteritems(self): + return self.copy().iteritems() + + def iterkeys(self): + return self.copy().iterkeys() + + def setdefault(self,key,value=None): + try: + return self[key] + except KeyError: + self[key] = value + return value + + def pop(self, key, *args): + try: + value = self[key] + del self[key] + return value + except KeyError: + if len(args) == 1: + return args[0] + raise + + def popitem(self): + (lower_key,value) = super(CIDict,self).popitem() + key = self._keys[lower_key] + del self._keys[lower_key] + + return (key,value) + + diff --git a/ipa-python/test/test_ipautil.py b/ipa-python/test/test_ipautil.py new file mode 100644 index 000000000..16991eff8 --- /dev/null +++ b/ipa-python/test/test_ipautil.py @@ -0,0 +1,207 @@ +#! /usr/bin/python -E +# +# Copyright (C) 2007 Red Hat +# see file 'COPYING' for use and warranty information +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; version 2 or later +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +import unittest +import ipa.ipautil + +class TestCIDict(unittest.TestCase): + def setUp(self): + self.cidict = ipa.ipautil.CIDict() + self.cidict["Key1"] = "val1" + self.cidict["key2"] = "val2" + self.cidict["KEY3"] = "VAL3" + + def tearDown(self): + pass + + def testLen(self): + self.assertEqual(3, len(self.cidict)) + + def test__GetItem(self): + self.assertEqual("val1", self.cidict["Key1"]) + self.assertEqual("val1", self.cidict["key1"]) + self.assertEqual("val2", self.cidict["KEY2"]) + self.assertEqual("VAL3", self.cidict["key3"]) + self.assertEqual("VAL3", self.cidict["KEY3"]) + try: + self.cidict["key4"] + fail("should have raised KeyError") + except KeyError: + pass + + def testGet(self): + self.assertEqual("val1", self.cidict.get("Key1")) + self.assertEqual("val1", self.cidict.get("key1")) + self.assertEqual("val2", self.cidict.get("KEY2")) + self.assertEqual("VAL3", self.cidict.get("key3")) + self.assertEqual("VAL3", self.cidict.get("KEY3")) + self.assertEqual("default", self.cidict.get("key4", "default")) + + def test__SetItem(self): + self.cidict["key4"] = "val4" + self.assertEqual("val4", self.cidict["key4"]) + self.cidict["KEY4"] = "newval4" + self.assertEqual("newval4", self.cidict["key4"]) + + def testDel(self): + self.assert_(self.cidict.has_key("Key1")) + del(self.cidict["Key1"]) + self.failIf(self.cidict.has_key("Key1")) + + self.assert_(self.cidict.has_key("key2")) + del(self.cidict["KEY2"]) + self.failIf(self.cidict.has_key("key2")) + + def testClear(self): + self.assertEqual(3, len(self.cidict)) + self.cidict.clear() + self.assertEqual(0, len(self.cidict)) + + def testCopy(self): + """A copy is no longer a CIDict, but should preserve the case of + the keys as they were inserted.""" + copy = self.cidict.copy() + self.assertEqual(3, len(copy)) + self.assert_(copy.has_key("Key1")) + self.assertEqual("val1", copy["Key1"]) + self.failIf(copy.has_key("key1")) + + def testHasKey(self): + self.assert_(self.cidict.has_key("KEY1")) + self.assert_(self.cidict.has_key("key2")) + self.assert_(self.cidict.has_key("key3")) + + def testItems(self): + items = self.cidict.items() + self.assertEqual(3, len(items)) + items_set = set(items) + self.assert_(("Key1", "val1") in items_set) + self.assert_(("key2", "val2") in items_set) + self.assert_(("KEY3", "VAL3") in items_set) + + def testIterItems(self): + items = [] + for (k,v) in self.cidict.iteritems(): + items.append((k,v)) + self.assertEqual(3, len(items)) + items_set = set(items) + self.assert_(("Key1", "val1") in items_set) + self.assert_(("key2", "val2") in items_set) + self.assert_(("KEY3", "VAL3") in items_set) + + def testIterKeys(self): + keys = [] + for k in self.cidict.iterkeys(): + keys.append(k) + self.assertEqual(3, len(keys)) + keys_set = set(keys) + self.assert_("Key1" in keys_set) + self.assert_("key2" in keys_set) + self.assert_("KEY3" in keys_set) + + def testIterValues(self): + values = [] + for k in self.cidict.itervalues(): + values.append(k) + self.assertEqual(3, len(values)) + values_set = set(values) + self.assert_("val1" in values_set) + self.assert_("val2" in values_set) + self.assert_("VAL3" in values_set) + + def testKeys(self): + keys = self.cidict.keys() + self.assertEqual(3, len(keys)) + keys_set = set(keys) + self.assert_("Key1" in keys_set) + self.assert_("key2" in keys_set) + self.assert_("KEY3" in keys_set) + + def testValues(self): + values = self.cidict.values() + self.assertEqual(3, len(values)) + values_set = set(values) + self.assert_("val1" in values_set) + self.assert_("val2" in values_set) + self.assert_("VAL3" in values_set) + + def testUpdate(self): + newdict = { "KEY2": "newval2", + "key4": "val4" } + self.cidict.update(newdict) + self.assertEqual(4, len(self.cidict)) + + items = self.cidict.items() + self.assertEqual(4, len(items)) + items_set = set(items) + self.assert_(("Key1", "val1") in items_set) + # note the update "overwrites" the case of the key2 + self.assert_(("KEY2", "newval2") in items_set) + self.assert_(("KEY3", "VAL3") in items_set) + self.assert_(("key4", "val4") in items_set) + + def testSetDefault(self): + self.assertEqual("val1", self.cidict.setdefault("KEY1", "default")) + + self.failIf(self.cidict.has_key("KEY4")) + self.assertEqual("default", self.cidict.setdefault("KEY4", "default")) + self.assert_(self.cidict.has_key("KEY4")) + self.assertEqual("default", self.cidict["key4"]) + + self.failIf(self.cidict.has_key("KEY5")) + self.assertEqual(None, self.cidict.setdefault("KEY5")) + self.assert_(self.cidict.has_key("KEY5")) + self.assertEqual(None, self.cidict["key5"]) + + def testPop(self): + self.assertEqual("val1", self.cidict.pop("KEY1", "default")) + self.failIf(self.cidict.has_key("key1")) + + self.assertEqual("val2", self.cidict.pop("KEY2")) + self.failIf(self.cidict.has_key("key2")) + + self.assertEqual("default", self.cidict.pop("key4", "default")) + try: + self.cidict.pop("key4") + fail("should have raised KeyError") + except KeyError: + pass + + def testPopItem(self): + items = set(self.cidict.items()) + self.assertEqual(3, len(self.cidict)) + + item = self.cidict.popitem() + self.assertEqual(2, len(self.cidict)) + self.assert_(item in items) + items.discard(item) + + item = self.cidict.popitem() + self.assertEqual(1, len(self.cidict)) + self.assert_(item in items) + items.discard(item) + + item = self.cidict.popitem() + self.assertEqual(0, len(self.cidict)) + self.assert_(item in items) + items.discard(item) + + +if __name__ == '__main__': + unittest.main() |