From 2aa3800ea0c64828dd4fac8349d9b3869ea59e92 Mon Sep 17 00:00:00 2001 From: Vyron Vasileiadis Date: Sun, 30 Aug 2026 22:38:59 +0300 Subject: [PATCH 1/2] gh-156680: Raise the documented error from IPv6Network.next_network() next_network() guarded address-space exhaustion with except OverflowError, which only int.to_bytes() on the IPv4 path raises. _BaseV6._string_from_ip_int() raises ValueError instead, so the handler never ran for IPv6 and the internal 'IPv6 address is too large' message escaped. Range-check next_ip against _ALL_ONES before formatting it, which decides the outcome for both address families before either path runs. --- Lib/ipaddress.py | 12 ++++++------ Lib/test/test_ipaddress.py | 10 ++++++++-- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py index 6978483544e621..e805cd0e2a0124 100644 --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -1150,15 +1150,15 @@ def next_network(self, next_prefix=None): ((new_netmask._ip & self.network_address._ip) >> bit_shift) + 1 ) << bit_shift - try: - return self.__class__( - f"{self._string_from_ip_int(next_ip)}/{next_prefix}" - ) - except OverflowError: + if next_ip > self._ALL_ONES: raise ValueError( f"out of address space, cannot make another /{next_prefix} " "network" - ) from None + ) + + return self.__class__( + f"{self._string_from_ip_int(next_ip)}/{next_prefix}" + ) class _BaseConstants: diff --git a/Lib/test/test_ipaddress.py b/Lib/test/test_ipaddress.py index 375d45172a9f4d..d6d0d8220449bd 100644 --- a/Lib/test/test_ipaddress.py +++ b/Lib/test/test_ipaddress.py @@ -1596,9 +1596,15 @@ def testNextNetworkWithBadPrefix(self): def testNextNetworkOutOfAddressSpace(self): ipv4 = ipaddress.IPv4Network('255.255.255.0/24') - self.assertRaises(ValueError, ipv4.next_network) + self.assertRaisesRegex( + ValueError, + 'out of address space, cannot make another /24 network', + ipv4.next_network) ipv6 = ipaddress.IPv6Network('ffff:ffff:ffff:ffff:ffff:ffff:ffff:0/112') - self.assertRaises(ValueError, ipv6.next_network) + self.assertRaisesRegex( + ValueError, + 'out of address space, cannot make another /112 network', + ipv6.next_network) def testFancySubnetting(self): self.assertEqual(sorted(self.ipv4_network.subnets(prefixlen_diff=3)), From e9745c356df36737ea8b9441a19019a19b45c013 Mon Sep 17 00:00:00 2001 From: Vyron Vasileiadis Date: Fri, 4 Sep 2026 17:45:50 +0300 Subject: [PATCH 2/2] Address review comments Finish the next_network() docstring: a period on the argument sentence and a Raises section for the two ValueError cases. Build the result from an (address, prefix) tuple rather than formatting and reparsing a string. Give the What's New and NEWS entries explicit link titles so the IPv4Network and IPv6Network methods no longer both render as next_network(). --- Doc/whatsnew/3.16.rst | 6 +++--- Lib/ipaddress.py | 10 ++++++---- .../Library/2021-01-09-18-40-15.bpo-42861.T7Ge9O.rst | 5 +++-- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/Doc/whatsnew/3.16.rst b/Doc/whatsnew/3.16.rst index 858dc3b8a878e7..127ba17bab5d2a 100644 --- a/Doc/whatsnew/3.16.rst +++ b/Doc/whatsnew/3.16.rst @@ -412,9 +412,9 @@ io ipaddress --------- -* Add :meth:`~ipaddress.IPv4Network.next_network` and - :meth:`~ipaddress.IPv6Network.next_network` methods to find the next nearest - network with a specific prefix size. +* Add :meth:`IPv4Network.next_network() ` + and :meth:`IPv6Network.next_network() ` + methods to find the next nearest network with a specific prefix size. (Contributed by Faisal Mahmood in :gh:`87027`.) diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py index e805cd0e2a0124..de489c0ed034bb 100644 --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -1124,11 +1124,15 @@ def next_network(self, next_prefix=None): Args: next_prefix: The desired next prefix length, if not specified the - same self.prefixlen will be used + same self.prefixlen will be used. Returns: An IPv(4|6) Network object of the next closest network. + Raises: + ValueError: If next_prefix is outside the range of valid prefix + lengths, or if no further network of that size exists. + """ if next_prefix is None: next_prefix = self.prefixlen @@ -1156,9 +1160,7 @@ def next_network(self, next_prefix=None): "network" ) - return self.__class__( - f"{self._string_from_ip_int(next_ip)}/{next_prefix}" - ) + return self.__class__((next_ip, next_prefix)) class _BaseConstants: diff --git a/Misc/NEWS.d/next/Library/2021-01-09-18-40-15.bpo-42861.T7Ge9O.rst b/Misc/NEWS.d/next/Library/2021-01-09-18-40-15.bpo-42861.T7Ge9O.rst index 46ed99d1e1b499..9de1e937278152 100644 --- a/Misc/NEWS.d/next/Library/2021-01-09-18-40-15.bpo-42861.T7Ge9O.rst +++ b/Misc/NEWS.d/next/Library/2021-01-09-18-40-15.bpo-42861.T7Ge9O.rst @@ -1,2 +1,3 @@ -Add :meth:`~ipaddress.IPv4Network.next_network` and -:meth:`~ipaddress.IPv6Network.next_network`. Patch by Faisal Mahmood. +Add :meth:`IPv4Network.next_network() ` +and :meth:`IPv6Network.next_network() `. +Patch by Faisal Mahmood.