mirror of
https://github.com/python/cpython.git
synced 2026-05-05 01:51:01 +00:00
gh-142037: Improve error messages for printf-style formatting (GH-142081)
This affects string formatting as well as bytes and bytearray formatting. * For errors in the format string, always include the position of the start of the format unit. * For errors related to the formatted arguments, always include the number or the name of the formatted argument. * Suggest more probable causes of errors in the format string (stray %, unsupported format, unexpected character). * Provide more information when the number of arguments does not match the number of format units. * Raise more specific errors when access of arguments by name is mixed with sequential access and when * is used with a mapping. * Add tests for some uncovered cases.
This commit is contained in:
parent
5f736a0432
commit
012c498035
7 changed files with 591 additions and 207 deletions
|
|
@ -792,16 +792,16 @@ def __int__(self):
|
|||
pi = PseudoFloat(3.1415)
|
||||
|
||||
exceptions_params = [
|
||||
('%x format: an integer is required, not float', b'%x', 3.14),
|
||||
('%X format: an integer is required, not float', b'%X', 2.11),
|
||||
('%o format: an integer is required, not float', b'%o', 1.79),
|
||||
('%x format: an integer is required, not PseudoFloat', b'%x', pi),
|
||||
('%x format: an integer is required, not complex', b'%x', 3j),
|
||||
('%X format: an integer is required, not complex', b'%X', 2j),
|
||||
('%o format: an integer is required, not complex', b'%o', 1j),
|
||||
('%u format: a real number is required, not complex', b'%u', 3j),
|
||||
('%i format: a real number is required, not complex', b'%i', 2j),
|
||||
('%d format: a real number is required, not complex', b'%d', 2j),
|
||||
('%x requires an integer, not float', b'%x', 3.14),
|
||||
('%X requires an integer, not float', b'%X', 2.11),
|
||||
('%o requires an integer, not float', b'%o', 1.79),
|
||||
(r'%x requires an integer, not .*\.PseudoFloat', b'%x', pi),
|
||||
('%x requires an integer, not complex', b'%x', 3j),
|
||||
('%X requires an integer, not complex', b'%X', 2j),
|
||||
('%o requires an integer, not complex', b'%o', 1j),
|
||||
('%u requires a real number, not complex', b'%u', 3j),
|
||||
('%i requires a real number, not complex', b'%i', 2j),
|
||||
('%d requires a real number, not complex', b'%d', 2j),
|
||||
(
|
||||
r'%c requires an integer in range\(256\)'
|
||||
r' or a single byte, not .*\.PseudoFloat',
|
||||
|
|
@ -810,7 +810,7 @@ def __int__(self):
|
|||
]
|
||||
|
||||
for msg, format_bytes, value in exceptions_params:
|
||||
with self.assertRaisesRegex(TypeError, msg):
|
||||
with self.assertRaisesRegex(TypeError, 'format argument: ' + msg):
|
||||
operator.mod(format_bytes, value)
|
||||
|
||||
def test_memory_leak_gh_140939(self):
|
||||
|
|
|
|||
|
|
@ -57,10 +57,6 @@ def testcommon(formatstr, args, output=None, limit=None, overflowok=False):
|
|||
else:
|
||||
b_format = formatstr
|
||||
ba_format = bytearray(b_format)
|
||||
b_args = []
|
||||
if not isinstance(args, tuple):
|
||||
args = (args, )
|
||||
b_args = tuple(args)
|
||||
if output is None:
|
||||
b_output = ba_output = None
|
||||
else:
|
||||
|
|
@ -69,8 +65,8 @@ def testcommon(formatstr, args, output=None, limit=None, overflowok=False):
|
|||
else:
|
||||
b_output = output
|
||||
ba_output = bytearray(b_output)
|
||||
testformat(b_format, b_args, b_output, limit, overflowok)
|
||||
testformat(ba_format, b_args, ba_output, limit, overflowok)
|
||||
testformat(b_format, args, b_output, limit, overflowok)
|
||||
testformat(ba_format, args, ba_output, limit, overflowok)
|
||||
|
||||
def test_exc(formatstr, args, exception, excmsg):
|
||||
try:
|
||||
|
|
@ -82,6 +78,7 @@ def test_exc(formatstr, args, exception, excmsg):
|
|||
else:
|
||||
if verbose: print('no')
|
||||
print('Unexpected ', exception, ':', repr(str(exc)))
|
||||
raise
|
||||
except:
|
||||
if verbose: print('no')
|
||||
print('Unexpected exception')
|
||||
|
|
@ -92,6 +89,8 @@ def test_exc(formatstr, args, exception, excmsg):
|
|||
def test_exc_common(formatstr, args, exception, excmsg):
|
||||
# test str and bytes
|
||||
test_exc(formatstr, args, exception, excmsg)
|
||||
if isinstance(args, dict):
|
||||
args = {k.encode('ascii'): v for k, v in args.items()}
|
||||
test_exc(formatstr.encode('ascii'), args, exception, excmsg)
|
||||
|
||||
class FormatTest(unittest.TestCase):
|
||||
|
|
@ -272,45 +271,154 @@ 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('abc %', (), ValueError, "stray % at position 4")
|
||||
test_exc_common('abc % %s', 1, ValueError,
|
||||
"stray % at position 4 or unexpected format character '%' at position 6")
|
||||
test_exc_common('abc %z', 1, ValueError,
|
||||
"unsupported format %z at position 4")
|
||||
test_exc_common("abc %Id", 1, ValueError,
|
||||
"unsupported format %I at position 4")
|
||||
test_exc_common("abc %'d", 1, ValueError,
|
||||
"stray % at position 4 or unexpected format character \"'\" at position 5")
|
||||
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")
|
||||
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)")
|
||||
test_exc_common('%r %r', (1,), TypeError,
|
||||
"not enough arguments for format string (got 1)")
|
||||
test_exc_common('%r', (), TypeError,
|
||||
"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)")
|
||||
test_exc_common('%r %*r', (1,), TypeError,
|
||||
"not enough arguments for format string (got 1)")
|
||||
test_exc_common('%*r', (1,), TypeError,
|
||||
"not enough arguments for format string (got 1)")
|
||||
test_exc_common('%*r', (), TypeError,
|
||||
"not enough arguments for format string (got 0)")
|
||||
test_exc_common('%r %.*r', 1, TypeError,
|
||||
"not enough arguments for format string (got 1)")
|
||||
test_exc_common('%r %.*r', (1,), TypeError,
|
||||
"not enough arguments for format string (got 1)")
|
||||
test_exc_common('%.*r', (1,), TypeError,
|
||||
"not enough arguments for format string (got 1)")
|
||||
test_exc_common('%.*r', (), TypeError,
|
||||
"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)")
|
||||
test_exc_common('%*r', 3.14, TypeError,
|
||||
"not enough arguments for format string (got 1)")
|
||||
test_exc_common('%*r', (3.14, 1), TypeError,
|
||||
"format argument 1: * requires int, not float")
|
||||
test_exc_common('%.*r', 1, TypeError,
|
||||
"not enough arguments for format string (got 1)")
|
||||
test_exc_common('%.*r', 3.14, TypeError,
|
||||
"not enough arguments for format string (got 1)")
|
||||
test_exc_common('%.*r', (3.14, 1), TypeError,
|
||||
"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,
|
||||
"format argument 1: too big for width")
|
||||
test_exc_common('%.*r', (2**1000, 1), OverflowError,
|
||||
"format argument 1: too big for precision")
|
||||
test_exc_common('%.*r', (-2**1000, 1), OverflowError,
|
||||
"format argument 1: too big for precision")
|
||||
test_exc_common('%d', '1', TypeError,
|
||||
"%d format: a real number is required, not str")
|
||||
"format argument: %d requires a real number, not str")
|
||||
test_exc_common('%d', b'1', TypeError,
|
||||
"%d format: a real number is required, not bytes")
|
||||
"format argument: %d requires a real number, not bytes")
|
||||
test_exc_common('%d', ('1',), TypeError,
|
||||
"format argument 1: %d requires a real number, not str")
|
||||
test_exc_common('%x', '1', TypeError,
|
||||
"%x format: an integer is required, not str")
|
||||
"format argument: %x requires an integer, not str")
|
||||
test_exc_common('%x', 3.14, TypeError,
|
||||
"%x format: an integer is required, not float")
|
||||
"format argument: %x requires an integer, not float")
|
||||
test_exc_common('%x', ('1',), TypeError,
|
||||
"format argument 1: %x requires an integer, not str")
|
||||
test_exc_common('%i', '1', TypeError,
|
||||
"%i format: a real number is required, not str")
|
||||
"format argument: %i requires a real number, not str")
|
||||
test_exc_common('%i', b'1', TypeError,
|
||||
"%i format: a real number is required, not bytes")
|
||||
"format argument: %i requires a real number, not bytes")
|
||||
test_exc_common('%g', '1', TypeError,
|
||||
"format argument: %g requires a real number, not str")
|
||||
test_exc_common('%g', ('1',), TypeError,
|
||||
"format argument 1: %g requires a real number, not str")
|
||||
|
||||
def test_str_format(self):
|
||||
testformat("%r", "\u0378", "'\\u0378'") # non printable
|
||||
testformat("%a", "\u0378", "'\\u0378'") # non printable
|
||||
testformat("%r", "\u0374", "'\u0374'") # printable
|
||||
testformat("%a", "\u0374", "'\\u0374'") # printable
|
||||
testformat('%(x)r', {'x': 1}, '1')
|
||||
|
||||
# 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")
|
||||
"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")
|
||||
test_exc("abc %\x1fd", 1, ValueError,
|
||||
"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")
|
||||
test_exc("abc %\x80d", 1, ValueError,
|
||||
"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")
|
||||
test_exc('abc %€d', 1, ValueError,
|
||||
"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")
|
||||
test_exc('%c', -1, OverflowError, "%c arg not in range(0x110000)")
|
||||
"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)")
|
||||
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")
|
||||
test_exc('%(x).*r', {'x': 1}, ValueError,
|
||||
"* 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,
|
||||
"format argument 'x': %x requires an integer, not str")
|
||||
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)")
|
||||
test_exc('%c', (-1,), OverflowError,
|
||||
"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)")
|
||||
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")
|
||||
"format argument: %c argument not in range(0x110000)")
|
||||
test_exc('%c', 2**128, OverflowError,
|
||||
"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,
|
||||
"format argument 1: %c requires an integer or a unicode character, not float")
|
||||
test_exc('%(x)c', {'x': 3.14}, TypeError,
|
||||
"format argument 'x': %c requires an integer or a unicode character, not float")
|
||||
test_exc('%c', 'ab', TypeError,
|
||||
"format argument: %c requires an integer or a unicode character, not a string of length 2")
|
||||
test_exc('%c', ('ab',), TypeError,
|
||||
"format argument 1: %c requires an integer or a unicode character, not a string of length 2")
|
||||
test_exc('%(x)c', {'x': 'ab'}, TypeError,
|
||||
"format argument 'x': %c requires an integer or a unicode character, not a string of length 2")
|
||||
test_exc('%c', b'x', TypeError,
|
||||
"format argument: %c requires an integer or a unicode character, not bytes")
|
||||
|
||||
if maxsize == 2**31-1:
|
||||
# crashes 2.2.1 and earlier:
|
||||
|
|
@ -355,36 +463,83 @@ def __bytes__(self):
|
|||
testcommon(b"%r", b"ghi", b"b'ghi'")
|
||||
testcommon(b"%r", "jkl", b"'jkl'")
|
||||
testcommon(b"%r", "\u0544", b"'\\u0544'")
|
||||
testcommon(b'%(x)r', {b'x': 1}, b'1')
|
||||
|
||||
# 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"abc %\nd", 1, ValueError,
|
||||
"stray % at position 4 or unexpected format character with code 0x0a at position 5")
|
||||
test_exc(b"abc %'d", 1, ValueError,
|
||||
"stray % at position 4 or unexpected format character \"'\" at position 5")
|
||||
test_exc(b"abc %\x1fd", 1, ValueError,
|
||||
"stray % at position 4 or unexpected format character with code 0x1f at position 5")
|
||||
test_exc(b"abc %\x7fd", 1, ValueError,
|
||||
"stray % at position 4 or unexpected format character with code 0x7f at position 5")
|
||||
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")
|
||||
"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")
|
||||
"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")
|
||||
"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)")
|
||||
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")
|
||||
test_exc(b'%(x).*r', {b'x': 1}, ValueError,
|
||||
"* 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,
|
||||
"format argument b'x': %x requires an integer, not str")
|
||||
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,
|
||||
"%c arg 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)")
|
||||
test_exc(b"%(x)c", {b'x': -1}, OverflowError,
|
||||
"format argument b'x': %c argument not in range(256)")
|
||||
test_exc(b"%c", 256, OverflowError,
|
||||
"%c arg not in range(256)")
|
||||
"format argument: %c argument not in range(256)")
|
||||
test_exc(b"%c", 2**128, OverflowError,
|
||||
"%c arg not in range(256)")
|
||||
"format argument: %c argument 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")
|
||||
"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")
|
||||
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")
|
||||
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")
|
||||
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")
|
||||
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")
|
||||
test_exc(b"%c", "Y", TypeError,
|
||||
"%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,
|
||||
"%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")
|
||||
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")
|
||||
test_exc(b"%b", "Xc", TypeError,
|
||||
"%b requires a bytes-like object, "
|
||||
"or an object that implements __bytes__, not 'str'")
|
||||
"format argument: %b requires a bytes-like object, "
|
||||
"or an object that implements __bytes__, not str")
|
||||
test_exc(b"%b", ("Xc",), TypeError,
|
||||
"format argument 1: %b requires a bytes-like object, "
|
||||
"or an object that implements __bytes__, not str")
|
||||
test_exc(b"%(x)b", {b'x': "Xc"}, TypeError,
|
||||
"format argument b'x': %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'")
|
||||
"format argument: %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:
|
||||
|
|
@ -626,7 +781,7 @@ def test_specifier_z_error(self):
|
|||
with self.assertRaisesRegex(ValueError, error_msg):
|
||||
f"{'x':zs}" # can't apply to string
|
||||
|
||||
error_msg = re.escape("unsupported format character 'z'")
|
||||
error_msg = re.escape("unsupported format %z at position 0")
|
||||
with self.assertRaisesRegex(ValueError, error_msg):
|
||||
"%z.1f" % 0 # not allowed in old style string interpolation
|
||||
with self.assertRaisesRegex(ValueError, error_msg):
|
||||
|
|
|
|||
|
|
@ -733,22 +733,27 @@ def test_format_errors(self):
|
|||
with self.assertRaisesRegex(TypeError,
|
||||
'not all arguments converted during string formatting'):
|
||||
eval("'%s' % (x, y)", {'x': 1, 'y': 2})
|
||||
with self.assertRaisesRegex(ValueError, 'incomplete format'):
|
||||
with self.assertRaisesRegex(ValueError, 'stray % at position 2'):
|
||||
eval("'%s%' % (x,)", {'x': 1234})
|
||||
with self.assertRaisesRegex(ValueError, 'incomplete format'):
|
||||
with self.assertRaisesRegex(ValueError, 'stray % at position 4'):
|
||||
eval("'%s%%%' % (x,)", {'x': 1234})
|
||||
with self.assertRaisesRegex(TypeError,
|
||||
'not enough arguments for format string'):
|
||||
eval("'%s%z' % (x,)", {'x': 1234})
|
||||
with self.assertRaisesRegex(ValueError, 'unsupported format character'):
|
||||
with self.assertRaisesRegex(ValueError,
|
||||
'unsupported format %z at position 2'):
|
||||
eval("'%s%z' % (x, 5)", {'x': 1234})
|
||||
with self.assertRaisesRegex(TypeError, 'a real number is required, not str'):
|
||||
with self.assertRaisesRegex(TypeError,
|
||||
'format argument 1: %d requires a real number, not str'):
|
||||
eval("'%d' % (x,)", {'x': '1234'})
|
||||
with self.assertRaisesRegex(TypeError, 'an integer is required, not float'):
|
||||
with self.assertRaisesRegex(TypeError,
|
||||
'format argument 1: %x requires an integer, not float'):
|
||||
eval("'%x' % (x,)", {'x': 1234.56})
|
||||
with self.assertRaisesRegex(TypeError, 'an integer is required, not str'):
|
||||
with self.assertRaisesRegex(TypeError,
|
||||
'format argument 1: %x requires an integer, not str'):
|
||||
eval("'%x' % (x,)", {'x': '1234'})
|
||||
with self.assertRaisesRegex(TypeError, 'must be real number, not str'):
|
||||
with self.assertRaisesRegex(TypeError,
|
||||
'format argument 1: %f requires a real number, not str'):
|
||||
eval("'%f' % (x,)", {'x': '1234'})
|
||||
with self.assertRaisesRegex(TypeError,
|
||||
'not enough arguments for format string'):
|
||||
|
|
|
|||
|
|
@ -1578,17 +1578,40 @@ def __int__(self):
|
|||
self.assertEqual('%X' % letter_m, '6D')
|
||||
self.assertEqual('%o' % letter_m, '155')
|
||||
self.assertEqual('%c' % letter_m, 'm')
|
||||
self.assertRaisesRegex(TypeError, '%x format: an integer is required, not float', operator.mod, '%x', 3.14)
|
||||
self.assertRaisesRegex(TypeError, '%X format: an integer is required, not float', operator.mod, '%X', 2.11)
|
||||
self.assertRaisesRegex(TypeError, '%o format: an integer is required, not float', operator.mod, '%o', 1.79)
|
||||
self.assertRaisesRegex(TypeError, '%x format: an integer is required, not PseudoFloat', operator.mod, '%x', pi)
|
||||
self.assertRaisesRegex(TypeError, '%x format: an integer is required, not complex', operator.mod, '%x', 3j)
|
||||
self.assertRaisesRegex(TypeError, '%X format: an integer is required, not complex', operator.mod, '%X', 2j)
|
||||
self.assertRaisesRegex(TypeError, '%o format: an integer is required, not complex', operator.mod, '%o', 1j)
|
||||
self.assertRaisesRegex(TypeError, '%u format: a real number is required, not complex', operator.mod, '%u', 3j)
|
||||
self.assertRaisesRegex(TypeError, '%i format: a real number is required, not complex', operator.mod, '%i', 2j)
|
||||
self.assertRaisesRegex(TypeError, '%d format: a real number is required, not complex', operator.mod, '%d', 1j)
|
||||
self.assertRaisesRegex(TypeError, r'%c requires an int or a unicode character, not .*\.PseudoFloat', operator.mod, '%c', pi)
|
||||
with self.assertRaisesRegex(TypeError,
|
||||
'format argument: %x requires an integer, not float'):
|
||||
'%x' % 3.14
|
||||
with self.assertRaisesRegex(TypeError,
|
||||
'format argument: %X requires an integer, not float'):
|
||||
'%X' % 2.11
|
||||
with self.assertRaisesRegex(TypeError,
|
||||
'format argument: %o requires an integer, not float'):
|
||||
'%o' % 1.79
|
||||
with self.assertRaisesRegex(TypeError,
|
||||
r'format argument: %x requires an integer, not .*\.PseudoFloat'):
|
||||
'%x' % pi
|
||||
with self.assertRaisesRegex(TypeError,
|
||||
'format argument: %x requires an integer, not complex'):
|
||||
'%x' % 3j
|
||||
with self.assertRaisesRegex(TypeError,
|
||||
'format argument: %X requires an integer, not complex'):
|
||||
'%X' % 2j
|
||||
with self.assertRaisesRegex(TypeError,
|
||||
'format argument: %o requires an integer, not complex'):
|
||||
'%o' % 1j
|
||||
with self.assertRaisesRegex(TypeError,
|
||||
'format argument: %u requires a real number, not complex'):
|
||||
'%u' % 3j
|
||||
with self.assertRaisesRegex(TypeError,
|
||||
'format argument: %i requires a real number, not complex'):
|
||||
'%i' % 2j
|
||||
with self.assertRaisesRegex(TypeError,
|
||||
'format argument: %d requires a real number, not complex'):
|
||||
'%d' % 1j
|
||||
with self.assertRaisesRegex(TypeError,
|
||||
r'format argument: %c requires an integer or a unicode character, '
|
||||
r'not .*\.PseudoFloat'):
|
||||
'%c' % pi
|
||||
|
||||
class RaisingNumber:
|
||||
def __int__(self):
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
Improve error messages for printf-style formatting.
|
||||
For errors in the format string, always include the position of the
|
||||
start of the format unit.
|
||||
For errors related to the formatted arguments, always include the number
|
||||
or the name of the argument.
|
||||
Raise more specific errors and include more information (type and number
|
||||
of arguments, most probable causes of error).
|
||||
|
|
@ -404,26 +404,44 @@ PyBytes_FromFormat(const char *format, ...)
|
|||
|
||||
/* Helpers for formatstring */
|
||||
|
||||
#define FORMAT_ERROR(EXC, FMT, ...) do { \
|
||||
if (key != NULL) { \
|
||||
PyErr_Format((EXC), "format argument %R: " FMT, \
|
||||
key, __VA_ARGS__); \
|
||||
} \
|
||||
else if (argidx >= 0) { \
|
||||
PyErr_Format((EXC), "format argument %zd: " FMT, \
|
||||
argidx, __VA_ARGS__); \
|
||||
} \
|
||||
else { \
|
||||
PyErr_Format((EXC), "format argument: " FMT, __VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
Py_LOCAL_INLINE(PyObject *)
|
||||
getnextarg(PyObject *args, Py_ssize_t arglen, Py_ssize_t *p_argidx)
|
||||
getnextarg(PyObject *args, Py_ssize_t arglen, Py_ssize_t *p_argidx, int allowone)
|
||||
{
|
||||
Py_ssize_t argidx = *p_argidx;
|
||||
if (argidx < arglen) {
|
||||
(*p_argidx)++;
|
||||
if (arglen < 0)
|
||||
return args;
|
||||
else
|
||||
if (arglen >= 0) {
|
||||
return PyTuple_GetItem(args, argidx);
|
||||
}
|
||||
else if (allowone) {
|
||||
return args;
|
||||
}
|
||||
}
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"not enough arguments for format string");
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"not enough arguments for format string (got %zd)",
|
||||
arglen < 0 ? 1 : arglen);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Returns a new reference to a PyBytes object, or NULL on failure. */
|
||||
|
||||
static char*
|
||||
formatfloat(PyObject *v, int flags, int prec, int type,
|
||||
formatfloat(PyObject *v, Py_ssize_t argidx, PyObject *key,
|
||||
int flags, int prec, int type,
|
||||
PyObject **p_result, PyBytesWriter *writer, char *str)
|
||||
{
|
||||
char *p;
|
||||
|
|
@ -434,8 +452,11 @@ formatfloat(PyObject *v, int flags, int prec, int type,
|
|||
|
||||
x = PyFloat_AsDouble(v);
|
||||
if (x == -1.0 && PyErr_Occurred()) {
|
||||
PyErr_Format(PyExc_TypeError, "float argument required, "
|
||||
"not %.200s", Py_TYPE(v)->tp_name);
|
||||
if (PyErr_ExceptionMatches(PyExc_TypeError)) {
|
||||
FORMAT_ERROR(PyExc_TypeError,
|
||||
"%%%c requires a real number, not %T",
|
||||
type, v);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -470,7 +491,8 @@ formatfloat(PyObject *v, int flags, int prec, int type,
|
|||
}
|
||||
|
||||
static PyObject *
|
||||
formatlong(PyObject *v, int flags, int prec, int type)
|
||||
formatlong(PyObject *v, Py_ssize_t argidx, PyObject *key,
|
||||
int flags, int prec, int type)
|
||||
{
|
||||
PyObject *result, *iobj;
|
||||
if (PyLong_Check(v))
|
||||
|
|
@ -490,20 +512,21 @@ formatlong(PyObject *v, int flags, int prec, int type)
|
|||
if (!PyErr_ExceptionMatches(PyExc_TypeError))
|
||||
return NULL;
|
||||
}
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%%%c format: %s is required, not %.200s", type,
|
||||
(type == 'o' || type == 'x' || type == 'X') ? "an integer"
|
||||
: "a real number",
|
||||
Py_TYPE(v)->tp_name);
|
||||
FORMAT_ERROR(PyExc_TypeError,
|
||||
"%%%c requires %s, not %T",
|
||||
type,
|
||||
(type == 'o' || type == 'x' || type == 'X') ? "an integer"
|
||||
: "a real number",
|
||||
v);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
byte_converter(PyObject *arg, char *p)
|
||||
byte_converter(PyObject *arg, Py_ssize_t argidx, PyObject *key, char *p)
|
||||
{
|
||||
if (PyBytes_Check(arg)) {
|
||||
if (PyBytes_GET_SIZE(arg) != 1) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
FORMAT_ERROR(PyExc_TypeError,
|
||||
"%%c requires an integer in range(256) or "
|
||||
"a single byte, not a bytes object of length %zd",
|
||||
PyBytes_GET_SIZE(arg));
|
||||
|
|
@ -514,7 +537,7 @@ byte_converter(PyObject *arg, char *p)
|
|||
}
|
||||
else if (PyByteArray_Check(arg)) {
|
||||
if (PyByteArray_GET_SIZE(arg) != 1) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
FORMAT_ERROR(PyExc_TypeError,
|
||||
"%%c requires an integer in range(256) or "
|
||||
"a single byte, not a bytearray object of length %zd",
|
||||
PyByteArray_GET_SIZE(arg));
|
||||
|
|
@ -531,23 +554,25 @@ byte_converter(PyObject *arg, char *p)
|
|||
}
|
||||
if (!(0 <= ival && ival <= 255)) {
|
||||
/* this includes an overflow in converting to C long */
|
||||
PyErr_SetString(PyExc_OverflowError,
|
||||
"%c arg not in range(256)");
|
||||
FORMAT_ERROR(PyExc_OverflowError,
|
||||
"%%c argument not in range(256)%s", "");
|
||||
return 0;
|
||||
}
|
||||
*p = (char)ival;
|
||||
return 1;
|
||||
}
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%%c requires an integer in range(256) or a single byte, not %T",
|
||||
arg);
|
||||
FORMAT_ERROR(PyExc_TypeError,
|
||||
"%%c requires an integer in range(256) or "
|
||||
"a single byte, not %T",
|
||||
arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyObject *_PyBytes_FromBuffer(PyObject *x);
|
||||
|
||||
static PyObject *
|
||||
format_obj(PyObject *v, const char **pbuf, Py_ssize_t *plen)
|
||||
format_obj(PyObject *v, Py_ssize_t argidx, PyObject *key,
|
||||
const char **pbuf, Py_ssize_t *plen)
|
||||
{
|
||||
PyObject *func, *result;
|
||||
/* is it a bytes object? */
|
||||
|
|
@ -589,10 +614,10 @@ format_obj(PyObject *v, const char **pbuf, Py_ssize_t *plen)
|
|||
*plen = PyBytes_GET_SIZE(result);
|
||||
return result;
|
||||
}
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
FORMAT_ERROR(PyExc_TypeError,
|
||||
"%%b requires a bytes-like object, "
|
||||
"or an object that implements __bytes__, not '%.100s'",
|
||||
Py_TYPE(v)->tp_name);
|
||||
"or an object that implements __bytes__, not %T",
|
||||
v);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -607,6 +632,7 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len,
|
|||
Py_ssize_t fmtcnt;
|
||||
int args_owned = 0;
|
||||
PyObject *dict = NULL;
|
||||
PyObject *key = NULL;
|
||||
|
||||
if (args == NULL) {
|
||||
PyErr_BadInternalCall();
|
||||
|
|
@ -680,15 +706,17 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len,
|
|||
fmtcnt--;
|
||||
continue;
|
||||
}
|
||||
Py_CLEAR(key);
|
||||
const char *fmtstart = fmt;
|
||||
if (*fmt == '(') {
|
||||
const char *keystart;
|
||||
Py_ssize_t keylen;
|
||||
PyObject *key;
|
||||
int pcount = 1;
|
||||
|
||||
if (dict == NULL) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"format requires a mapping");
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"format requires a mapping, not %T",
|
||||
args);
|
||||
goto error;
|
||||
}
|
||||
++fmt;
|
||||
|
|
@ -704,8 +732,10 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len,
|
|||
}
|
||||
keylen = fmt - keystart - 1;
|
||||
if (fmtcnt < 0 || pcount > 0) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"incomplete format key");
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"stray %% or incomplete format key "
|
||||
"at position %zd",
|
||||
(Py_ssize_t)(fmtstart - format - 1));
|
||||
goto error;
|
||||
}
|
||||
key = PyBytes_FromStringAndSize(keystart,
|
||||
|
|
@ -717,13 +747,21 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len,
|
|||
args_owned = 0;
|
||||
}
|
||||
args = PyObject_GetItem(dict, key);
|
||||
Py_DECREF(key);
|
||||
if (args == NULL) {
|
||||
goto error;
|
||||
}
|
||||
args_owned = 1;
|
||||
arglen = -1;
|
||||
argidx = -2;
|
||||
arglen = -3;
|
||||
argidx = -4;
|
||||
}
|
||||
else {
|
||||
if (arglen < -1) {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"format requires a parenthesised mapping key "
|
||||
"at position %zd",
|
||||
(Py_ssize_t)(fmtstart - format - 1));
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/* Parse flags. Example: "%+i" => flags=F_SIGN. */
|
||||
|
|
@ -740,17 +778,28 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len,
|
|||
|
||||
/* Parse width. Example: "%10s" => width=10 */
|
||||
if (c == '*') {
|
||||
v = getnextarg(args, arglen, &argidx);
|
||||
if (arglen < -1) {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"* cannot be used with a parenthesised mapping key "
|
||||
"at position %zd",
|
||||
(Py_ssize_t)(fmtstart - format - 1));
|
||||
goto error;
|
||||
}
|
||||
v = getnextarg(args, arglen, &argidx, 0);
|
||||
if (v == NULL)
|
||||
goto error;
|
||||
if (!PyLong_Check(v)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"* wants int");
|
||||
FORMAT_ERROR(PyExc_TypeError, "* requires int, not %T", v);
|
||||
goto error;
|
||||
}
|
||||
width = PyLong_AsSsize_t(v);
|
||||
if (width == -1 && PyErr_Occurred())
|
||||
if (width == -1 && PyErr_Occurred()) {
|
||||
if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
|
||||
FORMAT_ERROR(PyExc_OverflowError,
|
||||
"too big for width%s", "");
|
||||
}
|
||||
goto error;
|
||||
}
|
||||
if (width < 0) {
|
||||
flags |= F_LJUST;
|
||||
width = -width;
|
||||
|
|
@ -765,9 +814,9 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len,
|
|||
if (!Py_ISDIGIT(c))
|
||||
break;
|
||||
if (width > (PY_SSIZE_T_MAX - ((int)c - '0')) / 10) {
|
||||
PyErr_SetString(
|
||||
PyExc_ValueError,
|
||||
"width too big");
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"width too big at position %zd",
|
||||
(Py_ssize_t)(fmtstart - format - 1));
|
||||
goto error;
|
||||
}
|
||||
width = width*10 + (c - '0');
|
||||
|
|
@ -780,18 +829,29 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len,
|
|||
if (--fmtcnt >= 0)
|
||||
c = *fmt++;
|
||||
if (c == '*') {
|
||||
v = getnextarg(args, arglen, &argidx);
|
||||
if (arglen < -1) {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"* cannot be used with a parenthesised mapping key "
|
||||
"at position %zd",
|
||||
(Py_ssize_t)(fmtstart - format - 1));
|
||||
goto error;
|
||||
}
|
||||
v = getnextarg(args, arglen, &argidx, 0);
|
||||
if (v == NULL)
|
||||
goto error;
|
||||
if (!PyLong_Check(v)) {
|
||||
PyErr_SetString(
|
||||
PyExc_TypeError,
|
||||
"* wants int");
|
||||
FORMAT_ERROR(PyExc_TypeError,
|
||||
"* requires int, not %T", v);
|
||||
goto error;
|
||||
}
|
||||
prec = PyLong_AsInt(v);
|
||||
if (prec == -1 && PyErr_Occurred())
|
||||
if (prec == -1 && PyErr_Occurred()) {
|
||||
if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
|
||||
FORMAT_ERROR(PyExc_OverflowError,
|
||||
"too big for precision%s", "");
|
||||
}
|
||||
goto error;
|
||||
}
|
||||
if (prec < 0)
|
||||
prec = 0;
|
||||
if (--fmtcnt >= 0)
|
||||
|
|
@ -804,9 +864,9 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len,
|
|||
if (!Py_ISDIGIT(c))
|
||||
break;
|
||||
if (prec > (INT_MAX - ((int)c - '0')) / 10) {
|
||||
PyErr_SetString(
|
||||
PyExc_ValueError,
|
||||
"prec too big");
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"precision too big at position %zd",
|
||||
(Py_ssize_t)(fmtstart - format - 1));
|
||||
goto error;
|
||||
}
|
||||
prec = prec*10 + (c - '0');
|
||||
|
|
@ -820,11 +880,12 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len,
|
|||
}
|
||||
}
|
||||
if (fmtcnt < 0) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"incomplete format");
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"stray %% at position %zd",
|
||||
(Py_ssize_t)(fmtstart - format - 1));
|
||||
goto error;
|
||||
}
|
||||
v = getnextarg(args, arglen, &argidx);
|
||||
v = getnextarg(args, arglen, &argidx, 1);
|
||||
if (v == NULL)
|
||||
goto error;
|
||||
|
||||
|
|
@ -852,7 +913,7 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len,
|
|||
case 's':
|
||||
// %s is only for 2/3 code; 3 only code should use %b
|
||||
case 'b':
|
||||
temp = format_obj(v, &pbuf, &len);
|
||||
temp = format_obj(v, argidx, key, &pbuf, &len);
|
||||
if (temp == NULL)
|
||||
goto error;
|
||||
if (prec >= 0 && len > prec)
|
||||
|
|
@ -900,7 +961,7 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len,
|
|||
continue;
|
||||
}
|
||||
|
||||
temp = formatlong(v, flags, prec, c);
|
||||
temp = formatlong(v, argidx, key, flags, prec, c);
|
||||
if (!temp)
|
||||
goto error;
|
||||
assert(PyUnicode_IS_ASCII(temp));
|
||||
|
|
@ -921,13 +982,13 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len,
|
|||
&& !(flags & (F_SIGN | F_BLANK)))
|
||||
{
|
||||
/* Fast path */
|
||||
res = formatfloat(v, flags, prec, c, NULL, writer, res);
|
||||
res = formatfloat(v, argidx, key, flags, prec, c, NULL, writer, res);
|
||||
if (res == NULL)
|
||||
goto error;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!formatfloat(v, flags, prec, c, &temp, NULL, res))
|
||||
if (!formatfloat(v, argidx, key, flags, prec, c, &temp, NULL, res))
|
||||
goto error;
|
||||
pbuf = PyBytes_AS_STRING(temp);
|
||||
len = PyBytes_GET_SIZE(temp);
|
||||
|
|
@ -938,7 +999,7 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len,
|
|||
|
||||
case 'c':
|
||||
pbuf = &onechar;
|
||||
len = byte_converter(v, &onechar);
|
||||
len = byte_converter(v, argidx, key, &onechar);
|
||||
if (!len)
|
||||
goto error;
|
||||
if (width == -1) {
|
||||
|
|
@ -949,11 +1010,36 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len,
|
|||
break;
|
||||
|
||||
default:
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"unsupported format character '%c' (0x%x) "
|
||||
"at index %zd",
|
||||
c, c,
|
||||
(Py_ssize_t)(fmt - 1 - format));
|
||||
if (Py_ISALPHA(c)) {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"unsupported format %%%c at position %zd",
|
||||
c, (Py_ssize_t)(fmtstart - format - 1));
|
||||
}
|
||||
else if (c == '\'') {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"stray %% at position %zd or unexpected "
|
||||
"format character \"'\" "
|
||||
"at position %zd",
|
||||
(Py_ssize_t)(fmtstart - format - 1),
|
||||
(Py_ssize_t)(fmt - format - 1));
|
||||
}
|
||||
else if (c >= 32 && c < 127 && c != '\'') {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"stray %% at position %zd or unexpected "
|
||||
"format character '%c' "
|
||||
"at position %zd",
|
||||
(Py_ssize_t)(fmtstart - format - 1),
|
||||
c, (Py_ssize_t)(fmt - format - 1));
|
||||
}
|
||||
else {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"stray %% at position %zd or unexpected "
|
||||
"format character with code 0x%02x "
|
||||
"at position %zd",
|
||||
(Py_ssize_t)(fmtstart - format - 1),
|
||||
Py_CHARMASK(c),
|
||||
(Py_ssize_t)(fmt - format - 1));
|
||||
}
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
|
@ -1042,6 +1128,7 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len,
|
|||
}
|
||||
|
||||
if (dict && (argidx < arglen)) {
|
||||
// XXX: Never happens?
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"not all arguments converted during bytes formatting");
|
||||
Py_XDECREF(temp);
|
||||
|
|
@ -1061,8 +1148,11 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len,
|
|||
} /* until end */
|
||||
|
||||
if (argidx < arglen && !dict) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"not all arguments converted during bytes formatting");
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"not all arguments converted during bytes formatting "
|
||||
"(required %zd, got %zd)",
|
||||
arglen < 0 ? 0 : argidx,
|
||||
arglen < 0 ? 1 : arglen);
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
|
@ -1072,6 +1162,7 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len,
|
|||
return PyBytesWriter_FinishWithPointer(writer, res);
|
||||
|
||||
error:
|
||||
Py_XDECREF(key);
|
||||
PyBytesWriter_Discard(writer);
|
||||
if (args_owned) {
|
||||
Py_DECREF(args);
|
||||
|
|
|
|||
|
|
@ -72,23 +72,44 @@ struct unicode_format_arg_t {
|
|||
Py_ssize_t width;
|
||||
int prec;
|
||||
int sign;
|
||||
Py_ssize_t fmtstart;
|
||||
PyObject *key;
|
||||
};
|
||||
|
||||
|
||||
// Use FORMAT_ERROR("...%s", "") when there is no arguments.
|
||||
#define FORMAT_ERROR(EXC, FMT, ...) do { \
|
||||
if (arg->key != NULL) { \
|
||||
PyErr_Format((EXC), "format argument %R: " FMT, \
|
||||
arg->key, __VA_ARGS__); \
|
||||
} \
|
||||
else if (ctx->argidx >= 0) { \
|
||||
PyErr_Format((EXC), "format argument %zd: " FMT, \
|
||||
ctx->argidx, __VA_ARGS__); \
|
||||
} \
|
||||
else { \
|
||||
PyErr_Format((EXC), "format argument: " FMT, __VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
static PyObject *
|
||||
unicode_format_getnextarg(struct unicode_formatter_t *ctx)
|
||||
unicode_format_getnextarg(struct unicode_formatter_t *ctx, int allowone)
|
||||
{
|
||||
Py_ssize_t argidx = ctx->argidx;
|
||||
|
||||
if (argidx < ctx->arglen) {
|
||||
if (argidx < ctx->arglen && (allowone || ctx->arglen >= 0)) {
|
||||
ctx->argidx++;
|
||||
if (ctx->arglen < 0)
|
||||
return ctx->args;
|
||||
else
|
||||
if (ctx->arglen >= 0) {
|
||||
return PyTuple_GetItem(ctx->args, argidx);
|
||||
}
|
||||
else if (allowone) {
|
||||
return ctx->args;
|
||||
}
|
||||
}
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"not enough arguments for format string");
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"not enough arguments for format string (got %zd)",
|
||||
ctx->arglen < 0 ? 1 : ctx->arglen);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -100,7 +121,9 @@ unicode_format_getnextarg(struct unicode_formatter_t *ctx)
|
|||
|
||||
Return 0 on success, raise an exception and return -1 on error. */
|
||||
static int
|
||||
formatfloat(PyObject *v, struct unicode_format_arg_t *arg,
|
||||
formatfloat(PyObject *v,
|
||||
struct unicode_formatter_t *ctx,
|
||||
struct unicode_format_arg_t *arg,
|
||||
PyObject **p_output,
|
||||
_PyUnicodeWriter *writer)
|
||||
{
|
||||
|
|
@ -111,8 +134,14 @@ formatfloat(PyObject *v, struct unicode_format_arg_t *arg,
|
|||
int dtoa_flags = 0;
|
||||
|
||||
x = PyFloat_AsDouble(v);
|
||||
if (x == -1.0 && PyErr_Occurred())
|
||||
if (x == -1.0 && PyErr_Occurred()) {
|
||||
if (PyErr_ExceptionMatches(PyExc_TypeError)) {
|
||||
FORMAT_ERROR(PyExc_TypeError,
|
||||
"%%%c requires a real number, not %T",
|
||||
arg->ch, v);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
prec = arg->prec;
|
||||
if (prec < 0)
|
||||
|
|
@ -287,6 +316,7 @@ _PyUnicode_FormatLong(PyObject *val, int alt, int prec, int type)
|
|||
* -1 and raise an exception on error */
|
||||
static int
|
||||
mainformatlong(PyObject *v,
|
||||
struct unicode_formatter_t *ctx,
|
||||
struct unicode_format_arg_t *arg,
|
||||
PyObject **p_output,
|
||||
_PyUnicodeWriter *writer)
|
||||
|
|
@ -364,16 +394,14 @@ mainformatlong(PyObject *v,
|
|||
case 'o':
|
||||
case 'x':
|
||||
case 'X':
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%%%c format: an integer is required, "
|
||||
"not %.200s",
|
||||
type, Py_TYPE(v)->tp_name);
|
||||
FORMAT_ERROR(PyExc_TypeError,
|
||||
"%%%c requires an integer, not %T",
|
||||
arg->ch, v);
|
||||
break;
|
||||
default:
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%%%c format: a real number is required, "
|
||||
"not %.200s",
|
||||
type, Py_TYPE(v)->tp_name);
|
||||
FORMAT_ERROR(PyExc_TypeError,
|
||||
"%%%c requires a real number, not %T",
|
||||
arg->ch, v);
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
|
|
@ -381,15 +409,17 @@ mainformatlong(PyObject *v,
|
|||
|
||||
|
||||
static Py_UCS4
|
||||
formatchar(PyObject *v)
|
||||
formatchar(PyObject *v,
|
||||
struct unicode_formatter_t *ctx,
|
||||
struct unicode_format_arg_t *arg)
|
||||
{
|
||||
/* presume that the buffer is at least 3 characters long */
|
||||
if (PyUnicode_Check(v)) {
|
||||
if (PyUnicode_GET_LENGTH(v) == 1) {
|
||||
return PyUnicode_READ_CHAR(v, 0);
|
||||
}
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%%c requires an int or a unicode character, "
|
||||
FORMAT_ERROR(PyExc_TypeError,
|
||||
"%%c requires an integer or a unicode character, "
|
||||
"not a string of length %zd",
|
||||
PyUnicode_GET_LENGTH(v));
|
||||
return (Py_UCS4) -1;
|
||||
|
|
@ -399,18 +429,18 @@ formatchar(PyObject *v)
|
|||
long x = PyLong_AsLongAndOverflow(v, &overflow);
|
||||
if (x == -1 && PyErr_Occurred()) {
|
||||
if (PyErr_ExceptionMatches(PyExc_TypeError)) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%%c requires an int or a unicode character, not %T",
|
||||
FORMAT_ERROR(PyExc_TypeError,
|
||||
"%%c requires an integer or a unicode character, "
|
||||
"not %T",
|
||||
v);
|
||||
return (Py_UCS4) -1;
|
||||
}
|
||||
return (Py_UCS4) -1;
|
||||
}
|
||||
|
||||
if (x < 0 || x > MAX_UNICODE) {
|
||||
/* this includes an overflow in converting to C long */
|
||||
PyErr_SetString(PyExc_OverflowError,
|
||||
"%c arg not in range(0x110000)");
|
||||
FORMAT_ERROR(PyExc_OverflowError,
|
||||
"%%c argument not in range(0x110000)%s", "");
|
||||
return (Py_UCS4) -1;
|
||||
}
|
||||
|
||||
|
|
@ -438,12 +468,12 @@ unicode_format_arg_parse(struct unicode_formatter_t *ctx,
|
|||
/* Get argument value from a dictionary. Example: "%(name)s". */
|
||||
Py_ssize_t keystart;
|
||||
Py_ssize_t keylen;
|
||||
PyObject *key;
|
||||
int pcount = 1;
|
||||
|
||||
if (ctx->dict == NULL) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"format requires a mapping");
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"format requires a mapping, not %T",
|
||||
ctx->args);
|
||||
return -1;
|
||||
}
|
||||
++ctx->fmtpos;
|
||||
|
|
@ -460,25 +490,34 @@ unicode_format_arg_parse(struct unicode_formatter_t *ctx,
|
|||
}
|
||||
keylen = ctx->fmtpos - keystart - 1;
|
||||
if (ctx->fmtcnt < 0 || pcount > 0) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"incomplete format key");
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"stray %% or incomplete format key at position %zd",
|
||||
arg->fmtstart);
|
||||
return -1;
|
||||
}
|
||||
key = PyUnicode_Substring(ctx->fmtstr,
|
||||
keystart, keystart + keylen);
|
||||
if (key == NULL)
|
||||
arg->key = PyUnicode_Substring(ctx->fmtstr,
|
||||
keystart, keystart + keylen);
|
||||
if (arg->key == NULL)
|
||||
return -1;
|
||||
if (ctx->args_owned) {
|
||||
ctx->args_owned = 0;
|
||||
Py_DECREF(ctx->args);
|
||||
}
|
||||
ctx->args = PyObject_GetItem(ctx->dict, key);
|
||||
Py_DECREF(key);
|
||||
ctx->args = PyObject_GetItem(ctx->dict, arg->key);
|
||||
if (ctx->args == NULL)
|
||||
return -1;
|
||||
ctx->args_owned = 1;
|
||||
ctx->arglen = -1;
|
||||
ctx->argidx = -2;
|
||||
ctx->arglen = -3;
|
||||
ctx->argidx = -4;
|
||||
}
|
||||
else {
|
||||
if (ctx->arglen < -1) {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"format requires a parenthesised mapping key "
|
||||
"at position %zd",
|
||||
arg->fmtstart);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Parse flags. Example: "%+i" => flags=F_SIGN. */
|
||||
|
|
@ -497,17 +536,28 @@ unicode_format_arg_parse(struct unicode_formatter_t *ctx,
|
|||
|
||||
/* Parse width. Example: "%10s" => width=10 */
|
||||
if (arg->ch == '*') {
|
||||
v = unicode_format_getnextarg(ctx);
|
||||
if (ctx->arglen < -1) {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"* cannot be used with a parenthesised mapping key "
|
||||
"at position %zd",
|
||||
arg->fmtstart);
|
||||
return -1;
|
||||
}
|
||||
v = unicode_format_getnextarg(ctx, 0);
|
||||
if (v == NULL)
|
||||
return -1;
|
||||
if (!PyLong_Check(v)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"* wants int");
|
||||
FORMAT_ERROR(PyExc_TypeError, "* requires int, not %T", v);
|
||||
return -1;
|
||||
}
|
||||
arg->width = PyLong_AsSsize_t(v);
|
||||
if (arg->width == -1 && PyErr_Occurred())
|
||||
if (arg->width == -1 && PyErr_Occurred()) {
|
||||
if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
|
||||
FORMAT_ERROR(PyExc_OverflowError,
|
||||
"too big for width%s", "");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
if (arg->width < 0) {
|
||||
arg->flags |= F_LJUST;
|
||||
arg->width = -arg->width;
|
||||
|
|
@ -528,8 +578,9 @@ unicode_format_arg_parse(struct unicode_formatter_t *ctx,
|
|||
mixing signed and unsigned comparison. Since arg->ch is between
|
||||
'0' and '9', casting to int is safe. */
|
||||
if (arg->width > (PY_SSIZE_T_MAX - ((int)arg->ch - '0')) / 10) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"width too big");
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"width too big at position %zd",
|
||||
arg->fmtstart);
|
||||
return -1;
|
||||
}
|
||||
arg->width = arg->width*10 + (arg->ch - '0');
|
||||
|
|
@ -544,17 +595,28 @@ unicode_format_arg_parse(struct unicode_formatter_t *ctx,
|
|||
ctx->fmtpos++;
|
||||
}
|
||||
if (arg->ch == '*') {
|
||||
v = unicode_format_getnextarg(ctx);
|
||||
if (ctx->arglen < -1) {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"* cannot be used with a parenthesised mapping key "
|
||||
"at position %zd",
|
||||
arg->fmtstart);
|
||||
return -1;
|
||||
}
|
||||
v = unicode_format_getnextarg(ctx, 0);
|
||||
if (v == NULL)
|
||||
return -1;
|
||||
if (!PyLong_Check(v)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"* wants int");
|
||||
FORMAT_ERROR(PyExc_TypeError, "* requires int, not %T", v);
|
||||
return -1;
|
||||
}
|
||||
arg->prec = PyLong_AsInt(v);
|
||||
if (arg->prec == -1 && PyErr_Occurred())
|
||||
if (arg->prec == -1 && PyErr_Occurred()) {
|
||||
if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
|
||||
FORMAT_ERROR(PyExc_OverflowError,
|
||||
"too big for precision%s", "");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
if (arg->prec < 0)
|
||||
arg->prec = 0;
|
||||
if (--ctx->fmtcnt >= 0) {
|
||||
|
|
@ -570,8 +632,9 @@ unicode_format_arg_parse(struct unicode_formatter_t *ctx,
|
|||
if (arg->ch < '0' || arg->ch > '9')
|
||||
break;
|
||||
if (arg->prec > (INT_MAX - ((int)arg->ch - '0')) / 10) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"precision too big");
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"precision too big at position %zd",
|
||||
arg->fmtstart);
|
||||
return -1;
|
||||
}
|
||||
arg->prec = arg->prec*10 + (arg->ch - '0');
|
||||
|
|
@ -589,8 +652,8 @@ unicode_format_arg_parse(struct unicode_formatter_t *ctx,
|
|||
}
|
||||
}
|
||||
if (ctx->fmtcnt < 0) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"incomplete format");
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"stray %% at position %zd", arg->fmtstart);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
|
|
@ -624,7 +687,7 @@ unicode_format_arg_format(struct unicode_formatter_t *ctx,
|
|||
if (ctx->fmtcnt == 0)
|
||||
ctx->writer.overallocate = 0;
|
||||
|
||||
v = unicode_format_getnextarg(ctx);
|
||||
v = unicode_format_getnextarg(ctx, 1);
|
||||
if (v == NULL)
|
||||
return -1;
|
||||
|
||||
|
|
@ -660,7 +723,7 @@ unicode_format_arg_format(struct unicode_formatter_t *ctx,
|
|||
case 'x':
|
||||
case 'X':
|
||||
{
|
||||
int ret = mainformatlong(v, arg, p_str, writer);
|
||||
int ret = mainformatlong(v, ctx, arg, p_str, writer);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
arg->sign = 1;
|
||||
|
|
@ -677,19 +740,19 @@ unicode_format_arg_format(struct unicode_formatter_t *ctx,
|
|||
&& !(arg->flags & (F_SIGN | F_BLANK)))
|
||||
{
|
||||
/* Fast path */
|
||||
if (formatfloat(v, arg, NULL, writer) == -1)
|
||||
if (formatfloat(v, ctx, arg, NULL, writer) == -1)
|
||||
return -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
arg->sign = 1;
|
||||
if (formatfloat(v, arg, p_str, NULL) == -1)
|
||||
if (formatfloat(v, ctx, arg, p_str, NULL) == -1)
|
||||
return -1;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
{
|
||||
Py_UCS4 ch = formatchar(v);
|
||||
Py_UCS4 ch = formatchar(v, ctx, arg);
|
||||
if (ch == (Py_UCS4) -1)
|
||||
return -1;
|
||||
if (arg->width == -1 && arg->prec == -1) {
|
||||
|
|
@ -703,12 +766,38 @@ unicode_format_arg_format(struct unicode_formatter_t *ctx,
|
|||
}
|
||||
|
||||
default:
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"unsupported format character '%c' (0x%x) "
|
||||
"at index %zd",
|
||||
(31<=arg->ch && arg->ch<=126) ? (char)arg->ch : '?',
|
||||
(int)arg->ch,
|
||||
ctx->fmtpos - 1);
|
||||
if (arg->ch < 128 && Py_ISALPHA(arg->ch)) {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"unsupported format %%%c at position %zd",
|
||||
(int)arg->ch, arg->fmtstart);
|
||||
}
|
||||
else if (arg->ch == '\'') {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"stray %% at position %zd or unexpected "
|
||||
"format character \"'\" at position %zd",
|
||||
arg->fmtstart,
|
||||
ctx->fmtpos - 1);
|
||||
}
|
||||
else if (arg->ch >= 32 && arg->ch < 127) {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"stray %% at position %zd or unexpected "
|
||||
"format character '%c' at position %zd",
|
||||
arg->fmtstart,
|
||||
(int)arg->ch, ctx->fmtpos - 1);
|
||||
}
|
||||
else if (Py_UNICODE_ISPRINTABLE(arg->ch)) {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"stray %% at position %zd or unexpected "
|
||||
"format character '%c' (U+%04X) at position %zd",
|
||||
arg->fmtstart,
|
||||
(int)arg->ch, (int)arg->ch, ctx->fmtpos - 1);
|
||||
}
|
||||
else {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"stray %% at position %zd or unexpected "
|
||||
"format character U+%04X at position %zd",
|
||||
arg->fmtstart, (int)arg->ch, ctx->fmtpos - 1);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
if (*p_str == NULL)
|
||||
|
|
@ -892,29 +981,40 @@ unicode_format_arg(struct unicode_formatter_t *ctx)
|
|||
arg.width = -1;
|
||||
arg.prec = -1;
|
||||
arg.sign = 0;
|
||||
arg.fmtstart = ctx->fmtpos - 1;
|
||||
arg.key = NULL;
|
||||
str = NULL;
|
||||
|
||||
ret = unicode_format_arg_parse(ctx, &arg);
|
||||
if (ret == -1)
|
||||
return -1;
|
||||
if (ret == -1) {
|
||||
goto onError;
|
||||
}
|
||||
|
||||
ret = unicode_format_arg_format(ctx, &arg, &str);
|
||||
if (ret == -1)
|
||||
return -1;
|
||||
if (ret == -1) {
|
||||
goto onError;
|
||||
}
|
||||
|
||||
if (ret != 1) {
|
||||
ret = unicode_format_arg_output(ctx, &arg, str);
|
||||
Py_DECREF(str);
|
||||
if (ret == -1)
|
||||
return -1;
|
||||
if (ret == -1) {
|
||||
goto onError;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx->dict && (ctx->argidx < ctx->arglen)) {
|
||||
// XXX: Never happens?
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"not all arguments converted during string formatting");
|
||||
return -1;
|
||||
goto onError;
|
||||
}
|
||||
Py_XDECREF(arg.key);
|
||||
return 0;
|
||||
|
||||
onError:
|
||||
Py_XDECREF(arg.key);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -983,8 +1083,11 @@ PyUnicode_Format(PyObject *format, PyObject *args)
|
|||
}
|
||||
|
||||
if (ctx.argidx < ctx.arglen && !ctx.dict) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"not all arguments converted during string formatting");
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"not all arguments converted during string formatting "
|
||||
"(required %zd, got %zd)",
|
||||
ctx.arglen < 0 ? 0 : ctx.argidx,
|
||||
ctx.arglen < 0 ? 1 : ctx.arglen);
|
||||
goto onError;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue