]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-41084: Adjust message when an f-string expression causes a SyntaxError (GH-21084)
authorLysandros Nikolaou <lisandrosnik@gmail.com>
Fri, 26 Jun 2020 11:24:05 +0000 (14:24 +0300)
committerGitHub <noreply@github.com>
Fri, 26 Jun 2020 11:24:05 +0000 (12:24 +0100)
Prefix the error message with `fstring: `, when parsing an f-string expression throws a `SyntaxError`.

Lib/test/test_fstring.py
Misc/NEWS.d/next/Core and Builtins/2020-06-23-15-10-19.bpo-41084.pt3y7F.rst [new file with mode: 0644]
Parser/pegen.c

index 7ffe01d2d8c31e3dd7c95f3913f459a8b723ada9..0dc7dd8e254c318a557d9eb4be47b7a3bc684477 100644 (file)
@@ -524,7 +524,7 @@ non-important content
                              # This looks like a nested format spec.
                              ])
 
-        self.assertAllRaise(SyntaxError, "invalid syntax",
+        self.assertAllRaise(SyntaxError, "f-string: invalid syntax",
                             [# Invalid syntax inside a nested spec.
                              "f'{4:{/5}}'",
                              ])
@@ -598,7 +598,7 @@ non-important content
         #  are added around it. But we shouldn't go from an invalid
         #  expression to a valid one. The added parens are just
         #  supposed to allow whitespace (including newlines).
-        self.assertAllRaise(SyntaxError, 'invalid syntax',
+        self.assertAllRaise(SyntaxError, 'f-string: invalid syntax',
                             ["f'{,}'",
                              "f'{,}'",  # this is (,), which is an error
                              ])
@@ -716,7 +716,7 @@ non-important content
 
         # lambda doesn't work without parens, because the colon
         #  makes the parser think it's a format_spec
-        self.assertAllRaise(SyntaxError, 'invalid syntax',
+        self.assertAllRaise(SyntaxError, 'f-string: invalid syntax',
                             ["f'{lambda x:x}'",
                              ])
 
@@ -1194,6 +1194,10 @@ non-important content
         self.assertEqual(f'{(x:=10)}', '10')
         self.assertEqual(x, 10)
 
+    def test_invalid_syntax_error_message(self):
+        with self.assertRaisesRegex(SyntaxError, "f-string: invalid syntax"):
+            compile("f'{a $ b}'", "?", "exec")
+
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-06-23-15-10-19.bpo-41084.pt3y7F.rst b/Misc/NEWS.d/next/Core and Builtins/2020-06-23-15-10-19.bpo-41084.pt3y7F.rst
new file mode 100644 (file)
index 0000000..cd349af
--- /dev/null
@@ -0,0 +1 @@
+Prefix the error message with 'f-string: ', when parsing an f-string expression which throws a :exc:`SyntaxError`.
index 594754cee5d5380d38e3ae0a59f7b0fdd21bb206..79fcd2f5999de17ae0f8214b3c33d1c529df08c2 100644 (file)
@@ -391,6 +391,21 @@ _PyPegen_raise_error_known_location(Parser *p, PyObject *errtype,
     PyObject *tmp = NULL;
     p->error_indicator = 1;
 
+    if (p->start_rule == Py_fstring_input) {
+        const char *fstring_msg = "f-string: ";
+        Py_ssize_t len = strlen(fstring_msg) + strlen(errmsg);
+
+        char *new_errmsg = PyMem_RawMalloc(len + 1); // Lengths of both strings plus NULL character
+        if (!new_errmsg) {
+            return (void *) PyErr_NoMemory();
+        }
+
+        // Copy both strings into new buffer
+        memcpy(new_errmsg, fstring_msg, strlen(fstring_msg));
+        memcpy(new_errmsg + strlen(fstring_msg), errmsg, strlen(errmsg));
+        new_errmsg[len] = 0;
+        errmsg = new_errmsg;
+    }
     errstr = PyUnicode_FromFormatV(errmsg, va);
     if (!errstr) {
         goto error;
@@ -427,11 +442,17 @@ _PyPegen_raise_error_known_location(Parser *p, PyObject *errtype,
 
     Py_DECREF(errstr);
     Py_DECREF(value);
+    if (p->start_rule == Py_fstring_input) {
+        PyMem_RawFree((void *)errmsg);
+    }
     return NULL;
 
 error:
     Py_XDECREF(errstr);
     Py_XDECREF(error_line);
+    if (p->start_rule == Py_fstring_input) {
+        PyMem_RawFree((void *)errmsg);
+    }
     return NULL;
 }