[tor-commits] [stem/master] OrderedDict substitute for older python versions
atagar at torproject.org
atagar at torproject.org
Mon Oct 29 16:04:29 UTC 2012
commit b09de1093e7a7237d3825d5728126cbf2f15842b
Author: Damian Johnson <atagar at torproject.org>
Date: Mon Oct 29 08:47:26 2012 -0700
OrderedDict substitute for older python versions
In d30a628e I simplified the _get_descriptor_components() by using the
collections.OrderedDict builtin. Unforutunately OrderedDict was introduced in
python 2.7, breaking our 2.5 and 2.6 compatability...
======================================================================
ERROR: test_voting_delay
----------------------------------------------------------------------
Traceback:
File "/home/atagar/Desktop/stem/test/unit/descriptor/networkstatus/document_v3.py", line 359, in test_voting_delay
document = get_network_status_document_v3({"voting-delay": "12 345"})
File "/home/atagar/Desktop/stem/test/mocking.py", line 782, in get_network_status_document_v3
return stem.descriptor.networkstatus.NetworkStatusDocumentV3(desc_content, validate = True)
File "/home/atagar/Desktop/stem/stem/descriptor/networkstatus.py", line 458, in __init__
self._header = _DocumentHeader(document_file, validate, default_params)
File "/home/atagar/Desktop/stem/stem/descriptor/networkstatus.py", line 541, in __init__
entries = stem.descriptor._get_descriptor_components(content, validate)
File "/home/atagar/Desktop/stem/stem/descriptor/__init__.py", line 289, in _get_descriptor_components
entries = collections.OrderedDict()
AttributeError: 'module' object has no attribute 'OrderedDict'
Caught by eoinof on...
https://trac.torproject.org/7244
I'm fixing this by adding an OrderedDict substitute that's under the MIT
license...
http://pypi.python.org/pypi/ordereddict
---
stem/descriptor/__init__.py | 8 ++-
stem/util/__init__.py | 1 +
stem/util/ordereddict.py | 130 +++++++++++++++++++++++++++++++++++++++++++
3 files changed, 137 insertions(+), 2 deletions(-)
diff --git a/stem/descriptor/__init__.py b/stem/descriptor/__init__.py
index ff3d59f..d667946 100644
--- a/stem/descriptor/__init__.py
+++ b/stem/descriptor/__init__.py
@@ -25,10 +25,14 @@ __all__ = [
import os
import re
-import collections
import stem.util.enum
+try:
+ from collections import OrderedDict
+except ImportError:
+ from stem.util.ordereddict import OrderedDict
+
KEYWORD_CHAR = "a-zA-Z0-9-"
WHITESPACE = " \t"
KEYWORD_LINE = re.compile("^([%s]+)(?:[%s]+(.*))?$" % (KEYWORD_CHAR, WHITESPACE))
@@ -286,7 +290,7 @@ def _get_descriptor_components(raw_contents, validate, extra_keywords = ()):
value tuple, the second being a list of those entries.
"""
- entries = collections.OrderedDict()
+ entries = OrderedDict()
extra_entries = [] # entries with a keyword in extra_keywords
remaining_lines = raw_contents.split("\n")
diff --git a/stem/util/__init__.py b/stem/util/__init__.py
index 78fe9e1..d371629 100644
--- a/stem/util/__init__.py
+++ b/stem/util/__init__.py
@@ -7,6 +7,7 @@ __all__ = [
"connection",
"enum",
"log",
+ "ordereddict",
"proc",
"system",
"term",
diff --git a/stem/util/ordereddict.py b/stem/util/ordereddict.py
new file mode 100644
index 0000000..cb97874
--- /dev/null
+++ b/stem/util/ordereddict.py
@@ -0,0 +1,130 @@
+# Drop in replacement for python 2.7's OrderedDict, from...
+# http://pypi.python.org/pypi/ordereddict
+
+# 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.
+
+from UserDict import DictMixin
+
+class OrderedDict(dict, DictMixin):
+ def __init__(self, *args, **kwds):
+ if len(args) > 1:
+ raise TypeError('expected at most 1 arguments, got %d' % len(args))
+ try:
+ self.__end
+ except AttributeError:
+ self.clear()
+ self.update(*args, **kwds)
+
+ def clear(self):
+ self.__end = end = []
+ end += [None, end, end] # sentinel node for doubly linked list
+ self.__map = {} # key --> [key, prev, next]
+ dict.clear(self)
+
+ def __setitem__(self, key, value):
+ if key not in self:
+ end = self.__end
+ curr = end[1]
+ curr[2] = end[1] = self.__map[key] = [key, curr, end]
+ dict.__setitem__(self, key, value)
+
+ def __delitem__(self, key):
+ dict.__delitem__(self, key)
+ key, prev, next = self.__map.pop(key)
+ prev[2] = next
+ next[1] = prev
+
+ def __iter__(self):
+ end = self.__end
+ curr = end[2]
+ while curr is not end:
+ yield curr[0]
+ curr = curr[2]
+
+ def __reversed__(self):
+ end = self.__end
+ curr = end[1]
+ while curr is not end:
+ yield curr[0]
+ curr = curr[1]
+
+ def popitem(self, last=True):
+ if not self:
+ raise KeyError('dictionary is empty')
+ if last:
+ key = reversed(self).next()
+ else:
+ key = iter(self).next()
+ value = self.pop(key)
+ return key, value
+
+ def __reduce__(self):
+ items = [[k, self[k]] for k in self]
+ tmp = self.__map, self.__end
+ del self.__map, self.__end
+ inst_dict = vars(self).copy()
+ self.__map, self.__end = tmp
+ if inst_dict:
+ return (self.__class__, (items,), inst_dict)
+ return self.__class__, (items,)
+
+ def keys(self):
+ return list(self)
+
+ setdefault = DictMixin.setdefault
+ update = DictMixin.update
+ pop = DictMixin.pop
+ values = DictMixin.values
+ items = DictMixin.items
+ iterkeys = DictMixin.iterkeys
+ itervalues = DictMixin.itervalues
+ iteritems = DictMixin.iteritems
+
+ def __repr__(self):
+ if not self:
+ return '%s()' % (self.__class__.__name__,)
+ return '%s(%r)' % (self.__class__.__name__, self.items())
+
+ 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
+
+ def __eq__(self, other):
+ if isinstance(other, OrderedDict):
+ if len(self) != len(other):
+ return False
+ for p, q in zip(self.items(), other.items()):
+ if p != q:
+ return False
+ return True
+ return dict.__eq__(self, other)
+
+ def __ne__(self, other):
+ return not self == other
+
More information about the tor-commits
mailing list