[tor-commits] [stem/master] Using rich comparison functions

atagar at torproject.org atagar at torproject.org
Sat Feb 2 18:20:49 UTC 2013


commit 5914ae523eb393383a120cd24c12c508e0ffaeac
Author: Damian Johnson <atagar at torproject.org>
Date:   Tue Jan 22 09:27:45 2013 -0800

    Using rich comparison functions
    
    Python 3.x drops support for __cmp__, requiring that users opt for rich
    comparison methods instead...
    
    http://python3porting.com/problems.html#unorderable-types-cmp-and-cmp
    
    ======================================================================
    ERROR: test_event_listening
    ----------------------------------------------------------------------
    Traceback:
      File "/home/atagar/Desktop/stem/test/data/python3/test/unit/control/controller.py", line 285, in test_event_listening
        self.assertRaises(InvalidRequest, self.controller.add_event_listener, mocking.no_op(), EventType.BW)
      File "/usr/lib/python3.2/unittest/case.py", line 574, in assertRaises
        callableObj(*args, **kwargs)
      File "/home/atagar/Desktop/stem/test/data/python3/stem/control.py", line 1438, in add_event_listener
        if not self.get_version().meets_requirements(event_version):
      File "/home/atagar/Desktop/stem/test/data/python3/stem/version.py", line 175, in meets_requirements
        return self >= requirements
    TypeError: unorderable types: Version() >= Version()
    
    This change uncovered a couple bugs where events failed to strip off the
    trailing 'OK'. I'm not entirely sure why the previous comparisons didn't catch
    this, but oh well - fixed now.
---
 stem/descriptor/networkstatus.py       |   66 ++++++++++++++++++++++++--------
 stem/descriptor/router_status_entry.py |   60 +++++++++++++++++++++++------
 stem/descriptor/server_descriptor.py   |   30 +++++++++++---
 stem/response/events.py                |    4 +-
 stem/version.py                        |   30 +++++++-------
 5 files changed, 139 insertions(+), 51 deletions(-)

diff --git a/stem/descriptor/networkstatus.py b/stem/descriptor/networkstatus.py
index c1bbadf..511f5b0 100644
--- a/stem/descriptor/networkstatus.py
+++ b/stem/descriptor/networkstatus.py
@@ -528,11 +528,20 @@ class NetworkStatusDocumentV3(NetworkStatusDocument):
 
     return self._header.meets_consensus_method(method)
 
-  def __cmp__(self, other):
+  def _compare(self, other, method):
     if not isinstance(other, NetworkStatusDocumentV3):
-      return 1
+      return False
 
-    return str(self) > str(other)
+    return method(str(self).strip(), str(other).strip())
+
+  def __eq__(self, other):
+    return self._compare(other, lambda s, o: s == o)
+
+  def __lt__(self, other):
+    return self._compare(other, lambda s, o: s < o)
+
+  def __le__(self, other):
+    return self._compare(other, lambda s, o: s <= o)
 
 
 class _DocumentHeader(object):
@@ -1124,11 +1133,20 @@ class DirectoryAuthority(stem.descriptor.Descriptor):
 
     return self._unrecognized_lines
 
-  def __cmp__(self, other):
+  def _compare(self, other, method):
     if not isinstance(other, DirectoryAuthority):
-      return 1
+      return False
+
+    return method(str(self).strip(), str(other).strip())
+
+  def __eq__(self, other):
+    return self._compare(other, lambda s, o: s == o)
+
+  def __lt__(self, other):
+    return self._compare(other, lambda s, o: s < o)
 
-    return str(self) > str(other)
+  def __le__(self, other):
+    return self._compare(other, lambda s, o: s <= o)
 
 
 class KeyCertificate(stem.descriptor.Descriptor):
@@ -1285,11 +1303,20 @@ class KeyCertificate(stem.descriptor.Descriptor):
 
     return self._unrecognized_lines
 
-  def __cmp__(self, other):
+  def _compare(self, other, method):
     if not isinstance(other, KeyCertificate):
-      return 1
+      return False
 
-    return str(self) > str(other)
+    return method(str(self).strip(), str(other).strip())
+
+  def __eq__(self, other):
+    return self._compare(other, lambda s, o: s == o)
+
+  def __lt__(self, other):
+    return self._compare(other, lambda s, o: s < o)
+
+  def __le__(self, other):
+    return self._compare(other, lambda s, o: s <= o)
 
 
 class DocumentSignature(object):
@@ -1321,17 +1348,24 @@ class DocumentSignature(object):
     self.key_digest = key_digest
     self.signature = signature
 
