[Python-checkins] gh-104658: Fix location of unclosed quote error for multiline f-strings (#104660)

pablogsal webhook-mailer at python.org
Sat May 20 09:07:12 EDT 2023


https://github.com/python/cpython/commit/ff7f7316326a19749c5d79f9e44acdbe7d54ac4e
commit: ff7f7316326a19749c5d79f9e44acdbe7d54ac4e
branch: main
author: Pablo Galindo Salgado <Pablogsal at gmail.com>
committer: pablogsal <Pablogsal at gmail.com>
date: 2023-05-20T14:07:05+01:00
summary:

gh-104658: Fix location of unclosed quote error for multiline f-strings (#104660)

files:
M Lib/test/test_fstring.py
M Parser/tokenizer.c
M Parser/tokenizer.h

diff --git a/Lib/test/test_fstring.py b/Lib/test/test_fstring.py
index 58e2550715ce..fcb12d25ff9d 100644
--- a/Lib/test/test_fstring.py
+++ b/Lib/test/test_fstring.py
@@ -1558,7 +1558,21 @@ def test_not_closing_quotes(self):
         self.assertAllRaise(SyntaxError, "unterminated f-string literal", ['f"', "f'"])
         self.assertAllRaise(SyntaxError, "unterminated triple-quoted f-string literal",
                             ['f"""', "f'''"])
-
+        # Ensure that the errors are reported at the correct line number.
+        data = '''\
+x = 1 + 1
+y = 2 + 2
+z = f"""
+sdfjnsdfjsdf
+sdfsdfs{1+
+2} dfigdf {3+
+4}sdufsd""
+'''
+        try:
+            compile(data, "?", "exec")
+        except SyntaxError as e:
+            self.assertEqual(e.text, 'z = f"""')
+            self.assertEqual(e.lineno, 3)
     def test_syntax_error_after_debug(self):
         self.assertAllRaise(SyntaxError, "f-string: expecting a valid expression after '{'",
                             [
diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c
index 91ffabac56c7..c5dc9e706fe4 100644
--- a/Parser/tokenizer.c
+++ b/Parser/tokenizer.c
@@ -1124,7 +1124,7 @@ tok_underflow_interactive(struct tok_state *tok) {
 
 static int
 tok_underflow_file(struct tok_state *tok) {
-    if (tok->start == NULL) {
+    if (tok->start == NULL && !INSIDE_FSTRING(tok)) {
         tok->cur = tok->inp = tok->buf;
     }
     if (tok->decoding_state == STATE_INIT) {
@@ -2250,6 +2250,7 @@ tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct t
         the_current_tok->f_string_quote_size = quote_size;
         the_current_tok->f_string_start = tok->start;
         the_current_tok->f_string_multi_line_start = tok->line_start;
+        the_current_tok->f_string_line_start = tok->lineno;
         the_current_tok->f_string_start_offset = -1;
         the_current_tok->f_string_multi_line_start_offset = -1;
         the_current_tok->last_expr_buffer = NULL;
@@ -2580,7 +2581,9 @@ tok_get_fstring_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct
             tok->cur++;
             tok->line_start = current_tok->f_string_multi_line_start;
             int start = tok->lineno;
-            tok->lineno = tok->first_lineno;
+
+            tokenizer_mode *the_current_tok = TOK_GET_MODE(tok);
+            tok->lineno = the_current_tok->f_string_line_start;
 
             if (current_tok->f_string_quote_size == 3) {
                 return MAKE_TOKEN(syntaxerror(tok,
diff --git a/Parser/tokenizer.h b/Parser/tokenizer.h
index 5e2171885ac7..fd169cf3d1ba 100644
--- a/Parser/tokenizer.h
+++ b/Parser/tokenizer.h
@@ -53,6 +53,7 @@ typedef struct _tokenizer_mode {
     int f_string_raw;
     const char* f_string_start;
     const char* f_string_multi_line_start;
+    int f_string_line_start;
 
     Py_ssize_t f_string_start_offset;
     Py_ssize_t f_string_multi_line_start_offset;



More information about the Python-checkins mailing list