mirror of https://github.com/python/cpython
gh-93283: Improve error message for f-string with invalid conversion character (GH-93349)
This commit is contained in:
parent
bb900712a5
commit
07df8d5b2c
|
@ -590,7 +590,9 @@ x = (
|
||||||
self.assertEqual(f'{-10:{"-"}#{1}0{"x"}}', ' -0xa')
|
self.assertEqual(f'{-10:{"-"}#{1}0{"x"}}', ' -0xa')
|
||||||
self.assertEqual(f'{10:#{3 != {4:5} and width}x}', ' 0xa')
|
self.assertEqual(f'{10:#{3 != {4:5} and width}x}', ' 0xa')
|
||||||
|
|
||||||
self.assertAllRaise(SyntaxError, "f-string: expecting '}'",
|
self.assertAllRaise(SyntaxError,
|
||||||
|
"""f-string: invalid conversion character 'r{"': """
|
||||||
|
"""expected 's', 'r', or 'a'""",
|
||||||
["""f'{"s"!r{":10"}}'""",
|
["""f'{"s"!r{":10"}}'""",
|
||||||
|
|
||||||
# This looks like a nested format spec.
|
# This looks like a nested format spec.
|
||||||
|
@ -1012,19 +1014,28 @@ x = (
|
||||||
# Not a conversion, but show that ! is allowed in a format spec.
|
# Not a conversion, but show that ! is allowed in a format spec.
|
||||||
self.assertEqual(f'{3.14:!<10.10}', '3.14!!!!!!')
|
self.assertEqual(f'{3.14:!<10.10}', '3.14!!!!!!')
|
||||||
|
|
||||||
self.assertAllRaise(SyntaxError, 'f-string: invalid conversion character',
|
self.assertAllRaise(SyntaxError, "f-string: expecting '}'",
|
||||||
["f'{3!g}'",
|
["f'{3!'",
|
||||||
"f'{3!A}'",
|
"f'{3!s'",
|
||||||
"f'{3!3}'",
|
"f'{3!g'",
|
||||||
"f'{3!G}'",
|
|
||||||
"f'{3!!}'",
|
|
||||||
"f'{3!:}'",
|
|
||||||
"f'{3! s}'", # no space before conversion char
|
|
||||||
])
|
])
|
||||||
|
|
||||||
self.assertAllRaise(SyntaxError, "f-string: expecting '}'",
|
self.assertAllRaise(SyntaxError, 'f-string: missed conversion character',
|
||||||
["f'{x!s{y}}'",
|
["f'{3!}'",
|
||||||
"f'{3!ss}'",
|
"f'{3!:'",
|
||||||
|
"f'{3!:}'",
|
||||||
|
])
|
||||||
|
|
||||||
|
for conv in 'g', 'A', '3', 'G', '!', ' s', 's ', ' s ', 'ä', 'ɐ', 'ª':
|
||||||
|
self.assertAllRaise(SyntaxError,
|
||||||
|
"f-string: invalid conversion character %r: "
|
||||||
|
"expected 's', 'r', or 'a'" % conv,
|
||||||
|
["f'{3!" + conv + "}'"])
|
||||||
|
|
||||||
|
self.assertAllRaise(SyntaxError,
|
||||||
|
"f-string: invalid conversion character 'ss': "
|
||||||
|
"expected 's', 'r', or 'a'",
|
||||||
|
["f'{3!ss}'",
|
||||||
"f'{3!ss:}'",
|
"f'{3!ss:}'",
|
||||||
"f'{3!ss:s}'",
|
"f'{3!ss:s}'",
|
||||||
])
|
])
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Improve error message for invalid syntax of conversion character in f-string
|
||||||
|
expressions.
|
|
@ -767,27 +767,43 @@ fstring_find_expr(Parser *p, const char **str, const char *end, int raw, int rec
|
||||||
/* Check for a conversion char, if present. */
|
/* Check for a conversion char, if present. */
|
||||||
if (**str == '!') {
|
if (**str == '!') {
|
||||||
*str += 1;
|
*str += 1;
|
||||||
|
const char *conv_start = *str;
|
||||||
|
while (1) {
|
||||||
if (*str >= end) {
|
if (*str >= end) {
|
||||||
goto unexpected_end_of_string;
|
goto unexpected_end_of_string;
|
||||||
}
|
}
|
||||||
|
if (**str == '}' || **str == ':') {
|
||||||
conversion = (unsigned char)**str;
|
break;
|
||||||
|
}
|
||||||
*str += 1;
|
*str += 1;
|
||||||
|
}
|
||||||
/* Validate the conversion. */
|
if (*str == conv_start) {
|
||||||
if (!(conversion == 's' || conversion == 'r' || conversion == 'a')) {
|
|
||||||
RAISE_SYNTAX_ERROR(
|
RAISE_SYNTAX_ERROR(
|
||||||
"f-string: invalid conversion character: "
|
"f-string: missed conversion character");
|
||||||
"expected 's', 'r', or 'a'");
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
conversion = (unsigned char)*conv_start;
|
||||||
|
/* Validate the conversion. */
|
||||||
|
if ((*str != conv_start + 1) ||
|
||||||
|
!(conversion == 's' || conversion == 'r' || conversion == 'a'))
|
||||||
|
{
|
||||||
|
PyObject *conv_obj = PyUnicode_FromStringAndSize(conv_start,
|
||||||
|
*str-conv_start);
|
||||||
|
if (conv_obj) {
|
||||||
|
RAISE_SYNTAX_ERROR(
|
||||||
|
"f-string: invalid conversion character %R: "
|
||||||
|
"expected 's', 'r', or 'a'",
|
||||||
|
conv_obj);
|
||||||
|
Py_DECREF(conv_obj);
|
||||||
|
}
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check for the format spec, if present. */
|
/* Check for the format spec, if present. */
|
||||||
if (*str >= end) {
|
assert(*str < end);
|
||||||
goto unexpected_end_of_string;
|
|
||||||
}
|
|
||||||
if (**str == ':') {
|
if (**str == ':') {
|
||||||
*str += 1;
|
*str += 1;
|
||||||
if (*str >= end) {
|
if (*str >= end) {
|
||||||
|
|
Loading…
Reference in New Issue