-  def __cmp__(self, other):
+  def _compare(self, other, method):
     if not isinstance(other, DocumentSignature):
-      return 1
+      return False
 
     for attr in ("identity", "key_digest", "signature"):
-      if getattr(self, attr) > getattr(other, attr):
-        return 1
-      elif getattr(self, attr) < getattr(other, attr):
-        return -1
+      if getattr(self, attr) != getattr(other, attr):
+        return method(getattr(self, attr), getattr(other, attr))
+
+    return method(True, True)  # we're equal
+
+  def __eq__(self, other):
+    return self._compare(other, lambda s, o: s == o)
+
+  def __lt__(self, other):
+    return self._compare(other, lambda s, o: s < o)
 
-    return 0
+  def __le__(self, other):
+    return self._compare(other, lambda s, o: s <= o)
 
 
 class BridgeNetworkStatusDocument(NetworkStatusDocument):
diff --git a/stem/descriptor/router_status_entry.py b/stem/descriptor/router_status_entry.py
index a19f17f..9af2f44 100644
--- a/stem/descriptor/router_status_entry.py
+++ b/stem/descriptor/router_status_entry.py
@@ -222,11 +222,20 @@ class RouterStatusEntry(stem.descriptor.Descriptor):
 
     return list(self._unrecognized_lines)
 
-  def __cmp__(self, other):
+  def _compare(self, other, method):
     if not isinstance(other, RouterStatusEntry):
-      return 1
+      return False
 
-    return str(self) > str(other)
+    return method(str(self).strip(), str(other).strip())
+
+  def __eq__(self, other):
+    return self._compare(other, lambda s, o: s == o)
+
+  def __lt__(self, other):
+    return self._compare(other, lambda s, o: s < o)
+
+  def __le__(self, other):
+    return self._compare(other, lambda s, o: s <= o)
 
 
 class RouterStatusEntryV2(RouterStatusEntry):
@@ -266,11 +275,20 @@ class RouterStatusEntryV2(RouterStatusEntry):
   def _single_fields(self):
     return ('r', 's', 'v')
 
-  def __cmp__(self, other):
+  def _compare(self, other, method):
     if not isinstance(other, RouterStatusEntryV2):
-      return 1
+      return False
+
+    return method(str(self).strip(), str(other).strip())
+
+  def __eq__(self, other):
+    return self._compare(other, lambda s, o: s == o)
+
+  def __lt__(self, other):
+    return self._compare(other, lambda s, o: s < o)
 
-    return str(self) > str(other)
+  def __le__(self, other):
+    return self._compare(other, lambda s, o: s <= o)
 
 
 class RouterStatusEntryV3(RouterStatusEntry):
@@ -348,11 +366,20 @@ class RouterStatusEntryV3(RouterStatusEntry):
   def _single_fields(self):
     return ('r', 's', 'v', 'w', 'p')
 
-  def __cmp__(self, other):
+  def _compare(self, other, method):
     if not isinstance(other, RouterStatusEntryV3):
-      return 1
+      return False
 
-    return str(self) > str(other)
+    return method(str(self).strip(), str(other).strip())
+
+  def __eq__(self, other):
+    return self._compare(other, lambda s, o: s == o)
+
+  def __lt__(self, other):
+    return self._compare(other, lambda s, o: s < o)
+
+  def __le__(self, other):
+    return self._compare(other, lambda s, o: s <= o)
 
 
 class RouterStatusEntryMicroV3(RouterStatusEntry):
@@ -410,11 +437,20 @@ class RouterStatusEntryMicroV3(RouterStatusEntry):
   def _single_fields(self):
     return ('r', 's', 'v', 'w', 'm')
 
-  def __cmp__(self, other):
+  def _compare(self, other, method):
     if not isinstance(other, RouterStatusEntryMicroV3):
-      return 1
+      return False
+
+    return method(str(self).strip(), str(other).strip())
+
+  def __eq__(self, other):
+    return self._compare(other, lambda s, o: s == o)
+
+  def __lt__(self, other):
+    return self._compare(other, lambda s, o: s < o)
 
-    return str(self) > str(other)
+  def __le__(self, other):
+    return self._compare(other, lambda s, o: s <= o)
 
 
 def _parse_r_line(desc, value, validate, include_digest = True):
