gh-156680: Raise the documented error from IPv6Network.next_network() - #156681
Conversation
…work() 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.
|
Also, reviewing fadb785 please fix the docstring of |
|
Oh and one more thing. I don't quite understand why we're doing this little dance with Apologies for all the changes I've asked you to make, indeed it grew to be quite a long list. As such, here's a patch instead: --- 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
@@ -1150,15 +1154,13 @@ 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__((next_ip, next_prefix)) |
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().
Documentation build overview
|
|
@StanFromIreland Thanks for the comments! Implemented all. |
StanFromIreland
left a comment
There was a problem hiding this comment.
Thanks, this looks good to me. @orsenthil can you please take a look as well?
| ) from None | ||
| ) | ||
|
|
||
| return self.__class__((next_ip, next_prefix)) |
There was a problem hiding this comment.
While technically this style can be used self.__class__((next_ip, next_prefix)) m because IPv4Network and IPv6Network do the _split_addr_prefix, we do not advertise or mention about this the value of the address argument. This styled tripped me a bit.
I would prefer the previous style.
return self.__class__(
f"{self._string_from_ip_int(next_ip)}/{next_prefix}"
)
Because of what we say address can be in the doc strings of the class.
There was a problem hiding this comment.
I realize that public docs document that.
https://docs.python.org/3/library/ipaddress.html#ipaddress.IPv4Network
https://docs.python.org/3/library/ipaddress.html#ipaddress.IPv6Network
The change might simply be a follow up doc string patch on here.
Lines 2301 to 2319 in a6d25db
|
Thanks for the patch @fedonman and review and ping @StanFromIreland . |
|
@StanFromIreland - could you please review this follow up PR #157280 |

Range-check
next_ipagainst_ALL_ONESinnext_network()instead of catchingOverflowError, which only the IPv4 path raises. The IPv6 path went through_BaseV6._string_from_ip_int(), whoseValueErrorescaped uncaught.next_network()is new in 3.16 and unreleased, so this is folded into the entry the method landed with and needs no NEWS fragment.IPv6Network.next_network()raises the wrong error when addresses run out #156680