| # Copyright (c) 2009 Raymond Hettinger. |
| # |
| # Permission is hereby granted, free of charge, to any person obtaining a copy |
| # of this software and associated documentation files (the "Software"), to deal |
| # in the Software without restriction, including without limitation the rights |
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| # copies of the Software, and to permit persons to whom the Software is |
| # furnished to do so, subject to the following conditions: |
| # |
| # The above copyright notice and this permission notice shall be included in |
| # all copies or substantial portions of the Software. |
| # |
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
| # SOFTWARE. |
| |
| # This code is obtained from http://code.activestate.com/recipes/576669/ |
| |
| from collections import MutableMapping |
| |
| class OrderedDict(dict, MutableMapping): |
| |
| # Methods with direct access to underlying attributes |
| |
| def __init__(self, *args, **kwds): |
| if len(args) > 1: |
| raise TypeError('expected at 1 argument, got %d', len(args)) |
| if not hasattr(self, '_keys'): |
| self._keys = [] |
| self.update(*args, **kwds) |
| |
| def clear(self): |
| del self._keys[:] |
| dict.clear(self) |
| |
| def __setitem__(self, key, value): |
| if key not in self: |
| self._keys.append(key) |
| dict.__setitem__(self, key, value) |
| |
| def __delitem__(self, key): |
| dict.__delitem__(self, key) |
| self._keys.remove(key) |
| |
| def __iter__(self): |
| return iter(self._keys) |
| |
| def __reversed__(self): |
| return reversed(self._keys) |
| |
| def popitem(self): |
| if not self: |
| raise KeyError |
| key = self._keys.pop() |
| value = dict.pop(self, key) |
| return key, value |
| |
| def __reduce__(self): |
| items = [[k, self[k]] for k in self] |
| inst_dict = vars(self).copy() |
| inst_dict.pop('_keys', None) |
| return (self.__class__, (items,), inst_dict) |
| |
| # Methods with indirect access via the above methods |
| |
| setdefault = MutableMapping.setdefault |
| update = MutableMapping.update |
| pop = MutableMapping.pop |
| keys = MutableMapping.keys |
| values = MutableMapping.values |
| items = MutableMapping.items |
| |
| def __repr__(self): |
| pairs = ', '.join(map('%r: %r'.__mod__, self.items())) |
| return '%s({%s})' % (self.__class__.__name__, pairs) |
| |
| def copy(self): |
| return self.__class__(self) |
| |
| @classmethod |
| def fromkeys(cls, iterable, value=None): |
| d = cls() |
| for key in iterable: |
| d[key] = value |
| return d |