Skip to content

Commit 10ad7eb

Browse files
authored
[3.8] bpo-28577: Special case added to IP v4 and v6 hosts for /32 and /128 networks (pythonGH-18757) (python#25536)
The `.hosts()` method now returns the single address present in a /32 or /128 network.. (cherry picked from commit 8e9c47a) Co-authored-by: Pete Wicken <2273100+JamoBox@users.noreply.github.com>
1 parent 196b8f3 commit 10ad7eb

File tree

5 files changed

+29
-1
lines changed

5 files changed

+29
-1
lines changed

Doc/library/ipaddress.rst

+6-1
Original file line numberDiff line numberDiff line change
@@ -487,14 +487,17 @@ dictionaries.
487487
hosts are all the IP addresses that belong to the network, except the
488488
network address itself and the network broadcast address. For networks
489489
with a mask length of 31, the network address and network broadcast
490-
address are also included in the result.
490+
address are also included in the result. Networks with a mask of 32
491+
will return a list containing the single host address.
491492

492493
>>> list(ip_network('192.0.2.0/29').hosts()) #doctest: +NORMALIZE_WHITESPACE
493494
[IPv4Address('192.0.2.1'), IPv4Address('192.0.2.2'),
494495
IPv4Address('192.0.2.3'), IPv4Address('192.0.2.4'),
495496
IPv4Address('192.0.2.5'), IPv4Address('192.0.2.6')]
496497
>>> list(ip_network('192.0.2.0/31').hosts())
497498
[IPv4Address('192.0.2.0'), IPv4Address('192.0.2.1')]
499+
>>> list(ip_network('192.0.2.1/32').hosts())
500+
[IPv4Address('192.0.2.1')]
498501

499502
.. method:: overlaps(other)
500503

@@ -656,6 +659,8 @@ dictionaries.
656659
hosts are all the IP addresses that belong to the network, except the
657660
Subnet-Router anycast address. For networks with a mask length of 127,
658661
the Subnet-Router anycast address is also included in the result.
662+
Networks with a mask of 128 will return a list containing the
663+
single host address.
659664

660665
.. method:: overlaps(other)
661666
.. method:: address_exclude(network)

Lib/ipaddress.py

+4
Original file line numberDiff line numberDiff line change
@@ -1458,6 +1458,8 @@ def __init__(self, address, strict=True):
14581458

14591459
if self._prefixlen == (self._max_prefixlen - 1):
14601460
self.hosts = self.__iter__
1461+
elif self._prefixlen == (self._max_prefixlen):
1462+
self.hosts = lambda: [IPv4Address(addr)]
14611463

14621464
@property
14631465
@functools.lru_cache()
@@ -2110,6 +2112,8 @@ def __init__(self, address, strict=True):
21102112

21112113
if self._prefixlen == (self._max_prefixlen - 1):
21122114
self.hosts = self.__iter__
2115+
elif self._prefixlen == self._max_prefixlen:
2116+
self.hosts = lambda: [IPv6Address(addr)]
21132117

21142118
def hosts(self):
21152119
"""Generate Iterator over usable hosts in a network.

Lib/test/test_ipaddress.py

+17
Original file line numberDiff line numberDiff line change
@@ -1124,6 +1124,15 @@ def testHosts(self):
11241124
self.assertEqual(list(ipaddress.ip_network(str_args).hosts()),
11251125
list(ipaddress.ip_network(tpl_args).hosts()))
11261126

1127+
# special case where the network is a /32
1128+
addrs = [ipaddress.IPv4Address('1.2.3.4')]
1129+
str_args = '1.2.3.4/32'
1130+
tpl_args = ('1.2.3.4', 32)
1131+
self.assertEqual(addrs, list(ipaddress.ip_network(str_args).hosts()))
1132+
self.assertEqual(addrs, list(ipaddress.ip_network(tpl_args).hosts()))
1133+
self.assertEqual(list(ipaddress.ip_network(str_args).hosts()),
1134+
list(ipaddress.ip_network(tpl_args).hosts()))
1135+
11271136
addrs = [ipaddress.IPv6Address('2001:658:22a:cafe::'),
11281137
ipaddress.IPv6Address('2001:658:22a:cafe::1')]
11291138
str_args = '2001:658:22a:cafe::/127'
@@ -1133,6 +1142,14 @@ def testHosts(self):
11331142
self.assertEqual(list(ipaddress.ip_network(str_args).hosts()),
11341143
list(ipaddress.ip_network(tpl_args).hosts()))
11351144

1145+
addrs = [ipaddress.IPv6Address('2001:658:22a:cafe::1'), ]
1146+
str_args = '2001:658:22a:cafe::1/128'
1147+
tpl_args = ('2001:658:22a:cafe::1', 128)
1148+
self.assertEqual(addrs, list(ipaddress.ip_network(str_args).hosts()))
1149+
self.assertEqual(addrs, list(ipaddress.ip_network(tpl_args).hosts()))
1150+
self.assertEqual(list(ipaddress.ip_network(str_args).hosts()),
1151+
list(ipaddress.ip_network(tpl_args).hosts()))
1152+
11361153
def testFancySubnetting(self):
11371154
self.assertEqual(sorted(self.ipv4_network.subnets(prefixlen_diff=3)),
11381155
sorted(self.ipv4_network.subnets(new_prefix=27)))

Misc/ACKS

+1
Original file line numberDiff line numberDiff line change
@@ -1816,6 +1816,7 @@ Jeff Wheeler
18161816
Christopher White
18171817
David White
18181818
Mats Wichmann
1819+
Pete Wicken
18191820
Marcel Widjaja
18201821
Truida Wiedijk
18211822
Felix Wiemann
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
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.

0 commit comments

Comments
 (0)