Lichen

Annotated lib/UserDict.py

6:f551873980e5
2016-08-30 Paul Boddie Added PythonLight alternative libraries.
paul@6 1
"""A more or less complete user-defined wrapper around dictionary objects."""
paul@6 2
paul@6 3
class UserDict:
paul@6 4
    def __init__(self, dict=None, **kwargs):
paul@6 5
        self.data = {}
paul@6 6
        if dict is not None:
paul@6 7
            self.update(dict)
paul@6 8
        if len(kwargs):
paul@6 9
            self.update(kwargs)
paul@6 10
    def __repr__(self): return repr(self.data)
paul@6 11
    def __cmp__(self, dict):
paul@6 12
        if isinstance(dict, UserDict):
paul@6 13
            return cmp(self.data, dict.data)
paul@6 14
        else:
paul@6 15
            return cmp(self.data, dict)
paul@6 16
    __hash__ = None # Avoid Py3k warning
paul@6 17
    def __len__(self): return len(self.data)
paul@6 18
    def __getitem__(self, key):
paul@6 19
        if key in self.data:
paul@6 20
            return self.data[key]
paul@6 21
        if hasattr(self.__class__, "__missing__"):
paul@6 22
            return self.__class__.__missing__(self, key)
paul@6 23
        raise KeyError(key)
paul@6 24
    def __setitem__(self, key, item): self.data[key] = item
paul@6 25
    def __delitem__(self, key): del self.data[key]
paul@6 26
    def clear(self): self.data.clear()
paul@6 27
    def copy(self):
paul@6 28
        if self.__class__ is UserDict:
paul@6 29
            return UserDict(self.data.copy())
paul@6 30
        import copy
paul@6 31
        data = self.data
paul@6 32
        try:
paul@6 33
            self.data = {}
paul@6 34
            c = copy.copy(self)
paul@6 35
        finally:
paul@6 36
            self.data = data
paul@6 37
        c.update(self)
paul@6 38
        return c
paul@6 39
    def keys(self): return self.data.keys()
paul@6 40
    def items(self): return self.data.items()
paul@6 41
    def iteritems(self): return self.data.iteritems()
paul@6 42
    def iterkeys(self): return self.data.iterkeys()
paul@6 43
    def itervalues(self): return self.data.itervalues()
paul@6 44
    def values(self): return self.data.values()
paul@6 45
    def has_key(self, key): return key in self.data
paul@6 46
    def update(self, dict=None, **kwargs):
paul@6 47
        if dict is None:
paul@6 48
            pass
paul@6 49
        elif isinstance(dict, UserDict):
paul@6 50
            self.data.update(dict.data)
paul@6 51
        elif isinstance(dict, type({})) or not hasattr(dict, 'items'):
paul@6 52
            self.data.update(dict)
paul@6 53
        else:
paul@6 54
            for k, v in dict.items():
paul@6 55
                self[k] = v
paul@6 56
        if len(kwargs):
paul@6 57
            self.data.update(kwargs)
paul@6 58
    def get(self, key, failobj=None):
paul@6 59
        if key not in self:
paul@6 60
            return failobj
paul@6 61
        return self[key]
paul@6 62
    def setdefault(self, key, failobj=None):
paul@6 63
        if key not in self:
paul@6 64
            self[key] = failobj
paul@6 65
        return self[key]
paul@6 66
    def pop(self, key, *args):
paul@6 67
        return self.data.pop(key, *args)
paul@6 68
    def popitem(self):
paul@6 69
        return self.data.popitem()
paul@6 70
    def __contains__(self, key):
paul@6 71
        return key in self.data
paul@6 72
    @classmethod
paul@6 73
    def fromkeys(cls, iterable, value=None):
paul@6 74
        d = cls()
paul@6 75
        for key in iterable:
paul@6 76
            d[key] = value
paul@6 77
        return d
paul@6 78
paul@6 79
class IterableUserDict(UserDict):
paul@6 80
    def __iter__(self):
paul@6 81
        return iter(self.data)
paul@6 82
paul@6 83
class DictMixin:
paul@6 84
    # Mixin defining all dictionary methods for classes that already have
