summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
Diffstat (limited to 'Lib')
-rw-r--r--Lib/ipaddress.py110
-rw-r--r--Lib/test/test_ipaddress.py17
2 files changed, 56 insertions, 71 deletions
diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py
index 7a3f36f..909a55d 100644
--- a/Lib/ipaddress.py
+++ b/Lib/ipaddress.py
@@ -532,6 +532,30 @@ class _IPAddressBase:
except ValueError:
cls._report_invalid_netmask(ip_str)
+ @classmethod
+ def _split_addr_prefix(cls, address):
+ """Helper function to parse address of Network/Interface.
+
+ Arg:
+ address: Argument of Network/Interface.
+
+ Returns:
+ (addr, prefix) tuple.
+ """
+ # a packed address or integer
+ if isinstance(address, (bytes, int)):
+ return address, cls._max_prefixlen
+
+ if not isinstance(address, tuple):
+ # Assume input argument to be string or any object representation
+ # which converts into a formatted IP prefix string.
+ address = _split_optional_netmask(address)
+
+ # Constructing from a tuple (addr, [mask])
+ if len(address) > 1:
+ return address
+ return address[0], cls._max_prefixlen
+
def __reduce__(self):
return self.__class__, (str(self),)
@@ -1305,32 +1329,16 @@ class IPv4Address(_BaseV4, _BaseAddress):
class IPv4Interface(IPv4Address):
def __init__(self, address):
- if isinstance(address, (bytes, int)):
- IPv4Address.__init__(self, address)
- self.network = IPv4Network(self._ip)
- self._prefixlen = self._max_prefixlen
- return
-
- if isinstance(address, tuple):
- IPv4Address.__init__(self, address[0])
- if len(address) > 1:
- self._prefixlen = int(address[1])
- else:
- self._prefixlen = self._max_prefixlen
-
- self.network = IPv4Network(address, strict=False)
- self.netmask = self.network.netmask
- self.hostmask = self.network.hostmask
- return
-
- addr = _split_optional_netmask(address)
- IPv4Address.__init__(self, addr[0])
+ addr, mask = self._split_addr_prefix(address)
- self.network = IPv4Network(address, strict=False)
+ IPv4Address.__init__(self, addr)
+ self.network = IPv4Network((addr, mask), strict=False)
+ self.netmask = self.network.netmask
self._prefixlen = self.network._prefixlen
- self.netmask = self.network.netmask
- self.hostmask = self.network.hostmask
+ @functools.cached_property
+ def hostmask(self):
+ return self.network.hostmask
def __str__(self):
return '%s/%d' % (self._string_from_ip_int(self._ip),
@@ -1435,20 +1443,7 @@ class IPv4Network(_BaseV4, _BaseNetwork):
ValueError: If strict is True and a network address is not
supplied.
"""
- # 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.
- else:
- args = _split_optional_netmask(address)
- addr = self._ip_int_from_string(args[0])
- mask = args[1] if len(args) == 2 else self._max_prefixlen
+ addr, mask = self._split_addr_prefix(address)
self.network_address = IPv4Address(addr)
self.netmask, self._prefixlen = self._make_netmask(mask)
@@ -1979,28 +1974,16 @@ class IPv6Address(_BaseV6, _BaseAddress):
class IPv6Interface(IPv6Address):
def __init__(self, address):
- if isinstance(address, (bytes, int)):
- IPv6Address.__init__(self, address)
- self.network = IPv6Network(self._ip)
- self._prefixlen = self._max_prefixlen
- return
- if isinstance(address, tuple):
- IPv6Address.__init__(self, address[0])
- if len(address) > 1:
- self._prefixlen = int(address[1])
- else:
- self._prefixlen = self._max_prefixlen
- self.network = IPv6Network(address, strict=False)
- self.netmask = self.network.netmask
- self.hostmask = self.network.hostmask
- return
+ addr, mask = self._split_addr_prefix(address)
- addr = _split_optional_netmask(address)
- IPv6Address.__init__(self, addr[0])
- self.network = IPv6Network(address, strict=False)
+ IPv6Address.__init__(self, addr)
+ self.network = IPv6Network((addr, mask), strict=False)
self.netmask = self.network.netmask
self._prefixlen = self.network._prefixlen
- self.hostmask = self.network.hostmask
+
+ @functools.cached_property
+ def hostmask(self):
+ return self.network.hostmask
def __str__(self):
return '%s/%d' % (self._string_from_ip_int(self._ip),
@@ -2110,20 +2093,7 @@ class IPv6Network(_BaseV6, _BaseNetwork):
ValueError: If strict was True and a network address was not
supplied.
"""
- # 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.
- else:
- args = _split_optional_netmask(address)
- addr = self._ip_int_from_string(args[0])
- mask = args[1] if len(args) == 2 else self._max_prefixlen
+ addr, mask = self._split_addr_prefix(address)
self.network_address = IPv6Address(addr)
self.netmask, self._prefixlen = self._make_netmask(mask)
diff --git a/Lib/test/test_ipaddress.py b/Lib/test/test_ipaddress.py
index 15317c9..20316f1 100644
--- a/Lib/test/test_ipaddress.py
+++ b/Lib/test/test_ipaddress.py
@@ -399,7 +399,13 @@ class NetmaskTestMixin_v4(CommonTestMixin_v4):
"""Input validation on interfaces and networks is very similar"""
def test_no_mask(self):
- self.assertEqual(str(self.factory('1.2.3.4')), '1.2.3.4/32')
+ for address in ('1.2.3.4', 0x01020304, b'\x01\x02\x03\x04'):
+ net = self.factory(address)
+ self.assertEqual(str(net), '1.2.3.4/32')
+ self.assertEqual(str(net.netmask), '255.255.255.255')
+ self.assertEqual(str(net.hostmask), '0.0.0.0')
+ # IPv4Network has prefixlen, but IPv4Interface doesn't.
+ # Should we add it to IPv4Interface too? (bpo-36392)
def test_split_netmask(self):
addr = "1.2.3.4/32/24"
@@ -527,6 +533,15 @@ class NetworkTestCase_v4(BaseTestCase, NetmaskTestMixin_v4):
class NetmaskTestMixin_v6(CommonTestMixin_v6):
"""Input validation on interfaces and networks is very similar"""
+ def test_no_mask(self):
+ for address in ('::1', 1, b'\x00'*15 + b'\x01'):
+ net = self.factory(address)
+ self.assertEqual(str(net), '::1/128')
+ self.assertEqual(str(net.netmask), 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff')
+ self.assertEqual(str(net.hostmask), '::')
+ # IPv6Network has prefixlen, but IPv6Interface doesn't.
+ # Should we add it to IPv4Interface too? (bpo-36392)
+
def test_split_netmask(self):
addr = "cafe:cafe::/128/190"
with self.assertAddressError("Only one '/' permitted in %r" % addr):