diff --git a/stem/descriptor/server_descriptor.py b/stem/descriptor/server_descriptor.py
index a4548bf..38781bd 100644
--- a/stem/descriptor/server_descriptor.py
+++ b/stem/descriptor/server_descriptor.py
@@ -793,11 +793,20 @@ class RelayDescriptor(ServerDescriptor):
 
     ServerDescriptor._parse(self, entries, validate)
 
-  def __cmp__(self, other):
+  def _compare(self, other, method):
     if not isinstance(other, RelayDescriptor):
-      return 1
+      return False
 
-    return str(self).strip() > str(other).strip()
+    return method(str(self).strip(), str(other).strip())
+
+  def __eq__(self, other):
+    return self._compare(other, lambda s, o: s == o)
+
+  def __lt__(self, other):
+    return self._compare(other, lambda s, o: s < o)
+
+  def __le__(self, other):
+    return self._compare(other, lambda s, o: s <= o)
 
   @staticmethod
   def _get_key_bytes(key_string):
@@ -918,8 +927,17 @@ class BridgeDescriptor(ServerDescriptor):
   def _last_keyword(self):
     return None
 
-  def __cmp__(self, other):
+  def _compare(self, other, method):
     if not isinstance(other, BridgeDescriptor):
-      return 1
+      return False
+
+    return method(str(self).strip(), str(other).strip())
+
+  def __eq__(self, other):
+    return self._compare(other, lambda s, o: s == o)
+
+  def __lt__(self, other):
+    return self._compare(other, lambda s, o: s < o)
 
-    return str(self).strip() > str(other).strip()
+  def __le__(self, other):
+    return self._compare(other, lambda s, o: s <= o)
diff --git a/stem/response/events.py b/stem/response/events.py
index 563b685..486e448 100644
--- a/stem/response/events.py
+++ b/stem/response/events.py
@@ -564,7 +564,7 @@ class NetworkStatusEvent(Event):
   _VERSION_ADDED = stem.version.Requirement.EVENT_NS
 
   def _parse(self):
-    content = str(self).lstrip("NS\n")
+    content = str(self).lstrip("NS\n").rstrip("\nOK")
 
     self.desc = list(stem.descriptor.router_status_entry._parse_file(
       StringIO.StringIO(content),
@@ -589,7 +589,7 @@ class NewConsensusEvent(Event):
   _VERSION_ADDED = stem.version.Requirement.EVENT_NEWCONSENSUS
 
   def _parse(self):
-    content = str(self).lstrip("NEWCONSENSUS\n")
+    content = str(self).lstrip("NEWCONSENSUS\n").rstrip("\nOK")
 
     self.desc = list(stem.descriptor.router_status_entry._parse_file(
       StringIO.StringIO(content),
diff --git a/stem/version.py b/stem/version.py
index 47b8393..46ed394 100644
--- a/stem/version.py
+++ b/stem/version.py
@@ -18,9 +18,7 @@ easily parsed and compared, for instance...
   get_system_tor_version - gets the version of our system's tor installation
 
   Version - Tor versioning information
-    |- meets_requirements - checks if this version meets the given requirements
-    |- __str__ - string representation
-    +- __cmp__ - compares with another Version
+    +- meets_requirements - checks if this version meets the given requirements
 
   VersionRequirements - Series of version requirements
     |- greater_than - adds rule that matches if we're greater than a version
@@ -187,22 +185,20 @@ class Version(object):
 
     return self.version_str
 
-  def __cmp__(self, other):
+  def _compare(self, other, method):
     """
     Compares version ordering according to the spec.
     """
 
     if not isinstance(other, Version):
-      return 1  # this is also used for equality checks
+      return False
 
     for attr in ("major", "minor", "micro", "patch"):
       my_version = max(0, self.__dict__[attr])
       other_version = max(0, other.__dict__[attr])
 
-      if my_version > other_version:
-        return 1
-      elif my_version < other_version:
-        return -1
+      if my_version != other_version:
+        return method(my_version, other_version)
 
     # According to the version spec...
     #
@@ -212,12 +208,16 @@ class Version(object):
     my_status = self.status if self.status else ""
     other_status = other.status if other.status else ""
 
-    if my_status > other_status:
-      return 1
-    elif my_status < other_status:
-      return -1
-    else:
-      return 0
+    return method(my_status, other_status)
+
+  def __eq__(self, other):
+    return self._compare(other, lambda s, o: s == o)
+
+  def __lt__(self, other):
+    return self._compare(other, lambda s, o: s < o)
+
+  def __le__(self, other):
+    return self._compare(other, lambda s, o: s <= o)
 
 
 class VersionRequirements(object):





More information about the tor-commits mailing list