Skip to content

Commit e149448

Browse files
committed
Merge branch '3.12' of https://github.com/python/cpython into 3.12
2 parents e904c35 + 164fa93 commit e149448

File tree

6 files changed

+38
-13
lines changed

6 files changed

+38
-13
lines changed

Lib/test/test_fstring.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import types
1414
import decimal
1515
import unittest
16+
import warnings
1617
from test import support
1718
from test.support.os_helper import temp_cwd
1819
from test.support.script_helper import assert_python_failure, assert_python_ok
@@ -772,7 +773,7 @@ def __format__(self, format_spec):
772773
self.assertEqual(f'{CustomFormat():\n}', '\n')
773774
self.assertEqual(f'{CustomFormat():\u2603}', '☃')
774775
with self.assertWarns(SyntaxWarning):
775-
exec('f"{F():¯\_(ツ)_/¯}"', {'F': CustomFormat})
776+
exec(r'f"{F():¯\_(ツ)_/¯}"', {'F': CustomFormat})
776777

777778
def test_side_effect_order(self):
778779
class X:
@@ -904,7 +905,7 @@ def test_backslashes_in_string_part(self):
904905
self.assertEqual(f'2\x203', '2 3')
905906
self.assertEqual(f'\x203', ' 3')
906907

907-
with self.assertWarns(DeprecationWarning): # invalid escape sequence
908+
with self.assertWarns(SyntaxWarning): # invalid escape sequence
908909
value = eval(r"f'\{6*7}'")
909910
self.assertEqual(value, '\\42')
910911
with self.assertWarns(SyntaxWarning): # invalid escape sequence
@@ -1037,7 +1038,7 @@ def test_fstring_backslash_before_double_bracket(self):
10371038
]
10381039
for case, expected_result in deprecated_cases:
10391040
with self.subTest(case=case, expected_result=expected_result):
1040-
with self.assertWarns(DeprecationWarning):
1041+
with self.assertWarns(SyntaxWarning):
10411042
result = eval(case)
10421043
self.assertEqual(result, expected_result)
10431044
self.assertEqual(fr'\{{\}}', '\\{\\}')
@@ -1046,6 +1047,12 @@ def test_fstring_backslash_before_double_bracket(self):
10461047
self.assertEqual(fr'\}}{1+1}', '\\}2')
10471048
self.assertEqual(fr'{1+1}\}}', '2\\}')
10481049

1050+
def test_fstring_backslash_before_double_bracket_warns_once(self):
1051+
with warnings.catch_warnings(record=True) as w:
1052+
eval(r"f'\{{'")
1053+
self.assertEqual(len(w), 1)
1054+
self.assertEqual(w[0].category, SyntaxWarning)
1055+
10491056
def test_fstring_backslash_prefix_raw(self):
10501057
self.assertEqual(f'\\', '\\')
10511058
self.assertEqual(f'\\\\', '\\\\')

Lib/test/test_future.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import ast
55
import unittest
66
from test.support import import_helper
7+
from test.support.script_helper import spawn_python, kill_python
78
from textwrap import dedent
89
import os
910
import re
@@ -121,6 +122,13 @@ def test_unicode_literals_exec(self):
121122
exec("from __future__ import unicode_literals; x = ''", {}, scope)
122123
self.assertIsInstance(scope["x"], str)
123124

