| 1 | #!/usr/bin/env python2
 | 
| 2 | """
 | 
| 3 | collections.py
 | 
| 4 | 
 | 
| 5 | To avoid other dependencies.  Copied OrderedDict from collections.py, and
 | 
| 6 | MutableMapping from _abcoll.
 | 
| 7 | """
 | 
| 8 | 
 | 
| 9 | from typing import Any
 | 
| 10 | 
 | 
| 11 | 
 | 
| 12 | class OrderedDict(dict):
 | 
| 13 |     'Dictionary that remembers insertion order'
 | 
| 14 |     # An inherited dict maps keys to values.
 | 
| 15 |     # The inherited dict provides __getitem__, __len__, __contains__, and get.
 | 
| 16 |     # The remaining methods are order-aware.
 | 
| 17 |     # Big-O running times for all methods are the same as regular dictionaries.
 | 
| 18 | 
 | 
| 19 |     # The internal self.__map dict maps keys to links in a doubly linked list.
 | 
| 20 |     # The circular doubly linked list starts and ends with a sentinel element.
 | 
| 21 |     # The sentinel element never gets deleted (this simplifies the algorithm).
 | 
| 22 |     # Each link is stored as a list of length three:  [PREV, NEXT, KEY].
 | 
| 23 | 
 | 
| 24 |     def __init__(*args, **kwds):
 | 
| 25 |         # type: (Any, Any) -> None
 | 
| 26 |         '''Initialize an ordered dictionary.  The signature is the same as
 | 
| 27 |         regular dictionaries, but keyword arguments are not recommended because
 | 
| 28 |         their insertion order is arbitrary.
 | 
| 29 | 
 | 
| 30 |         '''
 | 
| 31 | 
 | 
| 32 |         if not args:
 | 
| 33 |             raise TypeError("descriptor '__init__' of 'OrderedDict' object "
 | 
| 34 |                             "needs an argument")
 | 
| 35 |         self = args[0]
 | 
| 36 |         args = args[1:]
 | 
| 37 |         if len(args) > 1:
 | 
| 38 |             raise TypeError('expected at most 1 arguments, got %d' % len(args))
 | 
| 39 |         try:
 | 
| 40 |             self.__root
 | 
| 41 |         except AttributeError:
 | 
| 42 |             self.__root = root = []                     # sentinel node
 | 
| 43 |             root[:] = [root, root, None]
 | 
| 44 |             self.__map = {}
 | 
| 45 | 
 | 
| 46 |         # Oil patch
 | 
| 47 |         #self.__update(*args, **kwds)
 | 
| 48 |         if args:
 | 
| 49 |           raise AssertionError(args)
 | 
| 50 |         if kwds:
 | 
| 51 |           raise AssertionError(kwds)
 | 
| 52 | 
 | 
| 53 |     def __setitem__(self, key, value, dict_setitem=dict.__setitem__):
 | 
| 54 |         'od.__setitem__(i, y) <==> od[i]=y'
 | 
| 55 |         # Setting a new item creates a new link at the end of the linked list,
 | 
| 56 |         # and the inherited dictionary is updated with the new key/value pair.
 | 
| 57 |         if key not in self:
 | 
| 58 |             root = self.__root
 | 
| 59 |             last = root[0]
 | 
| 60 |             last[1] = root[0] = self.__map[key] = [last, root, key]
 | 
| 61 |         return dict_setitem(self, key, value)
 | 
| 62 | 
 | 
| 63 |     def __delitem__(self, key, dict_delitem=dict.__delitem__):
 | 
| 64 |         'od.__delitem__(y) <==> del od[y]'
 | 
| 65 |         # Deleting an existing item uses self.__map to find the link which gets
 | 
| 66 |         # removed by updating the links in the predecessor and successor nodes.
 | 
| 67 |         dict_delitem(self, key)
 | 
| 68 |         link_prev, link_next, _ = self.__map.pop(key)
 | 
| 69 |         link_prev[1] = link_next                        # update link_prev[NEXT]
 | 
| 70 |         link_next[0] = link_prev                        # update link_next[PREV]
 | 
| 71 | 
 | 
| 72 |     def __iter__(self):
 | 
| 73 |         'od.__iter__() <==> iter(od)'
 | 
| 74 |         # Traverse the linked list in order.
 | 
| 75 |         root = self.__root
 | 
| 76 |         curr = root[1]                                  # start at the first node
 | 
| 77 |         while curr is not root:
 | 
| 78 |             yield curr[2]                               # yield the curr[KEY]
 | 
| 79 |             curr = curr[1]                              # move to next node
 | 
| 80 | 
 | 
| 81 |     def __reversed__(self):
 | 
| 82 |         'od.__reversed__() <==> reversed(od)'
 | 
| 83 |         # Traverse the linked list in reverse order.
 | 
| 84 |         root = self.__root
 | 
| 85 |         curr = root[0]                                  # start at the last node
 | 
| 86 |         while curr is not root:
 | 
| 87 |             yield curr[2]                               # yield the curr[KEY]
 | 
| 88 |             curr = curr[0]                              # move to previous node
 | 
| 89 | 
 | 
| 90 |     def clear(self):
 | 
| 91 |         'od.clear() -> None.  Remove all items from od.'
 | 
| 92 |         root = self.__root
 | 
| 93 |         root[:] = [root, root, None]
 | 
| 94 |         self.__map.clear()
 | 
| 95 |         dict.clear(self)
 | 
| 96 | 
 | 
| 97 |     # -- the following methods do not depend on the internal structure --
 | 
| 98 | 
 | 
| 99 |     def keys(self):
 | 
