summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorXiang Zhang <angwerzx@126.com>2018-03-21 00:25:13 (GMT)
committerGitHub <noreply@github.com>2018-03-21 00:25:13 (GMT)
commit10b134a07c898c2fbc5fd3582503680a54ed80a2 (patch)
tree32ce163bf6c42d52dcbf62a6479de258c014ea04
parent5609b78392d59c7362ef8aa5c4a4529325f01f27 (diff)
downloadcpython-10b134a07c898c2fbc5fd3582503680a54ed80a2.zip
cpython-10b134a07c898c2fbc5fd3582503680a54ed80a2.tar.gz
cpython-10b134a07c898c2fbc5fd3582503680a54ed80a2.tar.bz2
bpo-27683: Fix a regression for host() of ipaddress network objects (GH-6016)
The result of host() was not empty when the network is constructed by a tuple containing an integer mask and only 1 bit left for addresses.
-rw-r--r--Doc/library/ipaddress.rst12
-rw-r--r--Lib/ipaddress.py109
-rw-r--r--Lib/test/test_ipaddress.py26
-rw-r--r--Misc/NEWS.d/next/Library/2018-03-07-22-28-17.bpo-27683.572Rv4.rst3
4 files changed, 75 insertions, 75 deletions
diff --git a/Doc/library/ipaddress.rst b/Doc/library/ipaddress.rst
index 935add17..b7b502a 100644
--- a/Doc/library/ipaddress.rst
+++ b/Doc/library/ipaddress.rst
@@ -485,12 +485,16 @@ dictionaries.
Returns an iterator over the usable hosts in the network. The usable
hosts are all the IP addresses that belong to the network, except the
- network address itself and the network broadcast address.
+ 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.
>>> list(ip_network('192.0.2.0/29').hosts()) #doctest: +NORMALIZE_WHITESPACE
[IPv4Address('192.0.2.1'), IPv4Address('192.0.2.2'),
IPv4Address('192.0.2.3'), IPv4Address('192.0.2.4'),
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')]
.. method:: overlaps(other)
@@ -647,6 +651,12 @@ dictionaries.
.. attribute:: num_addresses
.. attribute:: prefixlen
.. method:: hosts()
+
+ Returns an iterator over the usable hosts in the network. The usable
+ 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.
+
.. method:: overlaps(other)
.. method:: address_exclude(network)
.. method:: subnets(prefixlen_diff=1, new_prefix=None)
diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py
index 77df051..15507d6 100644
--- a/Lib/ipaddress.py
+++ b/Lib/ipaddress.py
@@ -1514,45 +1514,28 @@ class IPv4Network(_BaseV4, _BaseNetwork):
# Constructing from a packed address or integer
if isinstance(address, (int, bytes)):
- self.network_address = IPv4Address(address)
- self.netmask, self._prefixlen = self._make_netmask(self._max_prefixlen)
- #fixme: address/network test here.
- return
-
- if isinstance(address, tuple):
- if len(address) > 1:
- arg = address[1]
- else:
- # We weren't given an address[1]
- arg = self._max_prefixlen
- self.network_address = IPv4Address(address[0])
- self.netmask, self._prefixlen = self._make_netmask(arg)
- packed = int(self.network_address)
- if packed & int(self.netmask) != packed:
- if strict:
- raise ValueError('%s has host bits set' % self)
- else:
- self.network_address = IPv4Address(packed &
- int(self.netmask))
- return
-
+ addr = address
+ mask = self._max_prefixlen
+ # Constructing from a tuple (addr, [mask])
+ elif isinstance(address, tuple):
+ addr = address[0]
+ mask = address[1] if len(address) > 1 else self._max_prefixlen
# Assume input argument to be string or any object representation
# which converts into a formatted IP prefix string.
- addr = _split_optional_netmask(address)
- self.network_address = IPv4Address(self._ip_int_from_string(addr[0]))
-
- if len(addr) == 2:
- arg = addr[1]
else:
- arg = self._max_prefixlen
- self.netmask, self._prefixlen = self._make_netmask(arg)
-
- if strict:
- if (IPv4Address(int(self.network_address) & int(self.netmask)) !=
- self.network_address):
+ args = _split_optional_netmask(address)
+ addr = self._ip_int_from_string(args[0])
+ mask = args[1] if len(args) == 2 else self._max_prefixlen
+
+ self.network_address = IPv4Address(addr)
+ self.netmask, self._prefixlen = self._make_netmask(mask)
+ packed = int(self.network_address)
+ if packed & int(self.netmask) != packed:
+ if strict:
raise ValueError('%s has host bits set' % self)
- self.network_address = IPv4Address(int(self.network_address) &
- int(self.netmask))
+ else:
+ self.network_address = IPv4Address(packed &
+ int(self.netmask))
if self._prefixlen == (self._max_prefixlen - 1):
self.hosts = self.__iter__
@@ -2207,46 +2190,30 @@ class IPv6Network(_BaseV6, _BaseNetwork):
"""
_BaseNetwork.__init__(self, address)
- # Efficient constructor from integer or packed address
- if isinstance(address, (bytes, int)):
- self.network_address = IPv6Address(address)
- self.netmask, self._prefixlen = self._make_netmask(self._max_prefixlen)
- return
-
- if isinstance(address, tuple):
- if len(address) > 1:
- arg = address[1]
- else:
- arg = self._max_prefixlen
- self.netmask, self._prefixlen = self._make_netmask(arg)
- self.network_address = IPv6Address(address[0])
- packed = int(self.network_address)
- if packed & int(self.netmask) != packed:
- if strict:
- raise ValueError('%s has host bits set' % self)
- else:
- self.network_address = IPv6Address(packed &
- int(self.netmask))
- return
-
+ # Constructing from a packed address or integer
+ if isinstance(address, (int, bytes)):
+ addr = address
+ mask = self._max_prefixlen
+ # Constructing from a tuple (addr, [mask])
+ elif isinstance(address, tuple):
+ addr = address[0]
+ mask = address[1] if len(address) > 1 else self._max_prefixlen
# Assume input argument to be string or any object representation
# which converts into a formatted IP prefix string.
- addr = _split_optional_netmask(address)
-
- self.network_address = IPv6Address(self._ip_int_from_string(addr[0]))
-
- if len(addr) == 2:
- arg = addr[1]
else:
- arg = self._max_prefixlen
- self.netmask, self._prefixlen = self._make_netmask(arg)
-
- if strict:
- if (IPv6Address(int(self.network_address) & int(self.netmask)) !=
- self.network_address):
+ args = _split_optional_netmask(address)
+ addr = self._ip_int_from_string(args[0])
+ mask = args[1] if len(args) == 2 else self._max_prefixlen
+
+ self.network_address = IPv6Address(addr)
+ self.netmask, self._prefixlen = self._make_netmask(mask)
+ packed = int(self.network_address)
+ if packed & int(self.netmask) != packed:
+ if strict:
raise ValueError('%s has host bits set' % self)
- self.network_address = IPv6Address(int(self.network_address) &
- int(self.netmask))
+ else:
+ self.network_address = IPv6Address(packed &
+ int(self.netmask))
if self._prefixlen == (self._max_prefixlen - 1):
self.hosts = self.__iter__
diff --git a/Lib/test/test_ipaddress.py b/Lib/test/test_ipaddress.py
index a5aeb79..0e0753f 100644
--- a/Lib/test/test_ipaddress.py
+++ b/Lib/test/test_ipaddress.py
@@ -1127,10 +1127,30 @@ class IpaddrUnitTest(unittest.TestCase):
self.assertEqual(ipaddress.IPv4Address('1.2.3.1'), hosts[0])
self.assertEqual(ipaddress.IPv4Address('1.2.3.254'), hosts[-1])
+ ipv6_network = ipaddress.IPv6Network('2001:658:22a:cafe::/120')
+ hosts = list(ipv6_network.hosts())
+ self.assertEqual(255, len(hosts))
+ self.assertEqual(ipaddress.IPv6Address('2001:658:22a:cafe::1'), hosts[0])
+ self.assertEqual(ipaddress.IPv6Address('2001:658:22a:cafe::ff'), hosts[-1])
+
# special case where only 1 bit is left for address
- self.assertEqual([ipaddress.IPv4Address('2.0.0.0'),
- ipaddress.IPv4Address('2.0.0.1')],
- list(ipaddress.ip_network('2.0.0.0/31').hosts()))
+ addrs = [ipaddress.IPv4Address('2.0.0.0'),
+ ipaddress.IPv4Address('2.0.0.1')]
+ str_args = '2.0.0.0/31'
+ tpl_args = ('2.0.0.0', 31)
+ 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'
+ tpl_args = ('2001:658:22a:cafe::', 127)
+ 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)),
diff --git a/Misc/NEWS.d/next/Library/2018-03-07-22-28-17.bpo-27683.572Rv4.rst b/Misc/NEWS.d/next/Library/2018-03-07-22-28-17.bpo-27683.572Rv4.rst
new file mode 100644
index 0000000..4e6dfa8
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2018-03-07-22-28-17.bpo-27683.572Rv4.rst
@@ -0,0 +1,3 @@
+Fix a regression in :mod:`ipaddress` that result of :meth:`hosts`
+is empty when the network is constructed by a tuple containing an
+integer mask and only 1 bit left for addresses.