mirror of https://github.com/python/cpython
gh-105194: Fix format specifier escaped characters in f-strings (#105231)
This commit is contained in:
parent
4bfa01b9d9
commit
41de54378d
|
@ -923,7 +923,7 @@ fstring_conversion[ResultTokenWithMetadata*]:
|
||||||
fstring_full_format_spec[ResultTokenWithMetadata*]:
|
fstring_full_format_spec[ResultTokenWithMetadata*]:
|
||||||
| colon=':' spec=fstring_format_spec* { _PyPegen_setup_full_format_spec(p, colon, (asdl_expr_seq *) spec, EXTRA) }
|
| colon=':' spec=fstring_format_spec* { _PyPegen_setup_full_format_spec(p, colon, (asdl_expr_seq *) spec, EXTRA) }
|
||||||
fstring_format_spec[expr_ty]:
|
fstring_format_spec[expr_ty]:
|
||||||
| t=FSTRING_MIDDLE { _PyPegen_constant_from_token(p, t) }
|
| t=FSTRING_MIDDLE { _PyPegen_decoded_constant_from_token(p, t) }
|
||||||
| fstring_replacement_field
|
| fstring_replacement_field
|
||||||
fstring[expr_ty]:
|
fstring[expr_ty]:
|
||||||
| a=FSTRING_START b=fstring_middle* c=FSTRING_END { _PyPegen_joined_str(p, a, (asdl_expr_seq*)b, c) }
|
| a=FSTRING_START b=fstring_middle* c=FSTRING_END { _PyPegen_joined_str(p, a, (asdl_expr_seq*)b, c) }
|
||||||
|
|
|
@ -764,6 +764,16 @@ x = (
|
||||||
"""f'{"s"!{"r"}}'""",
|
"""f'{"s"!{"r"}}'""",
|
||||||
])
|
])
|
||||||
|
|
||||||
|
def test_custom_format_specifier(self):
|
||||||
|
class CustomFormat:
|
||||||
|
def __format__(self, format_spec):
|
||||||
|
return format_spec
|
||||||
|
|
||||||
|
self.assertEqual(f'{CustomFormat():\n}', '\n')
|
||||||
|
self.assertEqual(f'{CustomFormat():\u2603}', '☃')
|
||||||
|
with self.assertWarns(SyntaxWarning):
|
||||||
|
exec('f"{F():¯\_(ツ)_/¯}"', {'F': CustomFormat})
|
||||||
|
|
||||||
def test_side_effect_order(self):
|
def test_side_effect_order(self):
|
||||||
class X:
|
class X:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Do not escape with backslashes f-string format specifiers. Patch by Pablo
|
||||||
|
Galindo
|
|
@ -1350,6 +1350,25 @@ _PyPegen_joined_str(Parser *p, Token* a, asdl_expr_seq* raw_expressions, Token*b
|
||||||
p->arena);
|
p->arena);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
expr_ty _PyPegen_decoded_constant_from_token(Parser* p, Token* tok) {
|
||||||
|
Py_ssize_t bsize;
|
||||||
|
char* bstr;
|
||||||
|
if (PyBytes_AsStringAndSize(tok->bytes, &bstr, &bsize) == -1) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
PyObject* str = _PyPegen_decode_string(p, 0, bstr, bsize, tok);
|
||||||
|
if (str == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (_PyArena_AddPyObject(p->arena, str) < 0) {
|
||||||
|
Py_DECREF(str);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return _PyAST_Constant(str, NULL, tok->lineno, tok->col_offset,
|
||||||
|
tok->end_lineno, tok->end_col_offset,
|
||||||
|
p->arena);
|
||||||
|
}
|
||||||
|
|
||||||
expr_ty _PyPegen_constant_from_token(Parser* p, Token* tok) {
|
expr_ty _PyPegen_constant_from_token(Parser* p, Token* tok) {
|
||||||
char* bstr = PyBytes_AsString(tok->bytes);
|
char* bstr = PyBytes_AsString(tok->bytes);
|
||||||
if (bstr == NULL) {
|
if (bstr == NULL) {
|
||||||
|
|
|
@ -16323,7 +16323,7 @@ fstring_format_spec_rule(Parser *p)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
D(fprintf(stderr, "%*c+ fstring_format_spec[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "FSTRING_MIDDLE"));
|
D(fprintf(stderr, "%*c+ fstring_format_spec[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "FSTRING_MIDDLE"));
|
||||||
_res = _PyPegen_constant_from_token ( p , t );
|
_res = _PyPegen_decoded_constant_from_token ( p , t );
|
||||||
if (_res == NULL && PyErr_Occurred()) {
|
if (_res == NULL && PyErr_Occurred()) {
|
||||||
p->error_indicator = 1;
|
p->error_indicator = 1;
|
||||||
p->level--;
|
p->level--;
|
||||||
|
|
|
@ -328,6 +328,7 @@ expr_ty _PyPegen_collect_call_seqs(Parser *, asdl_expr_seq *, asdl_seq *,
|
||||||
int lineno, int col_offset, int end_lineno,
|
int lineno, int col_offset, int end_lineno,
|
||||||
int end_col_offset, PyArena *arena);
|
int end_col_offset, PyArena *arena);
|
||||||
expr_ty _PyPegen_constant_from_token(Parser* p, Token* tok);
|
expr_ty _PyPegen_constant_from_token(Parser* p, Token* tok);
|
||||||
|
expr_ty _PyPegen_decoded_constant_from_token(Parser* p, Token* tok);
|
||||||
expr_ty _PyPegen_constant_from_string(Parser* p, Token* tok);
|
expr_ty _PyPegen_constant_from_string(Parser* p, Token* tok);
|
||||||
expr_ty _PyPegen_concatenate_strings(Parser *p, asdl_expr_seq *, int, int, int, int, PyArena *);
|
expr_ty _PyPegen_concatenate_strings(Parser *p, asdl_expr_seq *, int, int, int, int, PyArena *);
|
||||||
expr_ty _PyPegen_FetchRawForm(Parser *p, int, int, int, int);
|
expr_ty _PyPegen_FetchRawForm(Parser *p, int, int, int, int);
|
||||||
|
|
Loading…
Reference in New Issue