diff options
author | mshields@google.com <mshields@google.com@09200d28-7f98-11dd-ad27-0f66e57d2035> | 2009-03-26 16:50:46 +0000 |
---|---|---|
committer | mshields@google.com <mshields@google.com@09200d28-7f98-11dd-ad27-0f66e57d2035> | 2009-03-26 16:50:46 +0000 |
commit | e56729fad74950335126caf991c37343a4c279ea (patch) | |
tree | 548320b330d2584a99c380ed464bf54cadfe9e78 /trunk | |
parent | 118fedea006bf5100c5117315edb7455fbef045e (diff) | |
download | ipaddr-py-e56729fad74950335126caf991c37343a4c279ea.tar.gz |
Expand rich comparison operations and their tests, with a goal of
supporting 2to3. Add a new method .networks_key(). Add a new script
to run through 2to3 and make sure tests pass under Python 3 with the
converted version.
Contributed by Philipp Hagemeister. http://codereview.appspot.com/27109
git-svn-id: https://ipaddr-py.googlecode.com/svn@66 09200d28-7f98-11dd-ad27-0f66e57d2035
Diffstat (limited to 'trunk')
-rw-r--r-- | trunk/ipaddr.py | 75 | ||||
-rwxr-xr-x | trunk/ipaddr_test.py | 81 | ||||
-rw-r--r-- | trunk/test-2to3.sh | 15 |
3 files changed, 126 insertions, 45 deletions
diff --git a/trunk/ipaddr.py b/trunk/ipaddr.py index 353daa5..7a2ae78 100644 --- a/trunk/ipaddr.py +++ b/trunk/ipaddr.py @@ -188,7 +188,7 @@ def collapse_address_list(addresses): """ return _collapse_address_list_recursive( - sorted(addresses,cmp=BaseIP.compare_networks)) + sorted(addresses, key=BaseIP.networks_key)) # backwards compatibility CollapseAddrList = collapse_address_list @@ -212,34 +212,59 @@ class BaseIP(object): raise IndexError return self._string_from_ip_int(self.broadcast + n) - def __eq__(self, other): + def __lt__(self, other): try: - if self.version != other.version: - return False + return (self.version < other.version + or self.ip < other.ip + or self.netmask < other.netmask) except AttributeError: - raise NotImplementedError('%s is not an IP address' % repr(other)) - return self.ip == other.ip and self.netmask == other.netmask + return NotImplemented - def __ne__(self, other): - return not self.__eq__(other) + def __gt__(self, other): + try: + return (self.version > other.version + or self.ip > other.ip + or self.netmask > other.netmask) + except AttributeError: + return NotImplemented - def __cmp__(self, other): + def __eq__(self, other): try: - return (cmp(self.version, other.version) or - cmp(self.ip, other.ip) or - cmp(self.prefixlen, other.prefixlen) or - 0) + return (self.version == other.version + and self.ip == other.ip + and self.netmask == other.netmask) except AttributeError: - return super(BaseIP, self).__cmp__(other) + return NotImplemented + + def __ne__(self, other): + eq = self.__eq__(other) + if eq is NotImplemented: + return NotImplemented + return not eq + + def __le__(self, other): + gt = self.__gt__(other) + if gt is NotImplemented: + return NotImplemented + return not gt + + def __ge__(self, other): + lt = self.__lt__(other) + if lt is NotImplemented: + return NotImplemented + return not lt def __repr__(self): return '%s(%r)' % (self.__class__.__name__, str(self)) + def __index__(self): + return self.ip + def __int__(self): return self.ip def __hex__(self): - return hex(self.ip) + return hex(int(self)) def address_exclude(self, other): """Remove an address from a larger block. @@ -314,7 +339,7 @@ class BaseIP(object): 's1: %s s2: %s other: %s' % (str(s1), str(s2), str(other))) - return sorted(ret_addrs, cmp=BaseIP.compare_networks) + return sorted(ret_addrs, key=BaseIP.networks_key) # backwards compatibility AddressExclude = address_exclude @@ -353,9 +378,11 @@ class BaseIP(object): eg: IPv6('::1/128') > IPv4('255.255.255.0/24') """ - if self.version != other.version: - return cmp(self.version, other.version) - + if self.version < other.version: + return -1 + if self.version > other.version: + return 1 + # self.version == other.version below here: if self.network < other.network: return -1 if self.network > other.network: @@ -371,6 +398,16 @@ class BaseIP(object): # backwards compatibility CompareNetworks = compare_networks + def networks_key(self): + """Network-only key function. + + Returns an object that identifies this address' network and + netmask. This function is a suitable "key" argument for sorted() + and list.sort(). + + """ + return self.version * 2**160 + self.network * 2**32 + self.netmask + def get_prefix(self): """Return the current prefix length.""" return self._prefixlen diff --git a/trunk/ipaddr_test.py b/trunk/ipaddr_test.py index bbd3489..3432dc2 100755 --- a/trunk/ipaddr_test.py +++ b/trunk/ipaddr_test.py @@ -254,16 +254,44 @@ class IpaddrUnitTest(unittest.TestCase): '2001:658:22a:cafe::5') def testEquals(self): - self.assertTrue(self.ipv4.__eq__(ipaddr.IPv4('1.2.3.4/24'))) - self.assertFalse(self.ipv4.__eq__(ipaddr.IPv4('1.2.3.4/23'))) - self.assertFalse(self.ipv4.__eq__(ipaddr.IPv4('1.2.3.5/24'))) - - self.assertTrue(self.ipv6.__eq__( - ipaddr.IPv6('2001:658:22a:cafe:200::1/64'))) - self.assertFalse(self.ipv6.__eq__( - ipaddr.IPv6('2001:658:22a:cafe:200::1/63'))) - self.assertFalse(self.ipv6.__eq__( - ipaddr.IPv6('2001:658:22a:cafe:200::2/64'))) + self.assertTrue(self.ipv4 == ipaddr.IPv4('1.2.3.4/24')) + self.assertFalse(self.ipv4 == ipaddr.IPv4('1.2.3.4/23')) + self.assertFalse(self.ipv4 == ipaddr.IPv4('1.2.3.5/24')) + self.assertFalse(self.ipv4 == ipaddr.IPv6('::1.2.3.4/24')) + self.assertFalse(self.ipv4 == '') + self.assertFalse(self.ipv4 == []) + self.assertFalse(self.ipv4 == 2) + + self.assertTrue(self.ipv6 == + ipaddr.IPv6('2001:658:22a:cafe:200::1/64')) + self.assertFalse(self.ipv6 == + ipaddr.IPv6('2001:658:22a:cafe:200::1/63')) + self.assertFalse(self.ipv6 == + ipaddr.IPv6('2001:658:22a:cafe:200::2/64')) + self.assertFalse(self.ipv6 == ipaddr.IPv4('1.2.3.4/23')) + self.assertFalse(self.ipv6 == '') + self.assertFalse(self.ipv6 == []) + self.assertFalse(self.ipv6 == 2) + + def testNotEquals(self): + self.assertFalse(self.ipv4 != ipaddr.IPv4('1.2.3.4/24')) + self.assertTrue(self.ipv4 != ipaddr.IPv4('1.2.3.4/23')) + self.assertTrue(self.ipv4 != ipaddr.IPv4('1.2.3.5/24')) + self.assertTrue(self.ipv4 != ipaddr.IPv6('::1.2.3.4/24')) + self.assertTrue(self.ipv4 != '') + self.assertTrue(self.ipv4 != []) + self.assertTrue(self.ipv4 != 2) + + self.assertFalse(self.ipv6 != + ipaddr.IPv6('2001:658:22a:cafe:200::1/64')) + self.assertTrue(self.ipv6 != + ipaddr.IPv6('2001:658:22a:cafe:200::1/63')) + self.assertTrue(self.ipv6 != + ipaddr.IPv6('2001:658:22a:cafe:200::2/64')) + self.assertTrue(self.ipv6 != ipaddr.IPv4('1.2.3.4/23')) + self.assertTrue(self.ipv6 != '') + self.assertTrue(self.ipv6 != []) + self.assertTrue(self.ipv6 != 2) def testSlash32Constructor(self): self.assertEquals(str(ipaddr.IPv4('1.2.3.4/255.255.255.255')), @@ -283,7 +311,6 @@ class IpaddrUnitTest(unittest.TestCase): ip4 = ipaddr.IPv4('1.1.3.0/24') ip5 = ipaddr.IPv4('1.1.4.0/24') # stored in no particular order b/c we want CollapseAddr to call [].sort - # and we want that sort to call ipaddr.IP.__cmp__() on our array members ip6 = ipaddr.IPv4('1.1.0.0/22') # check that addreses are subsumed properlly. collapsed = ipaddr.collapse_address_list([ip1, ip2, ip3, ip4, ip5, ip6]) @@ -299,7 +326,7 @@ class IpaddrUnitTest(unittest.TestCase): ip1 = ipaddr.IPv6('::2001:1/100') ip2 = ipaddr.IPv6('::2002:1/120') ip3 = ipaddr.IPv6('::2001:1/96') - # test that ipv6 addresses are subsumed properlly. + # test that ipv6 addresses are subsumed properly. collapsed = ipaddr.collapse_address_list([ip1, ip2, ip3]) self.assertEqual(collapsed, [ip3]) @@ -309,24 +336,30 @@ class IpaddrUnitTest(unittest.TestCase): ip2 = ipaddr.IPv4('1.1.1.1/24') ip3 = ipaddr.IPv4('1.1.2.0/24') - self.assertEquals(ip1.__cmp__(ip3), -1) - self.assertEquals(ip3.__cmp__(ip2), 1) + self.assertTrue(ip1 < ip3) + self.assertTrue(ip3 > ip2) self.assertEquals(ip1.compare_networks(ip2), 0) + self.assertTrue(ip1.networks_key() == ip2.networks_key()) + self.assertEquals(ip1.compare_networks(ip3), -1) + self.assertTrue(ip1.networks_key() < ip3.networks_key()) ip1 = ipaddr.IPv6('2001::2000/96') ip2 = ipaddr.IPv6('2001::2001/96') ip3 = ipaddr.IPv6('2001:ffff::2000/96') - self.assertEquals(ip1.__cmp__(ip3), -1) - self.assertEquals(ip3.__cmp__(ip2), 1) + self.assertTrue(ip1 < ip3) + self.assertTrue(ip3 > ip2) self.assertEquals(ip1.compare_networks(ip2), 0) + self.assertTrue(ip1.networks_key() == ip2.networks_key()) + self.assertEquals(ip1.compare_networks(ip3), -1) + self.assertTrue(ip1.networks_key() < ip3.networks_key()) # Test comparing different protocols ipv6 = ipaddr.IPv6('::/0') ipv4 = ipaddr.IPv4('0.0.0.0/0') - self.assertEquals(ipv6.__cmp__(ipv4), 1) - self.assertEquals(ipv4.__cmp__(ipv6), -1) + self.assertTrue(ipv6 > ipv4) + self.assertTrue(ipv4 < ipv6) def testEmbeddedIpv4(self): ipv4_string = '192.168.0.1' @@ -439,14 +472,10 @@ class IpaddrUnitTest(unittest.TestCase): self.assertEqual(42540616829182469433547762482097946625, int(self.ipv6)) def testHexRepresentation(self): - self.assertEqual('0x1020304', hex(self.ipv4)) - - # Force the return value to uppercase to workaround Python version - # differences, i.e.: - # 2.4.3: hex(long(10)) == '0xAL' - # 2.5.1: hex(long(10)) == '0xaL' - self.assertEqual('0X20010658022ACAFE0200000000000001L', - hex(self.ipv6).upper()) + self.assertEqual(hex(0x1020304), hex(self.ipv4)) + + self.assertEqual(hex(0x20010658022ACAFE0200000000000001), + hex(self.ipv6)) if __name__ == '__main__': diff --git a/trunk/test-2to3.sh b/trunk/test-2to3.sh new file mode 100644 index 0000000..408d665 --- /dev/null +++ b/trunk/test-2to3.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +# Converts the python2 ipaddr files to python3 and runs the unit tests +# with both python versions. + +mkdir -p 2to3output && \ +cp -f *.py 2to3output && \ +( cd 2to3output && 2to3 . | patch -p0 ) && \ +py3version=$(python3 --version 2>&1) && \ +echo -e "\nTesting with ${py3version}" && \ +python3 2to3output/ipaddr_test.py && \ +rm -r 2to3output && \ +pyversion=$(python --version 2>&1) && \ +echo -e "\nTesting with ${pyversion}" && \ +./ipaddr_test.py |