| 100 |         'od.keys() -> list of keys in od'
 | 
| 101 |         return list(self)
 | 
| 102 | 
 | 
| 103 |     def values(self):
 | 
| 104 |         'od.values() -> list of values in od'
 | 
| 105 |         return [self[key] for key in self]
 | 
| 106 | 
 | 
| 107 |     def items(self):
 | 
| 108 |         'od.items() -> list of (key, value) pairs in od'
 | 
| 109 |         return [(key, self[key]) for key in self]
 | 
| 110 | 
 | 
| 111 |     def iterkeys(self):
 | 
| 112 |         'od.iterkeys() -> an iterator over the keys in od'
 | 
| 113 |         # PATCH: not used in Oil
 | 
| 114 |         raise AssertionError()
 | 
| 115 | 
 | 
| 116 |     def itervalues(self):
 | 
| 117 |         'od.itervalues -> an iterator over the values in od'
 | 
| 118 |         # PATCH: not used in Oil
 | 
| 119 |         raise AssertionError()
 | 
| 120 | 
 | 
| 121 |     def iteritems(self):
 | 
| 122 |         'od.iteritems -> an iterator over the (key, value) pairs in od'
 | 
| 123 |         for k in self:
 | 
| 124 |             yield (k, self[k])
 | 
| 125 | 
 | 
| 126 |     # Oils patch: commented out
 | 
| 127 |     if 0:
 | 
| 128 |       update = MutableMapping.update
 | 
| 129 | 
 | 
| 130 |       __update = update # let subclasses override update without breaking __init__
 | 
| 131 | 
 | 
| 132 |     # Oils patch:
 | 
| 133 |     def update(self, other):
 | 
| 134 |         for k, v in other.iteritems():
 | 
| 135 |             self[k] = v
 | 
| 136 | 
 | 
| 137 |     __marker = object()
 | 
| 138 | 
 | 
| 139 |     def pop(self, key, default=__marker):
 | 
| 140 |         '''od.pop(k[,d]) -> v, remove specified key and return the corresponding
 | 
| 141 |         value.  If key is not found, d is returned if given, otherwise KeyError
 | 
| 142 |         is raised.
 | 
| 143 | 
 | 
| 144 |         '''
 | 
| 145 |         if key in self:
 | 
| 146 |             result = self[key]
 | 
| 147 |             del self[key]
 | 
| 148 |             return result
 | 
| 149 |         if default is self.__marker:
 | 
| 150 |             raise KeyError(key)
 | 
| 151 |         return default
 | 
| 152 | 
 | 
| 153 |     def setdefault(self, key, default=None):
 | 
| 154 |         'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od'
 | 
| 155 |         # PATCH: not used in Oil
 | 
| 156 |         raise AssertionError()
 | 
| 157 | 
 | 
| 158 |     def popitem(self, last=True):
 | 
| 159 |         '''od.popitem() -> (k, v), return and remove a (key, value) pair.
 | 
| 160 |         Pairs are returned in LIFO order if last is true or FIFO order if false.
 | 
| 161 | 
 | 
| 162 |         '''
 | 
| 163 |         # PATCH: not used in Oil
 | 
| 164 |         raise AssertionError()
 | 
| 165 | 
 | 
| 166 |     def __repr__(self, _repr_running={}):
 | 
| 167 |         'od.__repr__() <==> repr(od)'
 | 
| 168 |         #call_key = id(self), _get_ident()
 | 
| 169 | 
 | 
| 170 |         # Oil patch: we don't have threads
 | 
| 171 |         call_key = id(self)
 | 
| 172 | 
 | 
| 173 |         if call_key in _repr_running:
 | 
| 174 |             return '...'
 | 
| 175 |         _repr_running[call_key] = 1
 | 
| 176 |         try:
 | 
| 177 |             # Oil patch: use <> as a subtle indicator of OrderedDict
 | 
| 178 |             parts = ['<']
 | 
| 179 |             for i, key in enumerate(self):
 | 
| 180 |               if i != 0:
 | 
| 181 |                 parts.append(', ')
 | 
| 182 |               parts.append('%r: ' % key)
 | 
| 183 |               parts.append('%r' % self[key])
 | 
| 184 |             parts.append('>')
 | 
| 185 |             return ''.join(parts)
 | 
| 186 | 
 | 
| 187 |         finally:
 | 
| 188 |             del _repr_running[call_key]
 | 
| 189 | 
 | 
| 190 |     def copy(self):
 | 
| 191 |         'od.copy() -> a shallow copy of od'
 | 
| 192 |         # PATCH: not used in Oil
 | 
| 193 |         raise AssertionError()
 | 
| 194 | 
 | 
| 195 |     @classmethod
 | 
| 196 |     def fromkeys(cls, iterable, value=None):
 | 
| 197 |         '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S.
 | 
| 198 |         If not specified, the value defaults to None.
 | 
| 199 | 
 | 
| 200 |         '''
 | 
| 201 |         # PATCH: not used in Oil
 | 
| 202 |         raise AssertionError()
 | 
| 203 | 
 | 
| 204 |     def __eq__(self, other):
 | 
| 205 |         '''od.__eq__(y) <==> od==y.  Comparison to another OD is order-sensitive
 | 
| 206 |         while comparison to a regular mapping is order-insensitive.
 | 
| 207 | 
 | 
| 208 |         '''
 | 
| 209 |         # removed _imap code
 | 
| 210 |         raise AssertionError('not supported')
 | 
| 211 | 
 | 
| 212 |     def __ne__(self, other):
 | 
| 213 |         'od.__ne__(y) <==> od!=y'
 | 
| 214 |         return not self == other
 |