diff options
| author | Philipp Hagemeister <phihag@phihag.de> | 2017-12-16 10:13:51 +0100 |
|---|---|---|
| committer | Philipp Hagemeister <phihag@phihag.de> | 2017-12-16 10:13:51 +0100 |
| commit | d17c2deb1298706ac6de07eab1926905a72360a4 (patch) | |
| tree | 45dd9717af6004730d4ce336b6beb909de7b73d8 | |
| parent | ea9945d8b80552069aabddf197c7447953280d00 (diff) | |
| download | platform_external_python_ipaddress-d17c2deb1298706ac6de07eab1926905a72360a4.tar.gz platform_external_python_ipaddress-d17c2deb1298706ac6de07eab1926905a72360a4.tar.bz2 platform_external_python_ipaddress-d17c2deb1298706ac6de07eab1926905a72360a4.zip | |
update to upstream (git: 91dc64ba3f51100540b2ab6c6cd72c3bb18a6d49)
| -rw-r--r-- | ipaddress.py | 37 | ||||
| -rw-r--r-- | test_ipaddress.py | 136 |
2 files changed, 149 insertions, 24 deletions
diff --git a/ipaddress.py b/ipaddress.py index 20f33cb..263bcad 100644 --- a/ipaddress.py +++ b/ipaddress.py @@ -776,8 +776,7 @@ class _BaseNetwork(_IPAddressBase): if not isinstance(other, _BaseNetwork): raise TypeError("%s is not a network object" % other) - if not (other.network_address >= self.network_address and - other.broadcast_address <= self.broadcast_address): + if not other.subnet_of(self): raise ValueError('%s not contained in %s' % (other, self)) if other == self: return @@ -788,12 +787,10 @@ class _BaseNetwork(_IPAddressBase): s1, s2 = self.subnets() while s1 != other and s2 != other: - if (other.network_address >= s1.network_address and - other.broadcast_address <= s1.broadcast_address): + if other.subnet_of(s1): yield s2 s1, s2 = s1.subnets() - elif (other.network_address >= s2.network_address and - other.broadcast_address <= s2.broadcast_address): + elif other.subnet_of(s2): yield s1 s1, s2 = s2.subnets() else: @@ -975,6 +972,26 @@ class _BaseNetwork(_IPAddressBase): return (self.network_address.is_multicast and self.broadcast_address.is_multicast) + @staticmethod + def _is_subnet_of(a, b): + try: + # Always false if one is v4 and the other is v6. + if a._version != b._version: + raise TypeError(f"{a} and {b} are not of the same version") + return (b.network_address <= a.network_address and + b.broadcast_address >= a.broadcast_address) + except AttributeError: + raise TypeError(f"Unable to test subnet containment " + f"between {a} and {b}") + + def subnet_of(self, other): + """Return True if this network is a subnet of other.""" + return self._is_subnet_of(self, other) + + def supernet_of(self, other): + """Return True if this network is a supernet of other.""" + return self._is_subnet_of(other, self) + @property def is_reserved(self): """Test if the address is otherwise IETF reserved. @@ -1410,7 +1427,8 @@ class IPv4Interface(IPv4Address): if address_less is NotImplemented: return NotImplemented try: - return self.network < other.network + return (self.network < other.network or + self.network == other.network and address_less) except AttributeError: # We *do* allow addresses and interfaces to be sorted. The # unassociated address is considered less than all interfaces. @@ -2100,7 +2118,8 @@ class IPv6Interface(IPv6Address): if address_less is NotImplemented: return NotImplemented try: - return self.network < other.network + return (self.network < other.network or + self.network == other.network and address_less) except AttributeError: # We *do* allow addresses and interfaces to be sorted. The # unassociated address is considered less than all interfaces. @@ -2294,4 +2313,4 @@ class _IPv6Constants: _sitelocal_network = IPv6Network('fec0::/10') -IPv6Address._constants = _IPv6Constants +IPv6Address._constants = _IPv6Constants
\ No newline at end of file diff --git a/test_ipaddress.py b/test_ipaddress.py index 5f08f0c..a4fdc7e 100644 --- a/test_ipaddress.py +++ b/test_ipaddress.py @@ -92,7 +92,6 @@ class CommonTestMixin: y = pickle.loads(pickle.dumps(x, proto)) self.assertEqual(y, x) - class CommonTestMixin_v4(CommonTestMixin): def test_leading_zeros(self): @@ -119,7 +118,7 @@ class CommonTestMixin_v4(CommonTestMixin): def test_bad_packed_length(self): def assertBadLength(length): - addr = bytes(length) + addr = b'\0' * length msg = "%r (len %d != 4) is not permitted as an IPv4 address" with self.assertAddressError(re.escape(msg % (addr, length))): self.factory(addr) @@ -139,11 +138,11 @@ class CommonTestMixin_v6(CommonTestMixin): self.assertInstancesEqual(3232235521, "::c0a8:1") def test_packed(self): - addr = bytes(12) + bytes.fromhex("00000000") + addr = b'\0'*12 + bytes.fromhex("00000000") self.assertInstancesEqual(addr, "::") - addr = bytes(12) + bytes.fromhex("c0a80001") + addr = b'\0'*12 + bytes.fromhex("c0a80001") self.assertInstancesEqual(addr, "::c0a8:1") - addr = bytes.fromhex("c0a80001") + bytes(12) + addr = bytes.fromhex("c0a80001") + b'\0'*12 self.assertInstancesEqual(addr, "c0a8:1::") def test_negative_ints_rejected(self): @@ -158,7 +157,7 @@ class CommonTestMixin_v6(CommonTestMixin): def test_bad_packed_length(self): def assertBadLength(length): - addr = bytes(length) + addr = b'\0' * length msg = "%r (len %d != 16) is not permitted as an IPv6 address" with self.assertAddressError(re.escape(msg % (addr, length))): self.factory(addr) @@ -477,6 +476,56 @@ class InterfaceTestCase_v4(BaseTestCase, NetmaskTestMixin_v4): class NetworkTestCase_v4(BaseTestCase, NetmaskTestMixin_v4): factory = ipaddress.IPv4Network + def test_subnet_of(self): + # containee left of container + self.assertFalse( + self.factory('10.0.0.0/30').subnet_of( + self.factory('10.0.1.0/24'))) + # containee inside container + self.assertTrue( + self.factory('10.0.0.0/30').subnet_of( + self.factory('10.0.0.0/24'))) + # containee right of container + self.assertFalse( + self.factory('10.0.0.0/30').subnet_of( + self.factory('10.0.1.0/24'))) + # containee larger than container + self.assertFalse( + self.factory('10.0.1.0/24').subnet_of( + self.factory('10.0.0.0/30'))) + + def test_supernet_of(self): + # containee left of container + self.assertFalse( + self.factory('10.0.0.0/30').supernet_of( + self.factory('10.0.1.0/24'))) + # containee inside container + self.assertFalse( + self.factory('10.0.0.0/30').supernet_of( + self.factory('10.0.0.0/24'))) + # containee right of container + self.assertFalse( + self.factory('10.0.0.0/30').supernet_of( + self.factory('10.0.1.0/24'))) + # containee larger than container + self.assertTrue( + self.factory('10.0.0.0/24').supernet_of( + self.factory('10.0.0.0/30'))) + + def test_subnet_of_mixed_types(self): + with self.assertRaises(TypeError): + ipaddress.IPv4Network('10.0.0.0/30').supernet_of( + ipaddress.IPv6Network('::1/128')) + with self.assertRaises(TypeError): + ipaddress.IPv6Network('::1/128').supernet_of( + ipaddress.IPv4Network('10.0.0.0/30')) + with self.assertRaises(TypeError): + ipaddress.IPv4Network('10.0.0.0/30').subnet_of( + ipaddress.IPv6Network('::1/128')) + with self.assertRaises(TypeError): + ipaddress.IPv6Network('::1/128').subnet_of( + ipaddress.IPv4Network('10.0.0.0/30')) + class NetmaskTestMixin_v6(CommonTestMixin_v6): """Input validation on interfaces and networks is very similar""" @@ -540,6 +589,42 @@ class InterfaceTestCase_v6(BaseTestCase, NetmaskTestMixin_v6): class NetworkTestCase_v6(BaseTestCase, NetmaskTestMixin_v6): factory = ipaddress.IPv6Network + def test_subnet_of(self): + # containee left of container + self.assertFalse( + self.factory('2000:999::/56').subnet_of( + self.factory('2000:aaa::/48'))) + # containee inside container + self.assertTrue( + self.factory('2000:aaa::/56').subnet_of( + self.factory('2000:aaa::/48'))) + # containee right of container + self.assertFalse( + self.factory('2000:bbb::/56').subnet_of( + self.factory('2000:aaa::/48'))) + # containee larger than container + self.assertFalse( + self.factory('2000:aaa::/48').subnet_of( + self.factory('2000:aaa::/56'))) + + def test_supernet_of(self): + # containee left of container + self.assertFalse( + self.factory('2000:999::/56').supernet_of( + self.factory('2000:aaa::/48'))) + # containee inside container + self.assertFalse( + self.factory('2000:aaa::/56').supernet_of( + self.factory('2000:aaa::/48'))) + # containee right of container + self.assertFalse( + self.factory('2000:bbb::/56').supernet_of( + self.factory('2000:aaa::/48'))) + # containee larger than container + self.assertTrue( + self.factory('2000:aaa::/48').supernet_of( + self.factory('2000:aaa::/56'))) + class FactoryFunctionErrors(BaseTestCase): @@ -1405,14 +1490,35 @@ class IpaddrUnitTest(unittest.TestCase): ipaddress.ip_address('::2')) def testInterfaceComparison(self): - self.assertTrue(ipaddress.ip_interface('1.1.1.1') <= - ipaddress.ip_interface('1.1.1.1')) - self.assertTrue(ipaddress.ip_interface('1.1.1.1') <= - ipaddress.ip_interface('1.1.1.2')) - self.assertTrue(ipaddress.ip_interface('::1') <= - ipaddress.ip_interface('::1')) - self.assertTrue(ipaddress.ip_interface('::1') <= - ipaddress.ip_interface('::2')) + self.assertTrue(ipaddress.ip_interface('1.1.1.1/24') == + ipaddress.ip_interface('1.1.1.1/24')) + self.assertTrue(ipaddress.ip_interface('1.1.1.1/16') < + ipaddress.ip_interface('1.1.1.1/24')) + self.assertTrue(ipaddress.ip_interface('1.1.1.1/24') < + ipaddress.ip_interface('1.1.1.2/24')) + self.assertTrue(ipaddress.ip_interface('1.1.1.2/16') < + ipaddress.ip_interface('1.1.1.1/24')) + self.assertTrue(ipaddress.ip_interface('1.1.1.1/24') > + ipaddress.ip_interface('1.1.1.1/16')) + self.assertTrue(ipaddress.ip_interface('1.1.1.2/24') > + ipaddress.ip_interface('1.1.1.1/24')) + self.assertTrue(ipaddress.ip_interface('1.1.1.1/24') > + ipaddress.ip_interface('1.1.1.2/16')) + + self.assertTrue(ipaddress.ip_interface('::1/64') == + ipaddress.ip_interface('::1/64')) + self.assertTrue(ipaddress.ip_interface('::1/64') < + ipaddress.ip_interface('::1/80')) + self.assertTrue(ipaddress.ip_interface('::1/64') < + ipaddress.ip_interface('::2/64')) + self.assertTrue(ipaddress.ip_interface('::2/48') < + ipaddress.ip_interface('::1/64')) + self.assertTrue(ipaddress.ip_interface('::1/80') > + ipaddress.ip_interface('::1/64')) + self.assertTrue(ipaddress.ip_interface('::2/64') > + ipaddress.ip_interface('::1/64')) + self.assertTrue(ipaddress.ip_interface('::1/64') > + ipaddress.ip_interface('::2/48')) def testNetworkComparison(self): # ip1 and ip2 have the same network address @@ -1948,4 +2054,4 @@ class IpaddrUnitTest(unittest.TestCase): if __name__ == '__main__': - unittest.main() + unittest.main()
\ No newline at end of file |
