summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Shields <mshields@google.com>2009-03-26 16:50:46 +0000
committerMichael Shields <mshields@google.com>2009-03-26 16:50:46 +0000
commit83c3f9f927acb519dd93073467af55799849495d (patch)
treedd938dedb01fe203921db2f0e958748e3f999e9b
parent775d4f4874b2f3416b3c1d1a5db9269cfe76274b (diff)
downloadipaddr-py-83c3f9f927acb519dd93073467af55799849495d.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/trunk@66 09200d28-7f98-11dd-ad27-0f66e57d2035
-rw-r--r--ipaddr.py75
-rwxr-xr-xipaddr_test.py81
-rw-r--r--test-2to3.sh15
3 files changed, 126 insertions, 45 deletions
diff --git a/ipaddr.py b/ipaddr.py
index 353daa5..7a2ae78 100644
--- a/ipaddr.py
+++ b/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/ipaddr_test.py b/ipaddr_test.py
index bbd3489..3432dc2 100755
--- a/ipaddr_test.py
+++ b/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/test-2to3.sh b/test-2to3.sh
new file mode 100644
index 0000000..408d665
--- /dev/null
+++ b/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