125+
def test_syntactical_future_repl(self):
126+
p = spawn_python('-i')
127+
p.stdin.write(b"from __future__ import barry_as_FLUFL\n")
128+
p.stdin.write(b"2 <> 3\n")
129+
out = kill_python(p)
130+
self.assertNotIn(b'SyntaxError: invalid syntax', out)
131+
124132
class AnnotationsFutureTestCase(unittest.TestCase):
125133
template = dedent(
126134
"""
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fixed bug where :gh:`99111` breaks future import ``barry_as_FLUFL`` in the Python REPL.

Parser/string_parser.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ static int
1212
warn_invalid_escape_sequence(Parser *p, const char *first_invalid_escape, Token *t)
1313
{
1414
unsigned char c = *first_invalid_escape;
15+
if ((t->type == FSTRING_MIDDLE || t->type == FSTRING_END) && (c == '{' || c == '}')) { // in this case the tokenizer has already emitted a warning,
16+
// see tokenizer.c:warn_invalid_escape_sequence
17+
return 0;
18+
}
19+
1520
int octal = ('4' <= c && c <= '7');
1621
PyObject *msg =
1722
octal
@@ -31,7 +36,7 @@ warn_invalid_escape_sequence(Parser *p, const char *first_invalid_escape, Token
3136
if (PyErr_WarnExplicitObject(category, msg, p->tok->filename,
3237
t->lineno, NULL, NULL) < 0) {
3338
if (PyErr_ExceptionMatches(category)) {
34-
/* Replace the DeprecationWarning exception with a SyntaxError
39+
/* Replace the Syntax/DeprecationWarning exception with a SyntaxError
3540
to get a more accurate error report */
3641
PyErr_Clear();
3742

Parser/tokenizer.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1559,12 +1559,12 @@ warn_invalid_escape_sequence(struct tok_state *tok, int first_invalid_escape_cha
15591559
return -1;
15601560
}
15611561

1562-
if (PyErr_WarnExplicitObject(PyExc_DeprecationWarning, msg, tok->filename,
1562+
if (PyErr_WarnExplicitObject(PyExc_SyntaxWarning, msg, tok->filename,
15631563
tok->lineno, NULL, NULL) < 0) {
15641564
Py_DECREF(msg);
15651565

1566-
if (PyErr_ExceptionMatches(PyExc_DeprecationWarning)) {
1567-
/* Replace the DeprecationWarning exception with a SyntaxError
1566+
if (PyErr_ExceptionMatches(PyExc_SyntaxWarning)) {
1567+
/* Replace the SyntaxWarning exception with a SyntaxError
15681568
to get a more accurate error report */
15691569
PyErr_Clear();
15701570
return syntaxerror(tok, "invalid escape sequence '\\%c'", (char) first_invalid_escape_char);

Python/compile.c

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -510,8 +510,10 @@ static PyCodeObject *optimize_and_assemble(struct compiler *, int addNone);
510510

511511
static int
512512
compiler_setup(struct compiler *c, mod_ty mod, PyObject *filename,
513-
PyCompilerFlags flags, int optimize, PyArena *arena)
513+
PyCompilerFlags *flags, int optimize, PyArena *arena)
514514
{
515+
PyCompilerFlags local_flags = _PyCompilerFlags_INIT;
516+
515517
c->c_const_cache = PyDict_New();
516518
if (!c->c_const_cache) {
517519
return ERROR;
@@ -527,10 +529,13 @@ compiler_setup(struct compiler *c, mod_ty mod, PyObject *filename,
527529
if (!_PyFuture_FromAST(mod, filename, &c->c_future)) {
528530
return ERROR;
529531
}
530-
int merged = c->c_future.ff_features | flags.cf_flags;
532+
if (!flags) {
533+
flags = &local_flags;
534+
}
535+
int merged = c->c_future.ff_features | flags->cf_flags;
531536
c->c_future.ff_features = merged;
532-
flags.cf_flags = merged;
533-
c->c_flags = flags;
537+
flags->cf_flags = merged;
538+
c->c_flags = *flags;
534539
c->c_optimize = (optimize == -1) ? _Py_GetConfig()->optimization_level : optimize;
535540
c->c_nestlevel = 0;
536541

@@ -555,12 +560,11 @@ static struct compiler*
555560
new_compiler(mod_ty mod, PyObject *filename, PyCompilerFlags *pflags,
556561
int optimize, PyArena *arena)
557562
{
558-
PyCompilerFlags flags = pflags ? *pflags : _PyCompilerFlags_INIT;
559563
struct compiler *c = PyMem_Calloc(1, sizeof(struct compiler));
560564
if (c == NULL) {
561565
return NULL;
562566
}
563-
if (compiler_setup(c, mod, filename, flags, optimize, arena) < 0) {
567+
if (compiler_setup(c, mod, filename, pflags, optimize, arena) < 0) {
564568
compiler_free(c);
565569
return NULL;
566570
}

0 commit comments

Comments
 (0)