bpo-38964: Print correct filename on a SyntaxError in an fstring (GH-20399)

When a `SyntaxError` in the expression part of a fstring is found,
the filename attribute of the `SyntaxError` is always `<fstring>`.
With this commit, it gets changed to always have the name of the file
the fstring resides in.

Co-authored-by: Pablo Galindo <Pablogsal@gmail.com>
This commit is contained in:
Lysandros Nikolaou 2020-05-26 03:32:18 +03:00 committed by GitHub
parent 2602d97a0a
commit f7b1e46156
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 16 additions and 5 deletions

View file

@ -8,9 +8,12 @@
# Unicode identifiers in tests is allowed by PEP 3131. # Unicode identifiers in tests is allowed by PEP 3131.
import ast import ast
import os
import types import types
import decimal import decimal
import unittest import unittest
from test.support import temp_cwd, use_old_parser
from test.support.script_helper import assert_python_failure
a_global = 'global variable' a_global = 'global variable'
@ -1044,6 +1047,16 @@ def test_errors(self):
r"f'{1000:j}'", r"f'{1000:j}'",
]) ])
@unittest.skipIf(use_old_parser(), "The old parser only supports <fstring> as the filename")
def test_filename_in_syntaxerror(self):
# see issue 38964
with temp_cwd() as cwd:
file_path = os.path.join(cwd, 't.py')
with open(file_path, 'w') as f:
f.write('f"{a b}"') # This generates a SyntaxError
_, _, stderr = assert_python_failure(file_path)
self.assertIn(file_path, stderr.decode('utf-8'))
def test_loop(self): def test_loop(self):
for i in range(1000): for i in range(1000):
self.assertEqual(f'i:{i}', 'i:' + str(i)) self.assertEqual(f'i:{i}', 'i:' + str(i))

View file

@ -0,0 +1 @@
When there's a :exc:`SyntaxError` in the expression part of an fstring, the filename attribute of the :exc:`SyntaxError` gets correctly set to the name of the file the fstring resides in.

View file

@ -606,11 +606,8 @@ fstring_compile_expr(Parser *p, const char *expr_start, const char *expr_end,
if (tok == NULL) { if (tok == NULL) {
return NULL; return NULL;
} }
tok->filename = PyUnicode_FromString("<fstring>"); Py_INCREF(p->tok->filename);
if (!tok->filename) { tok->filename = p->tok->filename;
PyTokenizer_Free(tok);
return NULL;
}
Parser *p2 = _PyPegen_Parser_New(tok, Py_fstring_input, p->flags, p->feature_version, Parser *p2 = _PyPegen_Parser_New(tok, Py_fstring_input, p->flags, p->feature_version,
NULL, p->arena); NULL, p->arena);