Source code for dhtmlparser3.specialdict

from collections import OrderedDict


def _lower_if_str(item):
    """
    Try to convert item to lowercase, if it is string.

    Args:
        item (obj): Str, unicode or any other object.

    Returns:
        obj: ``item.lower()`` if `item` is ``str`` or ``unicode``, else just \
             `item` itself.
    """
    if isinstance(item, str):
        return item.lower()

    return item


[docs]class SpecialDict(OrderedDict): """ This dictionary stores items case sensitive, but compare them case INsensitive. """ def __init__(self, *args, **kwargs): # lower_key -> key mapping self._case_mapping = OrderedDict() super().__init__(*args, **kwargs) def __setitem__(self, key, value): lower_key = _lower_if_str(key) # remove the old key with (possibly) different case if lower_key in self._case_mapping: original_key = self._case_mapping[lower_key] if key != original_key: key_index = list(super().keys()).index(original_key) super().__delitem__(original_key) super().__setitem__(key, value) keys = list(super().keys()) for index in range(key_index, len(self) - 1): super().move_to_end(keys[index]) self._case_mapping[lower_key] = key super().__setitem__(key, value) def __getitem__(self, key): lower_key = _lower_if_str(key) if lower_key not in self._case_mapping: raise KeyError(repr(key)) return super().__getitem__(self._case_mapping[lower_key]) def __delitem__(self, key): lower_key = _lower_if_str(key) key = self._case_mapping[lower_key] del self._case_mapping[lower_key] return super().__delitem__(key)
[docs] def clear(self): self._case_mapping.clear() return super().clear()
[docs] def get(self, k, d=None): lower_key = _lower_if_str(k) if lower_key not in self._case_mapping: return d return super().get(self._case_mapping[lower_key], d)
def __contains__(self, key): lower_key = _lower_if_str(key) right_key = self._case_mapping.get(lower_key, None) return right_key and right_key in set(self.keys())
[docs] def has_key(self, key): return key in self
def __eq__(self, obj): if self is obj: return True if not hasattr(obj, "__getitem__"): return False keys = None if hasattr(obj, "keys"): keys = obj.keys() elif hasattr(obj, "iterkeys"): keys = list(obj.keys()) else: keys = list(obj) if len(self.keys()) != len(keys): return False for key in keys: if not self.__contains__(key): return False if obj[key] != self.__getitem__(key): return False return True def __ne__(self, obj): return not self.__eq__(obj) # python 2 / 3 compatibility def _is_py2(self): return hasattr(super(), "iteritems")
[docs] def iteritems(self, *args, **kwargs): if self._is_py2(): return super().iteritems(*args, **kwargs) return self.items()
[docs] def iterkeys(self, *args, **kwargs): if self._is_py2(): return super().iterkeys(*args, **kwargs) return self.keys()
[docs] def itervalues(self, *args, **kwargs): if self._is_py2(): return super().itervalues(*args, **kwargs) return self.values()
[docs] def keys(self, *args, **kwargs): if not self._is_py2(): return list(super().keys(*args, **kwargs)) return super().keys(*args, **kwargs)
[docs] def items(self, *args, **kwargs): if not self._is_py2(): return list(super().items(*args, **kwargs)) return super().items(*args, **kwargs)
[docs] def values(self, *args, **kwargs): if not self._is_py2(): return list(super().values(*args, **kwargs)) return super().values(*args, **kwargs)
[docs] def copy(self): new_dict = super().copy() new_dict._case_mapping = self._case_mapping.copy() return new_dict