8000 [3.7] bpo-28577: Special case added to IP v4 and v6 hosts for /32 and… · JamoBox/cpython@8deee8b · GitHub
[go: up one dir, main page]

Skip to content

Commit 8deee8b

Browse files
committed
[3.7] bpo-28577: Special case added to IP v4 and v6 hosts for /32 and /128 networks (pythonGH-18757)
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 2f01c56 commit 8deee8b

File tree

5 files changed

+29
-1
lines changed

5 files changed

+29
-1
lines changed

Doc/library/ipaddress.rst

Lines changed: 6 additions & 1 deletion
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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1532,6 +1532,8 @@ def __init__(self, address, strict=True):
15321532

15331533
if self._prefixlen == (self._max_prefixlen - 1):
15341534
self.hosts = self.__iter__
1535+
elif self._prefixlen == (self._max_prefixlen):
1536+
self.hosts = lambda: [IPv4Address(addr)]
15351537

15361538
@property
15371539
@functools.lru_cache()
@@ -2182,6 +2184,8 @@ def __init__(self, address, strict=True):
21822184

21832185
if self._prefixlen == (self._max_prefixlen - 1):
21842186
self.hosts = self.__iter__
2187+
elif self._prefixlen == self._max_prefixlen:
2188+
self.hosts = lambda: [IPv6Address(addr)]
21852189

21862190
def hosts(self):
21872191
"""Generate Iterator over usable hosts in a network.

Lib/test/test_ipaddress.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1159,6 +1159,15 @@ def testHosts(self):
11591159
self.assertEqual(list(ipaddress.ip_network(str_args).hosts()),
11601160
list(ipaddress.ip_network(tpl_args).hosts()))
11611161

1162+
# special case where the network is a /32
1163+
addrs = [ipaddress.IPv4Address('1.2.3.4')]
1164+
str_args = '1.2.3.4/32'
1165+
tpl_args = ('1.2.3.4', 32)
1166+
self.assertEqual(addrs, list(ipaddress.ip_network(str_args).hosts()))
1167+
self.assertEqual(addrs, list(ipaddress.ip_network(tpl_args).hosts()))
1168+
self.assertEqual(list(ipaddress.ip_network(str_args).hosts()),
1169+
list(ipaddress.ip_network(tpl_args).hosts()))
1170+
11621171
addrs = [ipaddress.IPv6Address('2001:658:22a:cafe::'),
11631172
ipaddress.IPv6Address('2001:658:22a:cafe::1')]
11641173
str_args = '2001:658:22a:cafe::/127'
@@ -1168,6 +1177,14 @@ def testHosts(self):
11681177
self.assertEqual(list(ipaddress.ip_network(str_args).hosts()),
11691178
list(ipaddress.ip_network(tpl_args).hosts()))
11701179

1180+
addrs = [ipaddress.IPv6Address('2001:658:22a:cafe::1'), ]
1181+
str_args = '2001:658:22a:cafe::1/128'
1182+
tpl_args = ('2001:658:22a:cafe::1', 128)
1183+
self.assertEqual(addrs, list(ipaddress.ip_network(str_args).hosts()))
1184+
self.assertEqual(addrs, list(ipaddress.ip_network(tpl_args).hosts()))
1185+
self.assertEqual(list(ipaddress.ip_network(str_args).hosts()),
1186+
list(ipaddress.ip_network(tpl_args).hosts()))
1187+
11711188
def testFancySubnetting(self):
11721189
self.assertEqual(sorted(self.ipv4_network.subnets(prefixlen_diff=3)),
11731190
sorted(self.ipv4_network.subnets(new_prefix=27)))

Misc/ACKS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1759,6 +1759,7 @@ Jeff Wheeler
17591759
Christopher White
17601760
David White
17611761
Mats Wichmann
1762+
Pete Wicken
17621763
Marcel Widjaja
17631764
Truida Wiedijk
17641765
Felix Wiemann
Lines changed: 1 addition & 0 deletions
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)
0