paul@6 85
    # a minimum dictionary interface including getitem, setitem, delitem,
paul@6 86
    # and keys. Without knowledge of the subclass constructor, the mixin
paul@6 87
    # does not define __init__() or copy().  In addition to the four base
paul@6 88
    # methods, progressively more efficiency comes with defining
paul@6 89
    # __contains__(), __iter__(), and iteritems().
paul@6 90
paul@6 91
    # second level definitions support higher levels
paul@6 92
    def __iter__(self):
paul@6 93
        for k in self.keys():
paul@6 94
            yield k
paul@6 95
    def has_key(self, key):
paul@6 96
        try:
paul@6 97
            self[key]
paul@6 98
        except KeyError:
paul@6 99
            return False
paul@6 100
        return True
paul@6 101
    def __contains__(self, key):
paul@6 102
        return self.has_key(key)
paul@6 103
paul@6 104
    # third level takes advantage of second level definitions
paul@6 105
    def iteritems(self):
paul@6 106
        for k in self:
paul@6 107
            yield (k, self[k])
paul@6 108
    def iterkeys(self):
paul@6 109
        return self.__iter__()
paul@6 110
paul@6 111
    # fourth level uses definitions from lower levels
paul@6 112
    def itervalues(self):
paul@6 113
        for _, v in self.iteritems():
paul@6 114
            yield v
paul@6 115
    def values(self):
paul@6 116
        return [v for _, v in self.iteritems()]
paul@6 117
    def items(self):
paul@6 118
        return list(self.iteritems())
paul@6 119
    def clear(self):
paul@6 120
        for key in self.keys():
paul@6 121
            del self[key]
paul@6 122
    def setdefault(self, key, default=None):
paul@6 123
        try:
paul@6 124
            return self[key]
paul@6 125
        except KeyError:
paul@6 126
            self[key] = default
paul@6 127
        return default
paul@6 128
    def pop(self, key, *args):
paul@6 129
        if len(args) > 1:
paul@6 130
            raise TypeError, "pop expected at most 2 arguments, got "\
paul@6 131
                              + repr(1 + len(args))
paul@6 132
        try:
paul@6 133
            value = self[key]
paul@6 134
        except KeyError:
paul@6 135
            if args:
paul@6 136
                return args[0]
paul@6 137
            raise
paul@6 138
        del self[key]
paul@6 139
        return value
paul@6 140
    def popitem(self):
paul@6 141
        try:
paul@6 142
            k, v = self.iteritems().next()
paul@6 143
        except StopIteration:
paul@6 144
            raise KeyError, 'container is empty'
paul@6 145
        del self[k]
paul@6 146
        return (k, v)
paul@6 147
    def update(self, other=None, **kwargs):
paul@6 148
        # Make progressively weaker assumptions about "other"
paul@6 149
        if other is None:
paul@6 150
            pass
paul@6 151
        elif hasattr(other, 'iteritems'):  # iteritems saves memory and lookups
paul@6 152
            for k, v in other.iteritems():
paul@6 153
                self[k] = v
paul@6 154
        elif hasattr(other, 'keys'):
paul@6 155
            for k in other.keys():
paul@6 156
                self[k] = other[k]
paul@6 157
        else:
paul@6 158
            for k, v in other:
paul@6 159
                self[k] = v
paul@6 160
        if kwargs:
paul@6 161
            self.update(kwargs)
paul@6 162
    def get(self, key, default=None):
paul@6 163
        try:
paul@6 164
            return self[key]
paul@6 165
        except KeyError:
paul@6 166
            return default
paul@6 167
    def __repr__(self):
paul@6 168
        return repr(dict(self.iteritems()))
paul@6 169
    def __cmp__(self, other):
paul@6 170
        if other is None:
paul@6 171
            return 1
paul@6 172
        if isinstance(other, DictMixin):
paul@6 173
            other = dict(other.iteritems())
paul@6 174
        return cmp(dict(self.iteritems()), other)
paul@6 175
    def __len__(self):
paul@6 176
        return len(self.keys())