Caseinsensitive Dict lookup


class CaseInsensitiveDict(dict):
def __init__(self, *args, **kwargs):
self.keystore = {}
d = dict(*args, **kwargs)
for k in d.keys():
self.keystore[self._get_lower(k)] = k
return super(CaseInsensitiveDict, self).__init__(*args, **kwargs)
def __setitem__(self, k, v):
if hasattr(self,'keystore'):
self.keystore[self._get_lower(k)] = k
return super(CaseInsensitiveDict, self).__setitem__(k, v)
def __getitem__(self, k):
if hasattr(self,'keystore') and self._get_lower(k) in self.keystore:
k = self.keystore[self._get_lower(k)]
return super(CaseInsensitiveDict, self).__getitem__(k)

@staticmethod
def _get_lower(k):
if isinstance(k, str):
return k.lower()
else:
return k



This one seems to do the trick at last.

This is based on the logic that for every key in the dictionary (you create for
you want a Caseinsensitive Dict lookup), store the key in the lower value in
the keystore.

When you retreive a item from the Dict, let your request be in any case, but
lower it and then lookup the actual key as it was stored in the keystore and
then retrieve the value using that key.

As the __init__, __setitem__, __getitem__ methods use the super() call to dict,
and using the *same* key and the value passed to the normal dictionary, this
class with an internal keystore would behave as unsuspecting as possible.

Devised this way after a good number of trials.
Lesson to myself:

Study the concepts, try the code before you look for examples in the web,
otherwise you tend to get influenced by examples. Sometimes it might be
helpful, that would only serve as learning. You might want to get back to
implement in the wayyou best understand.

During this patch workout, got to know mixins, decorators, staticmethod,
classmethod, dict more.

There are still couple of tests failing with
Issue2275(http://bugs.python.org/issue2275) , hopefully I would have ironed
them out by today.

2 comments:

Facundo Batista said...

Have some issues, though:

>>> c = CaseInsensitiveDict()
>>> c = CaseInsensitiveDict(No=3)
>>> c
{'No': 3}
>>> c["Si"] = 8
>>> c
{'Si': 8, 'No': 3}

As you see, they're not getting stored in lowercase.

>>> del c["si"]

Traceback (most recent call last):
File, line 1, in module
del c["si"]
KeyError: 'si'

And you didn't put support for deletion.

Note this, a little bit different: http://pastebin.lugmen.org.ar/4263

Senthil Kumaran said...

Hi Facundo, My thought was to provide a "Case Insenstive Dict 'lookup'" for the dictionary and consciously not to store them as lower case values.

I tried this in as minimal way without affecting any other dict method.

Here are the example usages.
http://pastebin.lugmen.org.ar/4264

This way, I was able to address the patch requirement (Lookup issue, and title cased string) and tests successfully.

I shall attach the patch, tests which will give an idea.

And in this: http://pastebin.lugmen.org.ar/4263
- Lower cased dict may fail certain requirements in the patch. We just want case insenstive lookup, where the representation to be same.

and I had made _get_lower() as a staticmethod as opposed to _get_lower(self,..) because I did not wish to expose it as method and wanted strictly within the class. (Well, either case should be fine here, unless guidelines advises against @staticmethod)

Thanks!