commit 5914ae523eb393383a120cd24c12c508e0ffaeac Author: Damian Johnson atagar@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):