From 31bac901e265958bc74e91b9222f082d4bdf3df6 Mon Sep 17 00:00:00 2001 From: Faisal Mahmood Date: Sat, 9 Jan 2021 17:31:42 +0000 Subject: [PATCH 01/11] Added next_network() method to Lib.ipaddress --- Lib/ipaddress.py | 42 ++++++++++++++++++++++++++++++++++++++ Lib/test/test_ipaddress.py | 42 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py index f1062a8cd052a5..1bd5a334f10415 100644 --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -1120,6 +1120,48 @@ def is_loopback(self): self.broadcast_address.is_loopback) + def next_network(self, next_prefix=None): + """Get the next closest network with a specific prefix. + + Args: + next_prefix: The desired next prefix length, if not specified the + same self.prefixlen will be used + + Returns: + An IPv(4|6) Network object of the next closest network. + + """ + if next_prefix is None: + next_prefix = self.prefixlen + new_netmask = self.netmask + else: + if next_prefix < 1 or next_prefix > self.max_prefixlen: + raise ValueError( + f"next prefix must be between 1 and {self.max_prefixlen}" + ) + new_netmask, _ = self._make_netmask(next_prefix) + + bit_shift = ( + self.max_prefixlen - next_prefix + if next_prefix <= self.prefixlen + else self.max_prefixlen - self.prefixlen + ) + + next_ip = ( + ((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: + raise ValueError( + f"out of address space, cannot make another /{next_prefix} " + "network" + ) from None + + class _BaseConstants: _private_networks = [] diff --git a/Lib/test/test_ipaddress.py b/Lib/test/test_ipaddress.py index 3f017b97dc28a3..554c192c70057e 100644 --- a/Lib/test/test_ipaddress.py +++ b/Lib/test/test_ipaddress.py @@ -1559,6 +1559,48 @@ def testHosts(self): self.assertEqual(list(ipaddress.ip_network(str_args).hosts()), list(ipaddress.ip_network(tpl_args).hosts())) + def testNextNetwork(self): + ipv4 = ipaddress.IPv4Network('1.2.3.0/24') + self.assertEqual( + ipv4.next_network(), + ipaddress.IPv4Network('1.2.4.0/24'), + ) + self.assertEqual( + ipv4.next_network(next_prefix=16), + ipaddress.IPv4Network('1.3.0.0/16'), + ) + self.assertEqual( + ipv4.next_network(next_prefix=25), + ipaddress.IPv4Network('1.2.4.0/25'), + ) + + ipv6 = ipaddress.IPv6Network('2001:dbb8:aaaa:aaaa::/64') + self.assertEqual( + ipv6.next_network(), + ipaddress.IPv6Network('2001:dbb8:aaaa:aaab::/64'), + ) + self.assertEqual( + ipv6.next_network(next_prefix=48), + ipaddress.IPv6Network('2001:dbb8:aaab::/48'), + ) + self.assertEqual( + ipv6.next_network(next_prefix=88), + ipaddress.IPv6Network('2001:dbb8:aaaa:aaab::/88'), + ) + + + def testNextNetworkWithBadPrefix(self): + self.assertRaises(ValueError, self.ipv4_network.next_network, 0) + self.assertRaises(ValueError, self.ipv4_network.next_network, 35) + self.assertRaises(ValueError, self.ipv6_network.next_network, 0) + self.assertRaises(ValueError, self.ipv6_network.next_network, 150) + + def testNextNetworkOutOfAddressSpace(self): + ipv4 = ipaddress.IPv4Network('255.255.255.0/24') + self.assertRaises(ValueError, ipv4.next_network) + ipv6 = ipaddress.IPv6Network('ffff:ffff:ffff:ffff:ffff:ffff:ffff:0/112') + self.assertRaises(ValueError, ipv6.next_network) + def testFancySubnetting(self): self.assertEqual(sorted(self.ipv4_network.subnets(prefixlen_diff=3)), sorted(self.ipv4_network.subnets(new_prefix=27))) From 944ce704a3879d1d54fe04664eb60da3f94647a4 Mon Sep 17 00:00:00 2001 From: Faisal Mahmood Date: Sat, 9 Jan 2021 19:14:32 +0000 Subject: [PATCH 02/11] Update docs --- Doc/library/ipaddress.rst | 29 +++++++++++++++++++ Doc/whatsnew/3.10.rst | 7 +++++ .../2021-01-09-18-40-15.bpo-42861.T7Ge9O.rst | 1 + 3 files changed, 37 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2021-01-09-18-40-15.bpo-42861.T7Ge9O.rst diff --git a/Doc/library/ipaddress.rst b/Doc/library/ipaddress.rst index 9ccd8602bcb2c3..f113e206732c3e 100644 --- a/Doc/library/ipaddress.rst +++ b/Doc/library/ipaddress.rst @@ -718,6 +718,30 @@ dictionaries. .. deprecated:: 3.7 It uses the same ordering and comparison algorithm as "<", "==", and ">" + .. method:: next_network(next_prefix=None) + + Finds the next closest network of prefix size *next_prefix*. If + *next_prefix=None*, then the current network prefix will be used. + Returns a single network object. + + >>> IPv4Network('192.0.2.0/24').next_network() + IPv4Network('192.0.3.0/24') + >>> IPv4Network('192.0.2.0/24').next_network(next_prefix=25) + IPv4Network('192.0.3.0/25') + >>> IPv4Network('192.0.2.0/24').next_network(next_prefix=23) + IPv4Network('192.0.4.0/23') + >>> IPv4Network('192.0.80.0/22').next_network(next_prefix=18) + IPv4Network('192.0.128.0/18') + >>> IPv4Network('192.0.80.0/22').next_network(next_prefix=50) + Traceback (most recent call last): + File "", line 1, in + raise ValueError( + ValueError: next prefix must be between 1 and 32 + >>> IPv4Network('255.255.255.0/24').next_network() + Traceback (most recent call last): + File "", line 1, in + raise ValueError( + ValueError: out of address space, cannot make another /24 network .. class:: IPv6Network(address, strict=True) @@ -795,6 +819,11 @@ dictionaries. Refer to the corresponding attribute documentation in :class:`IPv4Network`. + .. method:: next_network(next_prefix=None) + + Refer to the corresponding attribute documentation in + :class:`IPv4Network`. + .. attribute:: is_site_local This attribute is true for the network as a whole if it is true diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst index 390b82d5a1fdc1..39060c386f0c65 100644 --- a/Doc/whatsnew/3.10.rst +++ b/Doc/whatsnew/3.10.rst @@ -1237,6 +1237,13 @@ itertools Add :func:`itertools.pairwise`. (Contributed by Raymond Hettinger in :issue:`38200`.) +ipaddress +--------- + +XXX Add :func:`_BaseNetwork.next_network` to support finding the next closest +network. +(Contributed by Faisal Mahmood in :issue:`42861`.) + linecache --------- 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 new file mode 100644 index 00000000000000..5233239e428908 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2021-01-09-18-40-15.bpo-42861.T7Ge9O.rst @@ -0,0 +1 @@ +Add :func:`_BaseNetwork.next_network` method. Patch by Faisal Mahmood. From 3ce73abe178d7cb005b4ac7443b154cb4b07c6ce Mon Sep 17 00:00:00 2001 From: Faisal Mahmood Date: Sat, 9 Jan 2021 21:04:29 +0000 Subject: [PATCH 03/11] Resolve whitespace error in documentation --- Doc/library/ipaddress.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/ipaddress.rst b/Doc/library/ipaddress.rst index f113e206732c3e..4358ffc65945d6 100644 --- a/Doc/library/ipaddress.rst +++ b/Doc/library/ipaddress.rst @@ -721,7 +721,7 @@ dictionaries. .. method:: next_network(next_prefix=None) Finds the next closest network of prefix size *next_prefix*. If - *next_prefix=None*, then the current network prefix will be used. + *next_prefix=None*, then the current network prefix will be used. #doctest: +NORMALIZE_WHITESPACE Returns a single network object. >>> IPv4Network('192.0.2.0/24').next_network() From ff3817e5ccd07b4c1f852c875e94aa9d54958a9d Mon Sep 17 00:00:00 2001 From: Killer Kode Date: Mon, 15 Feb 2021 22:54:13 +0000 Subject: [PATCH 04/11] Added to next_network method in the docs --- Doc/library/ipaddress.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Doc/library/ipaddress.rst b/Doc/library/ipaddress.rst index 4358ffc65945d6..725d46ac9d081f 100644 --- a/Doc/library/ipaddress.rst +++ b/Doc/library/ipaddress.rst @@ -743,6 +743,8 @@ dictionaries. raise ValueError( ValueError: out of address space, cannot make another /24 network + .. versionadded:: 3.10 + .. class:: IPv6Network(address, strict=True) Construct an IPv6 network definition. *address* can be one of the following: From c3afdad9396de10cc5bdb32ac94f9827072d6785 Mon Sep 17 00:00:00 2001 From: Killer Kode Date: Mon, 15 Feb 2021 22:54:31 +0000 Subject: [PATCH 05/11] Removed whitespace --- Lib/test/test_ipaddress.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Lib/test/test_ipaddress.py b/Lib/test/test_ipaddress.py index 554c192c70057e..a74b692784eb59 100644 --- a/Lib/test/test_ipaddress.py +++ b/Lib/test/test_ipaddress.py @@ -1588,7 +1588,6 @@ def testNextNetwork(self): ipaddress.IPv6Network('2001:dbb8:aaaa:aaab::/88'), ) - def testNextNetworkWithBadPrefix(self): self.assertRaises(ValueError, self.ipv4_network.next_network, 0) self.assertRaises(ValueError, self.ipv4_network.next_network, 35) From b623ea065ad070c624c3dfe34b72d2020b7020f6 Mon Sep 17 00:00:00 2001 From: Killer Kode Date: Mon, 15 Feb 2021 22:55:36 +0000 Subject: [PATCH 06/11] Tweaked next_network description in for version 3.10 --- Doc/whatsnew/3.10.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst index 39060c386f0c65..9758a932983fae 100644 --- a/Doc/whatsnew/3.10.rst +++ b/Doc/whatsnew/3.10.rst @@ -1240,8 +1240,8 @@ Add :func:`itertools.pairwise`. ipaddress --------- -XXX Add :func:`_BaseNetwork.next_network` to support finding the next closest -network. +Add :func:`IPv4Network.next_network` and :func:`IPv6Network.next_network` +methods to find the next nearest network with a specific prefix size. (Contributed by Faisal Mahmood in :issue:`42861`.) linecache From 485d5309eee5a7d3320e6e4dea9343134a93e51d Mon Sep 17 00:00:00 2001 From: Killer Kode Date: Tue, 16 Feb 2021 00:17:21 +0000 Subject: [PATCH 07/11] Move next_network method next to other methods in ipaddress docs --- Doc/library/ipaddress.rst | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Doc/library/ipaddress.rst b/Doc/library/ipaddress.rst index 725d46ac9d081f..5865b9045b69aa 100644 --- a/Doc/library/ipaddress.rst +++ b/Doc/library/ipaddress.rst @@ -816,12 +816,8 @@ dictionaries. .. method:: supernet(prefixlen_diff=1, new_prefix=None) .. method:: subnet_of(other) .. method:: supernet_of(other) - .. method:: compare_networks(other) - - Refer to the corresponding attribute documentation in - :class:`IPv4Network`. - .. method:: next_network(next_prefix=None) + .. method:: compare_networks(other) Refer to the corresponding attribute documentation in :class:`IPv4Network`. From fbd4ab9770694162a6a7dc71192f917f7a8f1ef8 Mon Sep 17 00:00:00 2001 From: Senthil Kumaran Date: Tue, 7 Jul 2026 07:54:05 -0700 Subject: [PATCH 08/11] Update whatsnew with correct Python version. --- Doc/whatsnew/3.10.rst | 7 ------- Doc/whatsnew/3.16.rst | 8 ++++++++ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst index 9758a932983fae..390b82d5a1fdc1 100644 --- a/Doc/whatsnew/3.10.rst +++ b/Doc/whatsnew/3.10.rst @@ -1237,13 +1237,6 @@ itertools Add :func:`itertools.pairwise`. (Contributed by Raymond Hettinger in :issue:`38200`.) -ipaddress ---------- - -Add :func:`IPv4Network.next_network` and :func:`IPv6Network.next_network` -methods to find the next nearest network with a specific prefix size. -(Contributed by Faisal Mahmood in :issue:`42861`.) - linecache --------- diff --git a/Doc/whatsnew/3.16.rst b/Doc/whatsnew/3.16.rst index dd2c7b68d03992..85803278f49749 100644 --- a/Doc/whatsnew/3.16.rst +++ b/Doc/whatsnew/3.16.rst @@ -245,6 +245,14 @@ imaplib (Contributed by Przemysław Buczkowski and Serhiy Storchaka in :gh:`89869`.) +ipaddress +--------- + +Add :func:`IPv4Network.next_network` and :func:`IPv6Network.next_network` +methods to find the next nearest network with a specific prefix size. +(Contributed by Faisal Mahmood in :issue:`42861`.) + + logging ------- From f47c702e60c43fe225b7f70c3fe9dad71cf4eaa3 Mon Sep 17 00:00:00 2001 From: Senthil Kumaran Date: Tue, 7 Jul 2026 08:53:38 -0700 Subject: [PATCH 09/11] Address the make docs failure. --- Doc/library/ipaddress.rst | 2 +- Doc/whatsnew/3.16.rst | 6 +++--- .../next/Library/2021-01-09-18-40-15.bpo-42861.T7Ge9O.rst | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Doc/library/ipaddress.rst b/Doc/library/ipaddress.rst index 5865b9045b69aa..de6cefc596a016 100644 --- a/Doc/library/ipaddress.rst +++ b/Doc/library/ipaddress.rst @@ -743,7 +743,7 @@ dictionaries. raise ValueError( ValueError: out of address space, cannot make another /24 network - .. versionadded:: 3.10 + .. versionadded:: 3.16 .. class:: IPv6Network(address, strict=True) diff --git a/Doc/whatsnew/3.16.rst b/Doc/whatsnew/3.16.rst index 85803278f49749..1efce912b64367 100644 --- a/Doc/whatsnew/3.16.rst +++ b/Doc/whatsnew/3.16.rst @@ -248,9 +248,9 @@ imaplib ipaddress --------- -Add :func:`IPv4Network.next_network` and :func:`IPv6Network.next_network` -methods to find the next nearest network with a specific prefix size. -(Contributed by Faisal Mahmood in :issue:`42861`.) +Add :meth:`~ipaddress.IPv4Network.next_network` and +:meth:`~ipaddress.IPv6Network.next_network` methods to find the next nearest +network with a specific prefix size. logging 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 5233239e428908..46ed99d1e1b499 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 +1,2 @@ -Add :func:`_BaseNetwork.next_network` method. Patch by Faisal Mahmood. +Add :meth:`~ipaddress.IPv4Network.next_network` and +:meth:`~ipaddress.IPv6Network.next_network`. Patch by Faisal Mahmood. From 2e1326798692368e9463f08b7102c784791684cb Mon Sep 17 00:00:00 2001 From: Senthil Kumaran Date: Tue, 7 Jul 2026 23:08:01 -0700 Subject: [PATCH 10/11] fix minor extra line. --- Lib/ipaddress.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py index 1bd5a334f10415..9c7a0a46f4f0e1 100644 --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -1119,7 +1119,6 @@ def is_loopback(self): return (self.network_address.is_loopback and self.broadcast_address.is_loopback) - def next_network(self, next_prefix=None): """Get the next closest network with a specific prefix. From 28f195c9b52432edcf71ba634ba74ebb22ff4eaf Mon Sep 17 00:00:00 2001 From: Senthil Kumaran Date: Wed, 8 Jul 2026 05:46:44 -0700 Subject: [PATCH 11/11] Fix the Docstring. Remove unnecessary doctest directive, and add a note on ValueError Exception raised. --- Doc/library/ipaddress.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Doc/library/ipaddress.rst b/Doc/library/ipaddress.rst index de6cefc596a016..387d8034bb8c84 100644 --- a/Doc/library/ipaddress.rst +++ b/Doc/library/ipaddress.rst @@ -721,9 +721,12 @@ dictionaries. .. method:: next_network(next_prefix=None) Finds the next closest network of prefix size *next_prefix*. If - *next_prefix=None*, then the current network prefix will be used. #doctest: +NORMALIZE_WHITESPACE + *next_prefix=None*, then the current network prefix will be used. Returns a single network object. + Raises :exc:`ValueError` if *next_prefix* is out of range or no further + network of the requested size exists. + >>> IPv4Network('192.0.2.0/24').next_network() IPv4Network('192.0.3.0/24') >>> IPv4Network('192.0.2.0/24').next_network(next_prefix=25)