[Python-checkins] bpo-28577: Special case added to IP v4 and v6 hosts for /32 and /128 networks (GH-18757)

Pete Wicken webhook-mailer at python.org
Mon Mar 9 18:33:53 EDT 2020


https://github.com/python/cpython/commit/8e9c47a947954c997d4b725f4551d50a1d896722
commit: 8e9c47a947954c997d4b725f4551d50a1d896722
branch: master
author: Pete Wicken <2273100+JamoBox at users.noreply.github.com>
committer: GitHub <noreply at github.com>
date: 2020-03-09T15:33:45-07:00
summary:

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.

files:
A Misc/NEWS.d/next/Library/2020-03-02-23-52-38.bpo-28577.EK91ae.rst
M Doc/library/ipaddress.rst
M Lib/ipaddress.py
M Lib/test/test_ipaddress.py
M Misc/ACKS

diff --git a/Doc/library/ipaddress.rst b/Doc/library/ipaddress.rst
index 5938439941792..5f5e66412da47 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 702433953a1e2..ac1143acba426 100644
--- a/Lib/ipaddress.py
+++ b/Lib/ipaddress.py
@@ -1509,6 +1509,8 @@ def __init__(self, address, strict=True):
 
         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 @@ def __init__(self, address, strict=True):
 
         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 f4a4afba76a99..bbb3fc89da653 100644
--- a/Lib/test/test_ipaddress.py
+++ b/Lib/test/test_ipaddress.py
@@ -1424,14 +1424,15 @@ def testHosts(self):
         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 @@ def testHosts(self):
         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 5ec93a43755af..cc5694af008b3 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 0000000000000..de4c064378c24
--- /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.



More information about the Python-checkins mailing list