~ubuntu-branches/ubuntu/utopic/dulwich/utopic

« back to all changes in this revision

Viewing changes to dulwich/_compat.py

  • Committer: Package Import Robot
  • Author(s): Jelmer Vernooij
  • Date: 2014-04-23 01:41:04 UTC
  • mfrom: (1.5.5)
  • Revision ID: package-import@ubuntu.com-20140423014104-nulhaisomztpfriy
Tags: 0.9.6-1
* New upstream release.
* Allow output to stderr in autopktest.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# _compat.py -- For dealing with python2.4 oddness
2
 
# Copyright (C) 2008 Canonical Ltd.
3
 
#
4
 
# This program is free software; you can redistribute it and/or
5
 
# modify it under the terms of the GNU General Public License
6
 
# as published by the Free Software Foundation; version 2
7
 
# of the License or (at your option) a later version.
8
 
#
9
 
# This program is distributed in the hope that it will be useful,
10
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 
# GNU General Public License for more details.
13
 
#
14
 
# You should have received a copy of the GNU General Public License
15
 
# along with this program; if not, write to the Free Software
16
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17
 
# MA  02110-1301, USA.
18
 
 
19
 
"""Misc utilities to work with python <2.7.
20
 
 
21
 
These utilities can all be deleted when dulwich decides it wants to stop
22
 
support for python <2.7.
23
 
"""
24
 
 
25
 
# Backport of OrderedDict() class that runs on Python 2.4, 2.5, 2.6, 2.7 and pypy.
26
 
# Passes Python2.7's test suite and incorporates all the latest updates.
27
 
# Copyright (C) Raymond Hettinger, MIT license
28
 
 
29
 
try:
30
 
    from thread import get_ident as _get_ident
31
 
except ImportError:
32
 
    from dummy_thread import get_ident as _get_ident
33
 
 
34
 
try:
35
 
    from _abcoll import KeysView, ValuesView, ItemsView
36
 
except ImportError:
37
 
    pass
38
 
 
39
 
class OrderedDict(dict):
40
 
    'Dictionary that remembers insertion order'
41
 
    # An inherited dict maps keys to values.
42
 
    # The inherited dict provides __getitem__, __len__, __contains__, and get.
43
 
    # The remaining methods are order-aware.
44
 
    # Big-O running times for all methods are the same as for regular dictionaries.
45
 
 
46
 
    # The internal self.__map dictionary maps keys to links in a doubly linked list.
47
 
    # The circular doubly linked list starts and ends with a sentinel element.
48
 
    # The sentinel element never gets deleted (this simplifies the algorithm).
49
 
    # Each link is stored as a list of length three:  [PREV, NEXT, KEY].
50
 
 
51
 
    def __init__(self, *args, **kwds):
52
 
        '''Initialize an ordered dictionary.  Signature is the same as for
53
 
        regular dictionaries, but keyword arguments are not recommended
54
 
        because their insertion order is arbitrary.
55
 
 
56
 
        '''
57
 
        if len(args) > 1:
58
 
            raise TypeError('expected at most 1 arguments, got %d' % len(args))
59
 
        try:
60
 
            self.__root
61
 
        except AttributeError:
62
 
            self.__root = root = []                     # sentinel node
63
 
            root[:] = [root, root, None]
64
 
            self.__map = {}
65
 
        self.__update(*args, **kwds)
66
 
 
67
 
    def __setitem__(self, key, value, dict_setitem=dict.__setitem__):
68
 
        'od.__setitem__(i, y) <==> od[i]=y'
69
 
        # Setting a new item creates a new link which goes at the end of the linked
70
 
        # list, and the inherited dictionary is updated with the new key/value pair.
71
 
        if key not in self:
72
 
            root = self.__root
73
 
            last = root[0]
74
 
            last[1] = root[0] = self.__map[key] = [last, root, key]
75
 
        dict_setitem(self, key, value)
76
 
 
77
 
    def __delitem__(self, key, dict_delitem=dict.__delitem__):
