summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Wouters <thomas@python.org>2023-06-20 13:32:39 (GMT)
committerThomas Wouters <thomas@python.org>2023-06-20 13:32:39 (GMT)
commite149448595d9099d54a4f4603e6dd3864e81b6b8 (patch)
tree3e3cc5fcff73f0ee687af04864dacaa244fcf68a
parente904c35c315a20de97b59f146da3d47402c029da (diff)
parent164fa930011c46d3261538c17f8c4ffbeedc0f7e (diff)
downloadcpython-e149448595d9099d54a4f4603e6dd3864e81b6b8.zip
cpython-e149448595d9099d54a4f4603e6dd3864e81b6b8.tar.gz
cpython-e149448595d9099d54a4f4603e6dd3864e81b6b8.tar.bz2
Merge branch '3.12' of https://github.com/python/cpython into 3.12
-rw-r--r--Lib/test/test_fstring.py13
-rw-r--r--Lib/test/test_future.py8
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2023-06-19-11-04-01.gh-issue-105908.7oanny.rst1
-rw-r--r--Parser/string_parser.c7
-rw-r--r--Parser/tokenizer.c6
-rw-r--r--Python/compile.c16
6 files changed, 38 insertions, 13 deletions
diff --git a/Lib/test/test_fstring.py b/Lib/test/test_fstring.py
index 8f6b576..1eb3bfb 100644
--- a/Lib/test/test_fstring.py
+++ b/Lib/test/test_fstring.py
@@ -13,6 +13,7 @@ import re
import types
import decimal
import unittest
+import warnings
from test import support
from test.support.os_helper import temp_cwd
from test.support.script_helper import assert_python_failure, assert_python_ok
@@ -772,7 +773,7 @@ x = (
self.assertEqual(f'{CustomFormat():\n}', '\n')
self.assertEqual(f'{CustomFormat():\u2603}', '☃')
with self.assertWarns(SyntaxWarning):
- exec('f"{F():¯\_(ツ)_/¯}"', {'F': CustomFormat})
+ exec(r'f"{F():¯\_(ツ)_/¯}"', {'F': CustomFormat})
def test_side_effect_order(self):
class X:
@@ -904,7 +905,7 @@ x = (
self.assertEqual(f'2\x203', '2 3')
self.assertEqual(f'\x203', ' 3')
- with self.assertWarns(DeprecationWarning): # invalid escape sequence
+ with self.assertWarns(SyntaxWarning): # invalid escape sequence
value = eval(r"f'\{6*7}'")
self.assertEqual(value, '\\42')
with self.assertWarns(SyntaxWarning): # invalid escape sequence
@@ -1037,7 +1038,7 @@ x = (
]
for case, expected_result in deprecated_cases:
with self.subTest(case=case, expected_result=expected_result):
- with self.assertWarns(DeprecationWarning):
+ with self.assertWarns(SyntaxWarning):
result = eval(case)
self.assertEqual(result, expected_result)
self.assertEqual(fr'\{{\}}', '\\{\\}')
@@ -1046,6 +1047,12 @@ x = (
self.assertEqual(fr'\}}{1+1}', '\\}2')
self.assertEqual(fr'{1+1}\}}', '2\\}')
+ def test_fstring_backslash_before_double_bracket_warns_once(self):
+ with warnings.catch_warnings(record=True) as w:
+ eval(r"f'\{{'")
+ self.assertEqual(len(w), 1)
+ self.assertEqual(w[0].category, SyntaxWarning)
+
def test_fstring_backslash_prefix_raw(self):
self.assertEqual(f'\\', '\\')
self.assertEqual(f'\\\\', '\\\\')
diff --git a/Lib/test/test_future.py b/Lib/test/test_future.py
index b8b591a..4730bfa 100644
--- a/Lib/test/test_future.py
+++ b/Lib/test/test_future.py
@@ -4,6 +4,7 @@ import __future__
import ast
import unittest
from test.support import import_helper
+from test.support.script_helper import spawn_python, kill_python
from textwrap import dedent
import os
import re
@@ -121,6 +122,13 @@ class FutureTest(unittest.TestCase):
exec("from __future__ import unicode_literals; x = ''", {}, scope)
self.assertIsInstance(scope["x"], str)
+ def test_syntactical_future_repl(self):
+ p = spawn_python('-i')
+ p.stdin.write(b"from __future__ import barry_as_FLUFL\n")
+ p.stdin.write(b"2 <> 3\n")
+ out = kill_python(p)
+ self.assertNotIn(b'SyntaxError: invalid syntax', out)
+
class AnnotationsFutureTestCase(unittest.TestCase):
template = dedent(
"""
diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-19-11-04-01.gh-issue-105908.7oanny.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-19-11-04-01.gh-issue-105908.7oanny.rst
new file mode 100644
index 0000000..03db3f0
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-19-11-04-01.gh-issue-105908.7oanny.rst
@@ -0,0 +1 @@
+Fixed bug where :gh:`99111` breaks future import ``barry_as_FLUFL`` in the Python REPL.
diff --git a/Parser/string_parser.c b/Parser/string_parser.c
index d4ce338..20459e8 100644
--- a/Parser/string_parser.c
+++ b/Parser/string_parser.c
@@ -12,6 +12,11 @@ static int
warn_invalid_escape_sequence(Parser *p, const char *first_invalid_escape, Token *t)
{
unsigned char c = *first_invalid_escape;
+ if ((t->type == FSTRING_MIDDLE || t->type == FSTRING_END) && (c == '{' || c == '}')) { // in this case the tokenizer has already emitted a warning,
+ // see tokenizer.c:warn_invalid_escape_sequence
+ return 0;
+ }
+
int octal = ('4' <= c && c <= '7');
PyObject *msg =
octal
@@ -31,7 +36,7 @@ warn_invalid_escape_sequence(Parser *p, const char *first_invalid_escape, Token
if (PyErr_WarnExplicitObject(category, msg, p->tok->filename,
t->lineno, NULL, NULL) < 0) {
if (PyErr_ExceptionMatches(category)) {
- /* Replace the DeprecationWarning exception with a SyntaxError
+ /* Replace the Syntax/DeprecationWarning exception with a SyntaxError
to get a more accurate error report */
PyErr_Clear();
diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c
index 1a59f54..115b497 100644
--- a/Parser/tokenizer.c
+++ b/Parser/tokenizer.c
@@ -1559,12 +1559,12 @@ warn_invalid_escape_sequence(struct tok_state *tok, int first_invalid_escape_cha
return -1;
}
- if (PyErr_WarnExplicitObject(PyExc_DeprecationWarning, msg, tok->filename,
+ if (PyErr_WarnExplicitObject(PyExc_SyntaxWarning, msg, tok->filename,
tok->lineno, NULL, NULL) < 0) {
Py_DECREF(msg);
- if (PyErr_ExceptionMatches(PyExc_DeprecationWarning)) {
- /* Replace the DeprecationWarning exception with a SyntaxError
+ if (PyErr_ExceptionMatches(PyExc_SyntaxWarning)) {
+ /* Replace the SyntaxWarning exception with a SyntaxError
to get a more accurate error report */
PyErr_Clear();
return syntaxerror(tok, "invalid escape sequence '\\%c'", (char) first_invalid_escape_char);
diff --git a/Python/compile.c b/Python/compile.c
index f593e95..a8d0016 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -510,8 +510,10 @@ static PyCodeObject *optimize_and_assemble(struct compiler *, int addNone);
static int
compiler_setup(struct compiler *c, mod_ty mod, PyObject *filename,
- PyCompilerFlags flags, int optimize, PyArena *arena)
+ PyCompilerFlags *flags, int optimize, PyArena *arena)
{
+ PyCompilerFlags local_flags = _PyCompilerFlags_INIT;
+
c->c_const_cache = PyDict_New();
if (!c->c_const_cache) {
return ERROR;
@@ -527,10 +529,13 @@ compiler_setup(struct compiler *c, mod_ty mod, PyObject *filename,
if (!_PyFuture_FromAST(mod, filename, &c->c_future)) {
return ERROR;
}
- int merged = c->c_future.ff_features | flags.cf_flags;
+ if (!flags) {
+ flags = &local_flags;
+ }
+ int merged = c->c_future.ff_features | flags->cf_flags;
c->c_future.ff_features = merged;
- flags.cf_flags = merged;
- c->c_flags = flags;
+ flags->cf_flags = merged;
+ c->c_flags = *flags;
c->c_optimize = (optimize == -1) ? _Py_GetConfig()->optimization_level : optimize;
c->c_nestlevel = 0;
@@ -555,12 +560,11 @@ static struct compiler*
new_compiler(mod_ty mod, PyObject *filename, PyCompilerFlags *pflags,
int optimize, PyArena *arena)
{
- PyCompilerFlags flags = pflags ? *pflags : _PyCompilerFlags_INIT;
struct compiler *c = PyMem_Calloc(1, sizeof(struct compiler));
if (c == NULL) {
return NULL;
}
- if (compiler_setup(c, mod, filename, flags, optimize, arena) < 0) {
+ if (compiler_setup(c, mod, filename, pflags, optimize, arena) < 0) {
compiler_free(c);
return NULL;
}