diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py index 7469a9d6ddf..ca3031abb41 100644 --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -740,21 +740,21 @@ class _BaseNetwork(_IPAddressBase): addr1 = ip_network('192.0.2.0/28') addr2 = ip_network('192.0.2.1/32') - addr1.address_exclude(addr2) = + list(addr1.address_exclude(addr2)) = [IPv4Network('192.0.2.0/32'), IPv4Network('192.0.2.2/31'), - IPv4Network('192.0.2.4/30'), IPv4Network('192.0.2.8/29')] + IPv4Network('192.0.2.4/30'), IPv4Network('192.0.2.8/29')] or IPv6: addr1 = ip_network('2001:db8::1/32') addr2 = ip_network('2001:db8::1/128') - addr1.address_exclude(addr2) = + list(addr1.address_exclude(addr2)) = [ip_network('2001:db8::1/128'), - ip_network('2001:db8::2/127'), - ip_network('2001:db8::4/126'), - ip_network('2001:db8::8/125'), - ... - ip_network('2001:db8:8000::/33')] + ip_network('2001:db8::2/127'), + ip_network('2001:db8::4/126'), + ip_network('2001:db8::8/125'), + ... + ip_network('2001:db8:8000::/33')] Args: other: An IPv4Network or IPv6Network object of the same type. @@ -916,7 +916,7 @@ class _BaseNetwork(_IPAddressBase): new_prefixlen, self)) start = int(self.network_address) - end = int(self.broadcast_address) + end = int(self.broadcast_address) + 1 step = (int(self.hostmask) + 1) >> prefixlen_diff for new_addr in range(start, end, step): current = self.__class__((new_addr, new_prefixlen)) diff --git a/Lib/test/test_ipaddress.py b/Lib/test/test_ipaddress.py index 56f0be3ae8a..643d742e4cc 100644 --- a/Lib/test/test_ipaddress.py +++ b/Lib/test/test_ipaddress.py @@ -1066,6 +1066,26 @@ class IpaddrUnitTest(unittest.TestCase): '2001:658:22a:cafe:8000::/66', '2001:658:22a:cafe:c000::/66']) + def testGetSubnets3(self): + subnets = [str(x) for x in self.ipv4_network.subnets(8)] + self.assertEqual(subnets[:3], + ['1.2.3.0/32', '1.2.3.1/32', '1.2.3.2/32']) + self.assertEqual(subnets[-3:], + ['1.2.3.253/32', '1.2.3.254/32', '1.2.3.255/32']) + self.assertEqual(len(subnets), 256) + + ipv6_network = ipaddress.IPv6Network('2001:658:22a:cafe::/120') + subnets = [str(x) for x in ipv6_network.subnets(8)] + self.assertEqual(subnets[:3], + ['2001:658:22a:cafe::/128', + '2001:658:22a:cafe::1/128', + '2001:658:22a:cafe::2/128']) + self.assertEqual(subnets[-3:], + ['2001:658:22a:cafe::fd/128', + '2001:658:22a:cafe::fe/128', + '2001:658:22a:cafe::ff/128']) + self.assertEqual(len(subnets), 256) + def testSubnetFailsForLargeCidrDiff(self): self.assertRaises(ValueError, list, self.ipv4_interface.network.subnets(9)) @@ -1670,6 +1690,7 @@ class IpaddrUnitTest(unittest.TestCase): addr3 = ipaddress.ip_network('10.2.1.0/24') addr4 = ipaddress.ip_address('10.1.1.0') addr5 = ipaddress.ip_network('2001:db8::0/32') + addr6 = ipaddress.ip_network('10.1.1.5/32') self.assertEqual(sorted(list(addr1.address_exclude(addr2))), [ipaddress.ip_network('10.1.1.64/26'), ipaddress.ip_network('10.1.1.128/25')]) @@ -1677,6 +1698,15 @@ class IpaddrUnitTest(unittest.TestCase): self.assertRaises(TypeError, list, addr1.address_exclude(addr4)) self.assertRaises(TypeError, list, addr1.address_exclude(addr5)) self.assertEqual(list(addr1.address_exclude(addr1)), []) + self.assertEqual(sorted(list(addr1.address_exclude(addr6))), + [ipaddress.ip_network('10.1.1.0/30'), + ipaddress.ip_network('10.1.1.4/32'), + ipaddress.ip_network('10.1.1.6/31'), + ipaddress.ip_network('10.1.1.8/29'), + ipaddress.ip_network('10.1.1.16/28'), + ipaddress.ip_network('10.1.1.32/27'), + ipaddress.ip_network('10.1.1.64/26'), + ipaddress.ip_network('10.1.1.128/25')]) def testHash(self): self.assertEqual(hash(ipaddress.ip_interface('10.1.1.0/24')), diff --git a/Misc/NEWS b/Misc/NEWS index 315167e6a57..449f9e558de 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -194,6 +194,10 @@ Core and Builtins Library ------- +- Issue #26457: Fixed the subnets() methods in IP network classes for the case + when resulting prefix length is equal to maximal prefix length. + Based on patch by Xiang Zhang. + - Issue #26385: Remove the file if the internal open() call in NamedTemporaryFile() fails. Patch by Silent Ghost.