diff options
author | Thomas Wouters <thomas@python.org> | 2023-06-20 13:32:39 (GMT) |
---|---|---|
committer | Thomas Wouters <thomas@python.org> | 2023-06-20 13:32:39 (GMT) |
commit | e149448595d9099d54a4f4603e6dd3864e81b6b8 (patch) | |
tree | 3e3cc5fcff73f0ee687af04864dacaa244fcf68a | |
parent | e904c35c315a20de97b59f146da3d47402c029da (diff) | |
parent | 164fa930011c46d3261538c17f8c4ffbeedc0f7e (diff) | |
download | cpython-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.py | 13 | ||||
-rw-r--r-- | Lib/test/test_future.py | 8 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Core and Builtins/2023-06-19-11-04-01.gh-issue-105908.7oanny.rst | 1 | ||||
-rw-r--r-- | Parser/string_parser.c | 7 | ||||
-rw-r--r-- | Parser/tokenizer.c | 6 | ||||
-rw-r--r-- | Python/compile.c | 16 |
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; } |