From 52dc9c3066bcdc67a7a45d41cf158ecb1434d5f3 Mon Sep 17 00:00:00 2001 From: Thomas Cellerier Date: Tue, 3 May 2022 14:12:58 +0200 Subject: [PATCH] bpo-46415: Use f-string for ValueError in ipaddress.ip_{address,network,interface} helper functions (#30642) `IPv*Network` and `IPv*Interface` constructors accept a 2-tuple of (address description, netmask) as the address parameter. When the tuple-based address is used errors are not propagated correctly through the `ipaddress.ip_*` helper because of the %-formatting now expecting several arguments: In [7]: ipaddress.ip_network(("192.168.100.0", "fooo")) ... TypeError: not all arguments converted during string formatting Compared to: In [8]: ipaddress.IPv4Network(("192.168.100.0", "foo")) ... NetmaskValueError: 'foo' is not a valid netmask Use an f-string to make sure the error is always properly formatted. Co-authored-by: Jelle Zijlstra --- Lib/ipaddress.py | 15 ++++++--------- Lib/test/test_ipaddress.py | 16 ++++++++++++++++ .../2022-01-17-16-53-30.bpo-46415.6wSYg-.rst | 2 ++ 3 files changed, 24 insertions(+), 9 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2022-01-17-16-53-30.bpo-46415.6wSYg-.rst diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py index e601f6f476e..3f15601e700 100644 --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -51,8 +51,7 @@ def ip_address(address): except (AddressValueError, NetmaskValueError): pass - raise ValueError('%r does not appear to be an IPv4 or IPv6 address' % - address) + raise ValueError(f'{address!r} does not appear to be an IPv4 or IPv6 address') def ip_network(address, strict=True): @@ -81,8 +80,7 @@ def ip_network(address, strict=True): except (AddressValueError, NetmaskValueError): pass - raise ValueError('%r does not appear to be an IPv4 or IPv6 network' % - address) + raise ValueError(f'{address!r} does not appear to be an IPv4 or IPv6 network') def ip_interface(address): @@ -116,8 +114,7 @@ def ip_interface(address): except (AddressValueError, NetmaskValueError): pass - raise ValueError('%r does not appear to be an IPv4 or IPv6 interface' % - address) + raise ValueError(f'{address!r} does not appear to be an IPv4 or IPv6 interface') def v4_int_to_packed(address): @@ -160,7 +157,7 @@ def _split_optional_netmask(address): """Helper to split the netmask and raise AddressValueError if needed""" addr = str(address).split('/') if len(addr) > 2: - raise AddressValueError("Only one '/' permitted in %r" % address) + raise AddressValueError(f"Only one '/' permitted in {address!r}") return addr @@ -1304,7 +1301,7 @@ class IPv4Address(_BaseV4, _BaseAddress): # which converts into a formatted IP string. addr_str = str(address) if '/' in addr_str: - raise AddressValueError("Unexpected '/' in %r" % address) + raise AddressValueError(f"Unexpected '/' in {address!r}") self._ip = self._ip_int_from_string(addr_str) @property @@ -1913,7 +1910,7 @@ class IPv6Address(_BaseV6, _BaseAddress): # which converts into a formatted IP string. addr_str = str(address) if '/' in addr_str: - raise AddressValueError("Unexpected '/' in %r" % address) + raise AddressValueError(f"Unexpected '/' in {address!r}") addr_str, self._scope_id = self._split_scope_id(addr_str) self._ip = self._ip_int_from_string(addr_str) diff --git a/Lib/test/test_ipaddress.py b/Lib/test/test_ipaddress.py index b0605f0be04..e5162e86cb5 100644 --- a/Lib/test/test_ipaddress.py +++ b/Lib/test/test_ipaddress.py @@ -1132,6 +1132,14 @@ class IpaddrUnitTest(unittest.TestCase): self.assertEqual(ipaddress.IPv4Interface((3221225985, 24)), ipaddress.IPv4Interface('192.0.2.1/24')) + # Invalid netmask + with self.assertRaises(ValueError): + ipaddress.IPv4Network(('192.0.2.1', '255.255.255.255.0')) + + # Invalid netmask using factory + with self.assertRaises(ValueError): + ipaddress.ip_network(('192.0.2.1', '255.255.255.255.0')) + # issue #16531: constructing IPv6Network from an (address, mask) tuple def testIPv6Tuple(self): # /128 @@ -1191,6 +1199,14 @@ class IpaddrUnitTest(unittest.TestCase): ipaddress.IPv6Network((ip_scoped, 96)) # strict=False and host bits set + # Invalid netmask + with self.assertRaises(ValueError): + ipaddress.IPv6Network(('2001:db8::1', '255.255.255.0')) + + # Invalid netmask using factory + with self.assertRaises(ValueError): + ipaddress.ip_network(('2001:db8::1', '255.255.255.0')) + # issue57 def testAddressIntMath(self): self.assertEqual(ipaddress.IPv4Address('1.1.1.1') + 255, diff --git a/Misc/NEWS.d/next/Library/2022-01-17-16-53-30.bpo-46415.6wSYg-.rst b/Misc/NEWS.d/next/Library/2022-01-17-16-53-30.bpo-46415.6wSYg-.rst new file mode 100644 index 00000000000..016d6656041 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-01-17-16-53-30.bpo-46415.6wSYg-.rst @@ -0,0 +1,2 @@ +Fix ipaddress.ip_{address,interface,network} raising TypeError instead of +ValueError if given invalid tuple as address parameter.