78
 
        'od.__delitem__(y) <==> del od[y]'
79
 
        # Deleting an existing item uses self.__map to find the link which is
80
 
        # then removed by updating the links in the predecessor and successor nodes.
81
 
        dict_delitem(self, key)
82
 
        link_prev, link_next, key = self.__map.pop(key)
83
 
        link_prev[1] = link_next
84
 
        link_next[0] = link_prev
85
 
 
86
 
    def __iter__(self):
87
 
        'od.__iter__() <==> iter(od)'
88
 
        root = self.__root
89
 
        curr = root[1]
90
 
        while curr is not root:
91
 
            yield curr[2]
92
 
            curr = curr[1]
93
 
 
94
 
    def __reversed__(self):
95
 
        'od.__reversed__() <==> reversed(od)'
96
 
        root = self.__root
97
 
        curr = root[0]
98
 
        while curr is not root:
99
 
            yield curr[2]
100
 
            curr = curr[0]
101
 
 
102
 
    def clear(self):
103
 
        'od.clear() -> None.  Remove all items from od.'
104
 
        try:
105
 
            for node in self.__map.itervalues():
106
 
                del node[:]
107
 
            root = self.__root
108
 
            root[:] = [root, root, None]
109
 
            self.__map.clear()
110
 
        except AttributeError:
111
 
            pass
112
 
        dict.clear(self)
113
 
 
114
 
    def popitem(self, last=True):
115
 
        """od.popitem() -> (k, v), return and remove a (key, value) pair.
116
 
        Pairs are returned in LIFO order if last is true or FIFO order if false.
117
 
 
118
 
        """
119
 
        if not self:
120
 
            raise KeyError('dictionary is empty')
121
 
        root = self.__root
122
 
        if last:
123
 
            link = root[0]
124
 
            link_prev = link[0]
125
 
            link_prev[1] = root
126
 
            root[0] = link_prev
127
 
        else:
128
 
            link = root[1]
129
 
            link_next = link[1]
130
 
            root[1] = link_next
131
 
            link_next[0] = root
132
 
        key = link[2]
133
 
        del self.__map[key]
134
 
        value = dict.pop(self, key)
135
 
        return key, value
136
 
 
137
 
    # -- the following methods do not depend on the internal structure --
138
 
 
139
 
    def keys(self):
140
 
        """'od.keys() -> list of keys in od"""
141
 
        return list(self)
142
 
 
143
 
    def values(self):
144
 
        """od.values() -> list of values in od"""
145
 
        return [self[key] for key in self]
146
 
 
147
 
    def items(self):
148
 
        """od.items() -> list of (key, value) pairs in od"""
149
 
        return [(key, self[key]) for key in self]
150
 
 
151
 
    def iterkeys(self):
152
 
        """od.iterkeys() -> an iterator over the keys in od"""
153
 
        return iter(self)
154
 
 
155
 
    def itervalues(self):
156
 
        """od.itervalues -> an iterator over the values in od"""
157
 
        for k in self:
158
 
            yield self[k]
159
 
 
160
 
    def iteritems(self):
161
 
        """od.iteritems -> an iterator over the (key, value) items in od"""
162
 
        for k in self:
163
 
            yield (k, self[k])
164
 
 
165
 
    def update(*args, **kwds):
166
 
        """od.update(E, F) -> None.  Update od from dict/iterable E and F.
167
 
 
168
 
        If E is a dict instance, does:           for k in E: od[k] = E[k]
169
 
        If E has a .keys() method, does:         for k in E.keys(): od[k] = E[k]
170
 
        Or if E is an iterable of items, does:   for k, v in E: od[k] = v
171
 
        In either case, this is followed by:     for k, v in F.items(): od[k] = v
172
 
        """
173
 
        if len(args) > 2:
174
 
            raise TypeError('update() takes at most 2 positional '
175
 
                            'arguments (%d given)' % (len(args),))
176
 
        elif not args:
