Credit: based on @m000's answer. The following variant provides a get_orig_key method, by keeping track of the case-sensitive key of the last "set" operation.
class RobbieCaseInsensitiveDict(dict):
@classmethod
def _k(cls, key):
return key.lower() if isinstance(key, str) else key
def __init__(self, *args, **kwargs):
super(RobbieCaseInsensitiveDict, self).__init__(*args, **kwargs)
self.key_dict = {}
for key in self.keys():
if isinstance(key, str):
self.key_dict[key.lower()] = key
self._convert_keys()
def get_orig_key(self, case_ins_key):
if case_ins_key in self.key_dict:
return self.key_dict[case_ins_key]
else:
return case_ins_key
def __getitem__(self, key):
return super(RobbieCaseInsensitiveDict, self).__getitem__(self.__class__._k(key))
def __setitem__(self, key, value):
if isinstance(key, str):
self.key_dict[key.lower()] = key
super(RobbieCaseInsensitiveDict, self).__setitem__(self.__class__._k(key), value)
def __delitem__(self, key):
return super(RobbieCaseInsensitiveDict, self).__delitem__(self.__class__._k(key))
def __contains__(self, key):
return super(RobbieCaseInsensitiveDict, self).__contains__(self.__class__._k(key))
def has_key(self, key):
return super(RobbieCaseInsensitiveDict, self).has_key(self.__class__._k(key))
def pop(self, key, *args, **kwargs):
return super(RobbieCaseInsensitiveDict, self).pop(self.__class__._k(key), *args, **kwargs)
def get(self, key, *args, **kwargs):
return super(RobbieCaseInsensitiveDict, self).get(self.__class__._k(key), *args, **kwargs)
def setdefault(self, key, *args, **kwargs):
if isintance(key, str):
self.key_dict[key.lower()] = key
return super(RobbieCaseInsensitiveDict, self).setdefault(self.__class__._k(key), *args, **kwargs)
def update(self, E={}, **F):
super(RobbieCaseInsensitiveDict, self).update(self.__class__(E))
super(RobbieCaseInsensitiveDict, self).update(self.__class__(**F))
def _convert_keys(self):
for k in list(self.keys()):
v = super(RobbieCaseInsensitiveDict, self).pop(k)
self.__setitem__(k, v)