summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPete Wicken <2273100+JamoBox@users.noreply.github.com>2020-03-09 22:33:45 (GMT)
committerGitHub <noreply@github.com>2020-03-09 22:33:45 (GMT)
commit8e9c47a947954c997d4b725f4551d50a1d896722 (patch)
tree72a0d1e8aaf5962503c008323ce8ada7f037e8eb
parent9229eeee105f19705f72e553cf066751ac47c7b7 (diff)
downloadcpython-8e9c47a947954c997d4b725f4551d50a1d896722.zip
cpython-8e9c47a947954c997d4b725f4551d50a1d896722.tar.gz
cpython-8e9c47a947954c997d4b725f4551d50a1d896722.tar.bz2
bpo-28577: Special case added to IP v4 and v6 hosts for /32 and /128 networks (GH-18757)
The `.hosts()` method now returns the single address present in a /32 or /128 network.
-rw-r--r--Doc/library/ipaddress.rst7
-rw-r--r--Lib/ipaddress.py4
-rw-r--r--Lib/test/test_ipaddress.py17
-rw-r--r--Misc/ACKS1
-rw-r--r--Misc/NEWS.d/next/Library/2020-03-02-23-52-38.bpo-28577.EK91ae.rst1
5 files changed, 25 insertions, 5 deletions
diff --git a/Doc/library/ipaddress.rst b/Doc/library/ipaddress.rst
index 5938439..5f5e664 100644
--- a/Doc/library/ipaddress.rst
+++ b/Doc/library/ipaddress.rst
@@ -509,7 +509,8 @@ dictionaries.
hosts are all the IP addresses that belong to the network, except the
network address itself and the network broadcast address. For networks
with a mask length of 31, the network address and network broadcast
- address are also included in the result.
+ address are also included in the result. Networks with a mask of 32
+ will return a list containing the single host address.
>>> list(ip_network('192.0.2.0/29').hosts()) #doctest: +NORMALIZE_WHITESPACE
[IPv4Address('192.0.2.1'), IPv4Address('192.0.2.2'),
@@ -517,6 +518,8 @@ dictionaries.
IPv4Address('192.0.2.5'), IPv4Address('192.0.2.6')]
>>> list(ip_network('192.0.2.0/31').hosts())
[IPv4Address('192.0.2.0'), IPv4Address('192.0.2.1')]
+ >>> list(ip_network('192.0.2.1/32').hosts())
+ [IPv4Address('192.0.2.1')]
.. method:: overlaps(other)
@@ -678,6 +681,8 @@ dictionaries.
hosts are all the IP addresses that belong to the network, except the
Subnet-Router anycast address. For networks with a mask length of 127,
the Subnet-Router anycast address is also included in the result.
+ Networks with a mask of 128 will return a list containing the
+ single host address.
.. method:: overlaps(other)
.. method:: address_exclude(network)
diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py
index 7024339..ac1143a 100644
--- a/Lib/ipaddress.py
+++ b/Lib/ipaddress.py
@@ -1509,6 +1509,8 @@ class IPv4Network(_BaseV4, _BaseNetwork):
if self._prefixlen == (self._max_prefixlen - 1):
self.hosts = self.__iter__
+ elif self._prefixlen == (self._max_prefixlen):
+ self.hosts = lambda: [IPv4Address(addr)]
@property
@functools.lru_cache()
@@ -2212,6 +2214,8 @@ class IPv6Network(_BaseV6, _BaseNetwork):
if self._prefixlen == (self._max_prefixlen - 1):
self.hosts = self.__iter__
+ elif self._prefixlen == self._max_prefixlen:
+ self.hosts = lambda: [IPv6Address(addr)]
def hosts(self):
"""Generate Iterator over usable hosts in a network.
diff --git a/Lib/test/test_ipaddress.py b/Lib/test/test_ipaddress.py
index f4a4afb..bbb3fc8 100644
--- a/Lib/test/test_ipaddress.py
+++ b/Lib/test/test_ipaddress.py
@@ -1424,14 +1424,15 @@ class IpaddrUnitTest(unittest.TestCase):
self.assertEqual(list(ipaddress.ip_network(str_args).hosts()),
list(ipaddress.ip_network(tpl_args).hosts()))
- addrs = [ipaddress.IPv6Address('2001:658:22a:cafe::'),
- ipaddress.IPv6Address('2001:658:22a:cafe::1')]
- str_args = '2001:658:22a:cafe::/127'
- tpl_args = ('2001:658:22a:cafe::', 127)
+ # special case where the network is a /32
+ addrs = [ipaddress.IPv4Address('1.2.3.4')]
+ str_args = '1.2.3.4/32'
+ tpl_args = ('1.2.3.4', 32)
self.assertEqual(addrs, list(ipaddress.ip_network(str_args).hosts()))
self.assertEqual(addrs, list(ipaddress.ip_network(tpl_args).hosts()))
self.assertEqual(list(ipaddress.ip_network(str_args).hosts()),
list(ipaddress.ip_network(tpl_args).hosts()))
+
addrs = [ipaddress.IPv6Address('2001:658:22a:cafe::'),
ipaddress.IPv6Address('2001:658:22a:cafe::1')]
str_args = '2001:658:22a:cafe::/127'
@@ -1441,6 +1442,14 @@ class IpaddrUnitTest(unittest.TestCase):
self.assertEqual(list(ipaddress.ip_network(str_args).hosts()),
list(ipaddress.ip_network(tpl_args).hosts()))
+ addrs = [ipaddress.IPv6Address('2001:658:22a:cafe::1'), ]
+ str_args = '2001:658:22a:cafe::1/128'
+ tpl_args = ('2001:658:22a:cafe::1', 128)
+ self.assertEqual(addrs, list(ipaddress.ip_network(str_args).hosts()))
+ self.assertEqual(addrs, list(ipaddress.ip_network(tpl_args).hosts()))
+ self.assertEqual(list(ipaddress.ip_network(str_args).hosts()),
+ list(ipaddress.ip_network(tpl_args).hosts()))
+
def testFancySubnetting(self):
self.assertEqual(sorted(self.ipv4_network.subnets(prefixlen_diff=3)),
sorted(self.ipv4_network.subnets(new_prefix=27)))
diff --git a/Misc/ACKS b/Misc/ACKS
index 5ec93a4..cc5694a 100644
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -1823,6 +1823,7 @@ Jeff Wheeler
Christopher White
David White
Mats Wichmann
+Pete Wicken
Marcel Widjaja
Truida Wiedijk
Felix Wiemann
diff --git a/Misc/NEWS.d/next/Library/2020-03-02-23-52-38.bpo-28577.EK91ae.rst b/Misc/NEWS.d/next/Library/2020-03-02-23-52-38.bpo-28577.EK91ae.rst
new file mode 100644
index 0000000..de4c064
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2020-03-02-23-52-38.bpo-28577.EK91ae.rst
@@ -0,0 +1 @@
+The hosts method on 32-bit prefix length IPv4Networks and 128-bit prefix IPv6Networks now returns a list containing the single Address instead of an empty list.