From ab1af9d511ea7b84a75bd081835f34affb1fbfdf Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Fri, 13 Jun 2025 07:43:35 +0300 Subject: [PATCH 1/2] gh-119949: refactor test_exc() helper in test_format.py Use assertRaisesRegex() context and fix https://github.com/python/cpython/pull/119781#pullrequestreview-2088240959 --- Lib/test/test_format.py | 140 ++++++++++++++++++---------------------- 1 file changed, 64 insertions(+), 76 deletions(-) diff --git a/Lib/test/test_format.py b/Lib/test/test_format.py index c7cc32e09490b28..8fdbbc0d0da90fd 100644 --- a/Lib/test/test_format.py +++ b/Lib/test/test_format.py @@ -72,30 +72,18 @@ def testcommon(formatstr, args, output=None, limit=None, overflowok=False): testformat(b_format, b_args, b_output, limit, overflowok) testformat(ba_format, b_args, ba_output, limit, overflowok) -def test_exc(formatstr, args, exception, excmsg): - try: - testformat(formatstr, args) - except exception as exc: - if str(exc) == excmsg: - if verbose: - print("yes") - else: - if verbose: print('no') - print('Unexpected ', exception, ':', repr(str(exc))) - except: - if verbose: print('no') - print('Unexpected exception') - raise - else: - raise TestFailed('did not get expected exception: %s' % excmsg) - -def test_exc_common(formatstr, args, exception, excmsg): - # test str and bytes - test_exc(formatstr, args, exception, excmsg) - test_exc(formatstr.encode('ascii'), args, exception, excmsg) class FormatTest(unittest.TestCase): + def check_exc(self, formatstr, args, exception, excmsg): + with self.assertRaisesRegex(exception, excmsg): + testformat(formatstr, args) + + def check_exc_common(self, formatstr, args, exception, excmsg): + # test str and bytes + self.check_exc(formatstr, args, exception, excmsg) + self.check_exc(formatstr.encode('ascii'), args, exception, excmsg) + def test_common_format(self): # test the format identifiers that work the same across # str, bytes, and bytearrays (integer, float, oct, hex) @@ -272,21 +260,21 @@ def test_common_format(self): if verbose: print('Testing exceptions') - test_exc_common('%', (), ValueError, "incomplete format") - test_exc_common('% %s', 1, ValueError, - "unsupported format character '%' (0x25) at index 2") - test_exc_common('%d', '1', TypeError, - "%d format: a real number is required, not str") - test_exc_common('%d', b'1', TypeError, - "%d format: a real number is required, not bytes") - test_exc_common('%x', '1', TypeError, - "%x format: an integer is required, not str") - test_exc_common('%x', 3.14, TypeError, - "%x format: an integer is required, not float") - test_exc_common('%i', '1', TypeError, - "%i format: a real number is required, not str") - test_exc_common('%i', b'1', TypeError, - "%i format: a real number is required, not bytes") + self.check_exc_common('%', (), ValueError, "incomplete format") + self.check_exc_common('% %s', 1, ValueError, + r"unsupported format character '%' \(0x25\) at index 2") + self.check_exc_common('%d', '1', TypeError, + "%d format: a real number is required, not str") + self.check_exc_common('%d', b'1', TypeError, + "%d format: a real number is required, not bytes") + self.check_exc_common('%x', '1', TypeError, + "%x format: an integer is required, not str") + self.check_exc_common('%x', 3.14, TypeError, + "%x format: an integer is required, not float") + self.check_exc_common('%i', '1', TypeError, + "%i format: a real number is required, not str") + self.check_exc_common('%i', b'1', TypeError, + "%i format: a real number is required, not bytes") def test_str_format(self): testformat("%r", "\u0378", "'\\u0378'") # non printable @@ -297,20 +285,20 @@ def test_str_format(self): # Test exception for unknown format characters, etc. if verbose: print('Testing exceptions') - test_exc('abc %b', 1, ValueError, - "unsupported format character 'b' (0x62) at index 5") - #test_exc(unicode('abc %\u3000','raw-unicode-escape'), 1, ValueError, - # "unsupported format character '?' (0x3000) at index 5") - test_exc('%g', '1', TypeError, "must be real number, not str") - test_exc('no format', '1', TypeError, - "not all arguments converted during string formatting") - test_exc('%c', -1, OverflowError, "%c arg not in range(0x110000)") - test_exc('%c', sys.maxunicode+1, OverflowError, - "%c arg not in range(0x110000)") - #test_exc('%c', 2**128, OverflowError, "%c arg not in range(0x110000)") - test_exc('%c', 3.14, TypeError, "%c requires an int or a unicode character, not float") - test_exc('%c', 'ab', TypeError, "%c requires an int or a unicode character, not a string of length 2") - test_exc('%c', b'x', TypeError, "%c requires an int or a unicode character, not bytes") + self.check_exc('abc %b', 1, ValueError, + r"unsupported format character 'b' \(0x62\) at index 5") + #self.check_exc(unicode('abc %\u3000','raw-unicode-escape'), 1, ValueError, + # r"unsupported format character '?' \(0x3000\) at index 5") + self.check_exc('%g', '1', TypeError, "must be real number, not str") + self.check_exc('no format', '1', TypeError, + "not all arguments converted during string formatting") + self.check_exc('%c', -1, OverflowError, r"%c arg not in range\(0x110000\)") + self.check_exc('%c', sys.maxunicode+1, OverflowError, + r"%c arg not in range\(0x110000\)") + #self.check_exc('%c', 2**128, OverflowError, r"%c arg not in range\(0x110000\)") + self.check_exc('%c', 3.14, TypeError, "%c requires an int or a unicode character, not float") + self.check_exc('%c', 'ab', TypeError, "%c requires an int or a unicode character, not a string of length 2") + self.check_exc('%c', b'x', TypeError, "%c requires an int or a unicode character, not bytes") if maxsize == 2**31-1: # crashes 2.2.1 and earlier: @@ -359,32 +347,32 @@ def __bytes__(self): # Test exception for unknown format characters, etc. if verbose: print('Testing exceptions') - test_exc(b'%g', '1', TypeError, "float argument required, not str") - test_exc(b'%g', b'1', TypeError, "float argument required, not bytes") - test_exc(b'no format', 7, TypeError, - "not all arguments converted during bytes formatting") - test_exc(b'no format', b'1', TypeError, - "not all arguments converted during bytes formatting") - test_exc(b'no format', bytearray(b'1'), TypeError, - "not all arguments converted during bytes formatting") - test_exc(b"%c", -1, OverflowError, - "%c arg not in range(256)") - test_exc(b"%c", 256, OverflowError, - "%c arg not in range(256)") - test_exc(b"%c", 2**128, OverflowError, - "%c arg not in range(256)") - test_exc(b"%c", b"Za", TypeError, - "%c requires an integer in range(256) or a single byte, not a bytes object of length 2") - test_exc(b"%c", "Y", TypeError, - "%c requires an integer in range(256) or a single byte, not str") - test_exc(b"%c", 3.14, TypeError, - "%c requires an integer in range(256) or a single byte, not float") - test_exc(b"%b", "Xc", TypeError, - "%b requires a bytes-like object, " - "or an object that implements __bytes__, not 'str'") - test_exc(b"%s", "Wd", TypeError, - "%b requires a bytes-like object, " - "or an object that implements __bytes__, not 'str'") + self.check_exc(b'%g', '1', TypeError, "float argument required, not str") + self.check_exc(b'%g', b'1', TypeError, "float argument required, not bytes") + self.check_exc(b'no format', 7, TypeError, + "not all arguments converted during bytes formatting") + self.check_exc(b'no format', b'1', TypeError, + "not all arguments converted during bytes formatting") + self.check_exc(b'no format', bytearray(b'1'), TypeError, + "not all arguments converted during bytes formatting") + self.check_exc(b"%c", -1, OverflowError, + r"%c arg not in range\(256\)") + self.check_exc(b"%c", 256, OverflowError, + r"%c arg not in range\(256\)") + self.check_exc(b"%c", 2**128, OverflowError, + r"%c arg not in range\(256\)") + self.check_exc(b"%c", b"Za", TypeError, + r"%c requires an integer in range\(256\) or a single byte, not a bytes object of length 2") + self.check_exc(b"%c", "Y", TypeError, + r"%c requires an integer in range\(256\) or a single byte, not str") + self.check_exc(b"%c", 3.14, TypeError, + r"%c requires an integer in range\(256\) or a single byte, not float") + self.check_exc(b"%b", "Xc", TypeError, + "%b requires a bytes-like object, " + "or an object that implements __bytes__, not 'str'") + self.check_exc(b"%s", "Wd", TypeError, + "%b requires a bytes-like object, " + "or an object that implements __bytes__, not 'str'") if maxsize == 2**31-1: # crashes 2.2.1 and earlier: From 535983d2f1c75a387cee255180668df183053def Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Sun, 24 May 2026 12:56:15 +0300 Subject: [PATCH 2/2] address review: minimize diff --- Lib/test/test_format.py | 111 ++++++++++++++++++++-------------------- 1 file changed, 55 insertions(+), 56 deletions(-) diff --git a/Lib/test/test_format.py b/Lib/test/test_format.py index 06fb249a657108e..5d322cb444cfb68 100644 --- a/Lib/test/test_format.py +++ b/Lib/test/test_format.py @@ -72,7 +72,7 @@ def testcommon(formatstr, args, output=None, limit=None, overflowok=False): class FormatTest(unittest.TestCase): def check_exc(self, formatstr, args, exception, excmsg): - with self.assertRaisesRegex(exception, excmsg): + with self.assertRaisesRegex(exception, re.escape(excmsg)): testformat(formatstr, args) def check_exc_common(self, formatstr, args, exception, excmsg): @@ -271,49 +271,49 @@ def test_common_format(self): test_exc_common("abc %1 d", 1, ValueError, "stray % at position 4 or unexpected format character ' ' at position 6") test_exc_common('abc % (x)r', {}, ValueError, - "stray % at position 4 or unexpected format character '\(' at position 6") + "stray % at position 4 or unexpected format character '(' at position 6") test_exc_common('abc %((x)r', {}, ValueError, "stray % or incomplete format key at position 4") test_exc_common('%r %r', 1, TypeError, - "not enough arguments for format string \(got 1\)") + "not enough arguments for format string (got 1)") test_exc_common('%r %r', (1,), TypeError, - "not enough arguments for format string \(got 1\)") + "not enough arguments for format string (got 1)") test_exc_common('%r', (), TypeError, - "not enough arguments for format string \(got 0\)") + "not enough arguments for format string (got 0)") test_exc_common('abc %' + '9'*50 + 'r', 1, ValueError, "width too big at position 4") test_exc_common('abc %.' + '9'*50 + 'r', 1, ValueError, "precision too big at position 4") test_exc_common('%r %*r', 1, TypeError, - "not enough arguments for format string \(got 1\)") + "not enough arguments for format string (got 1)") test_exc_common('%r %*r', (1,), TypeError, - "not enough arguments for format string \(got 1\)") + "not enough arguments for format string (got 1)") test_exc_common('%*r', (1,), TypeError, - "not enough arguments for format string \(got 1\)") + "not enough arguments for format string (got 1)") test_exc_common('%*r', (), TypeError, - "not enough arguments for format string \(got 0\)") + "not enough arguments for format string (got 0)") test_exc_common('%r %.*r', 1, TypeError, - "not enough arguments for format string \(got 1\)") + "not enough arguments for format string (got 1)") test_exc_common('%r %.*r', (1,), TypeError, - "not enough arguments for format string \(got 1\)") + "not enough arguments for format string (got 1)") test_exc_common('%.*r', (1,), TypeError, - "not enough arguments for format string \(got 1\)") + "not enough arguments for format string (got 1)") test_exc_common('%.*r', (), TypeError, - "not enough arguments for format string \(got 0\)") + "not enough arguments for format string (got 0)") test_exc_common('%(x)r', 1, TypeError, "format requires a mapping, not int") test_exc_common('%*r', 1, TypeError, - "not enough arguments for format string \(got 1\)") + "not enough arguments for format string (got 1)") test_exc_common('%*r', 3.14, TypeError, - "not enough arguments for format string \(got 1\)") + "not enough arguments for format string (got 1)") test_exc_common('%*r', (3.14, 1), TypeError, - "format argument 1: \* requires int, not float") + "format argument 1: * requires int, not float") test_exc_common('%.*r', 1, TypeError, - "not enough arguments for format string \(got 1\)") + "not enough arguments for format string (got 1)") test_exc_common('%.*r', 3.14, TypeError, - "not enough arguments for format string \(got 1\)") + "not enough arguments for format string (got 1)") test_exc_common('%.*r', (3.14, 1), TypeError, - "format argument 1: \* requires int, not float") + "format argument 1: * requires int, not float") test_exc_common('%*r', (2**1000, 1), OverflowError, "format argument 1: too big for width") test_exc_common('%*r', (-2**1000, 1), OverflowError, @@ -357,27 +357,27 @@ def test_str_format(self): test_exc('abc %b', 1, ValueError, "unsupported format %b at position 4") test_exc("abc %\nd", 1, ValueError, - "stray % at position 4 or unexpected format character U\+000A at position 5") + "stray % at position 4 or unexpected format character U+000A at position 5") test_exc("abc %\x1fd", 1, ValueError, - "stray % at position 4 or unexpected format character U\+001F at position 5") + "stray % at position 4 or unexpected format character U+001F at position 5") test_exc("abc %\x7fd", 1, ValueError, - "stray % at position 4 or unexpected format character U\+007F at position 5") + "stray % at position 4 or unexpected format character U+007F at position 5") test_exc("abc %\x80d", 1, ValueError, - "stray % at position 4 or unexpected format character U\+0080 at position 5") + "stray % at position 4 or unexpected format character U+0080 at position 5") test_exc('abc %äd', 1, ValueError, - "stray % at position 4 or unexpected format character 'ä' \(U\+00E4\) at position 5") + "stray % at position 4 or unexpected format character 'ä' (U+00E4) at position 5") test_exc('abc %€d', 1, ValueError, - "stray % at position 4 or unexpected format character '€' \(U\+20AC\) at position 5") + "stray % at position 4 or unexpected format character '€' (U+20AC) at position 5") test_exc('no format', '1', TypeError, - "not all arguments converted during string formatting \(required 0, got 1\)") + "not all arguments converted during string formatting (required 0, got 1)") test_exc('%r', (1, 2), TypeError, - "not all arguments converted during string formatting \(required 1, got 2\)") + "not all arguments converted during string formatting (required 1, got 2)") test_exc('%(x)r %r', {'x': 1}, ValueError, "format requires a parenthesised mapping key at position 6") test_exc('%(x)*r', {'x': 1}, ValueError, - "\* cannot be used with a parenthesised mapping key at position 0") + "* cannot be used with a parenthesised mapping key at position 0") test_exc('%(x).*r', {'x': 1}, ValueError, - "\* cannot be used with a parenthesised mapping key at position 0") + "* cannot be used with a parenthesised mapping key at position 0") test_exc('%(x)d', {'x': '1'}, TypeError, "format argument 'x': %d requires a real number, not str") test_exc('%(x)x', {'x': '1'}, TypeError, @@ -385,15 +385,15 @@ def test_str_format(self): test_exc('%(x)g', {'x': '1'}, TypeError, "format argument 'x': %g requires a real number, not str") test_exc('%c', -1, OverflowError, - "format argument: %c argument not in range\(0x110000\)") + "format argument: %c argument not in range(0x110000)") test_exc('%c', (-1,), OverflowError, - "format argument 1: %c argument not in range\(0x110000\)") + "format argument 1: %c argument not in range(0x110000)") test_exc('%(x)c', {'x': -1}, OverflowError, - "format argument 'x': %c argument not in range\(0x110000\)") + "format argument 'x': %c argument not in range(0x110000)") test_exc('%c', sys.maxunicode+1, OverflowError, - "format argument: %c argument not in range\(0x110000\)") + "format argument: %c argument not in range(0x110000)") test_exc('%c', 2**128, OverflowError, - "format argument: %c argument not in range\(0x110000\)") + "format argument: %c argument not in range(0x110000)") test_exc('%c', 3.14, TypeError, "format argument: %c requires an integer or a unicode character, not float") test_exc('%c', (3.14,), TypeError, @@ -457,7 +457,6 @@ def __bytes__(self): # Test exception for unknown format characters, etc. if verbose: print('Testing exceptions') - test_exc = self.check_exc test_exc(b"abc %\nd", 1, ValueError, "stray % at position 4 or unexpected format character with code 0x0a at position 5") @@ -470,19 +469,19 @@ def __bytes__(self): test_exc(b"abc %\x80d", 1, ValueError, "stray % at position 4 or unexpected format character with code 0x80 at position 5") test_exc(b'no format', 7, TypeError, - "not all arguments converted during bytes formatting \(required 0, got 1\)") + "not all arguments converted during bytes formatting (required 0, got 1)") test_exc(b'no format', b'1', TypeError, - "not all arguments converted during bytes formatting \(required 0, got 1\)") + "not all arguments converted during bytes formatting (required 0, got 1)") test_exc(b'no format', bytearray(b'1'), TypeError, - "not all arguments converted during bytes formatting \(required 0, got 1\)") + "not all arguments converted during bytes formatting (required 0, got 1)") test_exc(b'%r', (1, 2), TypeError, - "not all arguments converted during bytes formatting \(required 1, got 2\)") + "not all arguments converted during bytes formatting (required 1, got 2)") test_exc(b'%(x)r %r', {b'x': 1}, ValueError, "format requires a parenthesised mapping key at position 6") test_exc(b'%(x)*r', {b'x': 1}, ValueError, - "\* cannot be used with a parenthesised mapping key at position 0") + "* cannot be used with a parenthesised mapping key at position 0") test_exc(b'%(x).*r', {b'x': 1}, ValueError, - "\* cannot be used with a parenthesised mapping key at position 0") + "* cannot be used with a parenthesised mapping key at position 0") test_exc(b'%(x)d', {b'x': '1'}, TypeError, "format argument b'x': %d requires a real number, not str") test_exc(b'%(x)x', {b'x': '1'}, TypeError, @@ -490,35 +489,35 @@ def __bytes__(self): test_exc(b'%(x)g', {b'x': '1'}, TypeError, "format argument b'x': %g requires a real number, not str") test_exc(b"%c", -1, OverflowError, - "format argument: %c argument not in range\(256\)") + "format argument: %c argument not in range(256)") test_exc(b"%c", (-1,), OverflowError, - "format argument 1: %c argument not in range\(256\)") + "format argument 1: %c argument not in range(256)") test_exc(b"%(x)c", {b'x': -1}, OverflowError, - "format argument b'x': %c argument not in range\(256\)") + "format argument b'x': %c argument not in range(256)") test_exc(b"%c", 256, OverflowError, - "format argument: %c argument not in range\(256\)") + "format argument: %c argument not in range(256)") test_exc(b"%c", 2**128, OverflowError, - "format argument: %c argument not in range\(256\)") + "format argument: %c argument not in range(256)") test_exc(b"%c", b"Za", TypeError, - "format argument: %c requires an integer in range\(256\) or a single byte, not a bytes object of length 2") + "format argument: %c requires an integer in range(256) or a single byte, not a bytes object of length 2") test_exc(b"%c", (b"Za",), TypeError, - "format argument 1: %c requires an integer in range\(256\) or a single byte, not a bytes object of length 2") + "format argument 1: %c requires an integer in range(256) or a single byte, not a bytes object of length 2") test_exc(b"%(x)c", {b'x': b"Za"}, TypeError, - "format argument b'x': %c requires an integer in range\(256\) or a single byte, not a bytes object of length 2") + "format argument b'x': %c requires an integer in range(256) or a single byte, not a bytes object of length 2") test_exc(b"%c", bytearray(b"Za"), TypeError, - "format argument: %c requires an integer in range\(256\) or a single byte, not a bytearray object of length 2") + "format argument: %c requires an integer in range(256) or a single byte, not a bytearray object of length 2") test_exc(b"%c", (bytearray(b"Za"),), TypeError, - "format argument 1: %c requires an integer in range\(256\) or a single byte, not a bytearray object of length 2") + "format argument 1: %c requires an integer in range(256) or a single byte, not a bytearray object of length 2") test_exc(b"%(x)c", {b'x': bytearray(b"Za")}, TypeError, - "format argument b'x': %c requires an integer in range\(256\) or a single byte, not a bytearray object of length 2") + "format argument b'x': %c requires an integer in range(256) or a single byte, not a bytearray object of length 2") test_exc(b"%c", "Y", TypeError, - "format argument: %c requires an integer in range\(256\) or a single byte, not str") + "format argument: %c requires an integer in range(256) or a single byte, not str") test_exc(b"%c", 3.14, TypeError, - "format argument: %c requires an integer in range\(256\) or a single byte, not float") + "format argument: %c requires an integer in range(256) or a single byte, not float") test_exc(b"%c", (3.14,), TypeError, - "format argument 1: %c requires an integer in range\(256\) or a single byte, not float") + "format argument 1: %c requires an integer in range(256) or a single byte, not float") test_exc(b"%(x)c", {b'x': 3.14}, TypeError, - "format argument b'x': %c requires an integer in range\(256\) or a single byte, not float") + "format argument b'x': %c requires an integer in range(256) or a single byte, not float") test_exc(b"%b", "Xc", TypeError, "format argument: %b requires a bytes-like object, " "or an object that implements __bytes__, not str")