177
 
            raise TypeError('update() takes at least 1 argument (0 given)')
178
 
        self = args[0]
179
 
        # Make progressively weaker assumptions about "other"
180
 
        other = ()
181
 
        if len(args) == 2:
182
 
            other = args[1]
183
 
        if isinstance(other, dict):
184
 
            for key in other:
185
 
                self[key] = other[key]
186
 
        elif hasattr(other, 'keys'):
187
 
            for key in other.keys():
188
 
                self[key] = other[key]
189
 
        else:
190
 
            for key, value in other:
191
 
                self[key] = value
192
 
        for key, value in kwds.items():
193
 
            self[key] = value
194
 
 
195
 
    __update = update  # let subclasses override update without breaking __init__
196
 
 
197
 
    __marker = object()
198
 
 
199
 
    def pop(self, key, default=__marker):
200
 
        """od.pop(k[,d]) -> v, remove specified key and return the corresponding value.
201
 
        If key is not found, d is returned if given, otherwise KeyError is raised.
202
 
 
203
 
        """
204
 
        if key in self:
205
 
            result = self[key]
206
 
            del self[key]
207
 
            return result
208
 
        if default is self.__marker:
209
 
            raise KeyError(key)
210
 
        return default
211
 
 
212
 
    def setdefault(self, key, default=None):
213
 
        'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od'
214
 
        if key in self:
215
 
            return self[key]
216
 
        self[key] = default
217
 
        return default
218
 
 
219
 
    def __repr__(self, _repr_running={}):
220
 
        'od.__repr__() <==> repr(od)'
221
 
        call_key = id(self), _get_ident()
222
 
        if call_key in _repr_running:
223
 
            return '...'
224
 
        _repr_running[call_key] = 1
225
 
        try:
226
 
            if not self:
227
 
                return '%s()' % (self.__class__.__name__,)
228
 
            return '%s(%r)' % (self.__class__.__name__, self.items())
229
 
        finally:
230
 
            del _repr_running[call_key]
231
 
 
232
 
    def __reduce__(self):
233
 
        'Return state information for pickling'
234
 
        items = [[k, self[k]] for k in self]
235
 
        inst_dict = vars(self).copy()
236
 
        for k in vars(OrderedDict()):
237
 
            inst_dict.pop(k, None)
238
 
        if inst_dict:
239
 
            return (self.__class__, (items,), inst_dict)
240
 
        return self.__class__, (items,)
241
 
 
242
 
    def copy(self):
243
 
        'od.copy() -> a shallow copy of od'
244
 
        return self.__class__(self)
245
 
 
246
 
    @classmethod
247
 
    def fromkeys(cls, iterable, value=None):
248
 
        '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S
249
 
        and values equal to v (which defaults to None).
250
 
 
251
 
        '''
252
 
        d = cls()
253
 
        for key in iterable:
254
 
            d[key] = value
255
 
        return d
256
 
 
257
 
    def __eq__(self, other):
258
 
        '''od.__eq__(y) <==> od==y.  Comparison to another OD is order-sensitive
259
 
        while comparison to a regular mapping is order-insensitive.
260
 
 
261
 
        '''
262
 
        if isinstance(other, OrderedDict):
263
 
            return len(self)==len(other) and self.items() == other.items()
264
 
        return dict.__eq__(self, other)
265
 
 
266
 
    def __ne__(self, other):
267
 
        return not self == other
268
 
 
269
 
    # -- the following methods are only used in Python 2.7 --
270
 
 
271
 
    def viewkeys(self):
272
 
        "od.viewkeys() -> a set-like object providing a view on od's keys"
273
 
        return KeysView(self)
274
 
 
275
 
    def viewvalues(self):
276
 
        "od.viewvalues() -> an object providing a view on od's values"
277
 
        return ValuesView(self)
278
 
 
279
 
    def viewitems(self):
280
 
        "od.viewitems() -> a set-like object providing a view on od's items"
281
 
        return ItemsView(self)