Skip to content

Commit 3990961

Browse files
pythongh-139640: Fix swallowing syntax warnings in different modules
Revert pythonGH-131993. Explicitly silence the duplicated PEP 765 syntax warnings in the REPL. Fix swallowing some syntax warnings in different modules if they accidentally have the same message and are emitted from the same line. Co-authored-by: Tomas R. <[email protected]>
1 parent 162997b commit 3990961

File tree

8 files changed

+82
-50
lines changed

8 files changed

+82
-50
lines changed

Include/cpython/warnings.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,3 @@ PyAPI_FUNC(int) PyErr_WarnExplicitFormat(
1818

1919
// DEPRECATED: Use PyErr_WarnEx() instead.
2020
#define PyErr_Warn(category, msg) PyErr_WarnEx((category), (msg), 1)
21-
22-
int _PyErr_WarnExplicitObjectWithContext(
23-
PyObject *category,
24-
PyObject *message,
25-
PyObject *filename,
26-
int lineno);

Lib/_pyrepl/console.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,8 +217,26 @@ def runsource(self, source, filename="<input>", symbol="single"):
217217
wrapper = ast.Interactive if stmt is last_stmt else ast.Module
218218
the_symbol = symbol if stmt is last_stmt else "exec"
219219
item = wrapper([stmt])
220+
import warnings
220221
try:
221-
code = self.compile.compiler(item, filename, the_symbol)
222+
with warnings.catch_warnings(record=True) as caught_warnings:
223+
# Enable all warnings
224+
warnings.simplefilter("always")
225+
code = self.compile.compiler(item, filename, the_symbol)
226+
for warning in caught_warnings:
227+
if issubclass(warning.category, SyntaxWarning) and "in a 'finally' block" in str(warning.message):
228+
# Ignore this warning as it would've alread been raised
229+
# when compiling the code above
230+
pass
231+
else:
232+
# Re-emit other warnings
233+
warnings.warn_explicit(
234+
message=warning.message,
235+
category=warning.category,
236+
filename=warning.filename,
237+
lineno=warning.lineno,
238+
source=warning.source
239+
)
222240
linecache._register_code(code, source, filename)
223241
except SyntaxError as e:
224242
if e.args[0] == "'await' outside function":

Lib/test/test_compile.py

Lines changed: 48 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1664,22 +1664,21 @@ class WeirdDict(dict):
16641664
self.assertRaises(NameError, ns['foo'])
16651665

16661666
def test_compile_warnings(self):
1667-
# See gh-131927
1668-
# Compile warnings originating from the same file and
1669-
# line are now only emitted once.
1667+
# Each invocation of compile() emits compiler warnings, even if they
1668+
# have the same message and line number.
1669+
source = textwrap.dedent(r"""
1670+
# tokenizer
1671+
1or 0 # line 3
1672+
# code generator
1673+
1 is 1 # line 5
1674+
""")
16701675
with warnings.catch_warnings(record=True) as caught:
16711676
warnings.simplefilter("default")
1672-
compile('1 is 1', '<stdin>', 'eval')
1673-
compile('1 is 1', '<stdin>', 'eval')
1674-
1675-
self.assertEqual(len(caught), 1)
1677+
for i in range(2):
1678+
# Even if compile() is at the same line.
1679+
compile(source, '<stdin>', 'exec')
16761680

1677-
with warnings.catch_warnings(record=True) as caught:
1678-
warnings.simplefilter("always")
1679-
compile('1 is 1', '<stdin>', 'eval')
1680-
compile('1 is 1', '<stdin>', 'eval')
1681-
1682-
self.assertEqual(len(caught), 2)
1681+
self.assertEqual([wm.lineno for wm in caught], [3, 5] * 2)
16831682

16841683
def test_compile_warning_in_finally(self):
16851684
# Ensure that warnings inside finally blocks are
@@ -1690,16 +1689,47 @@ def test_compile_warning_in_finally(self):
16901689
try:
16911690
pass
16921691
finally:
1693-
1 is 1
1692+
1 is 1 # line 5
1693+
try:
1694+
pass
1695+
finally: # nested
1696+
1 is 1 # line 9
16941697
""")
16951698

16961699
with warnings.catch_warnings(record=True) as caught:
1697-
warnings.simplefilter("default")
1700+
warnings.simplefilter("always")
16981701
compile(source, '<stdin>', 'exec')
16991702

1700-
self.assertEqual(len(caught), 1)
1701-
self.assertEqual(caught[0].category, SyntaxWarning)
1702-
self.assertIn("\"is\" with 'int' literal", str(caught[0].message))
1703+
self.assertEqual(sorted(wm.lineno for wm in caught), [5, 9])
1704+
for wm in caught:
1705+
self.assertEqual(wm.category, SyntaxWarning)
1706+
self.assertIn("\"is\" with 'int' literal", str(wm.message))
1707+
1708+
# Other code path is used for "try" with "except*".
1709+
source = textwrap.dedent("""
1710+
try:
1711+
pass
1712+
except *Exception:
1713+
pass
1714+
finally:
1715+
1 is 1 # line 7
1716+
try:
1717+
pass
1718+
except *Exception:
1719+
pass
1720+
finally: # nested
1721+
1 is 1 # line 13
1722+
""")
1723+
1724+
with warnings.catch_warnings(record=True) as caught:
1725+
warnings.simplefilter("always")
1726+
compile(source, '<stdin>', 'exec')
1727+
1728+
self.assertEqual(sorted(wm.lineno for wm in caught), [7, 13])
1729+
for wm in caught:
1730+
self.assertEqual(wm.category, SyntaxWarning)
1731+
self.assertIn("\"is\" with 'int' literal", str(wm.message))
1732+
17031733

17041734
class TestBooleanExpression(unittest.TestCase):
17051735
class Value:

Lib/test/test_pyrepl/test_interact.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ def f():
293293
""")
294294

295295
with warnings.catch_warnings(record=True) as caught:
296-
warnings.simplefilter("default")
296+
warnings.simplefilter("always")
297297
console.runsource(code)
298298

299299
count = sum("'return' in a 'finally' block" in str(w.message)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix swallowing some syntax warnings in different modules if they
2+
accidentally have the same message and are emitted from the same line.

Python/_warnings.c

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1473,28 +1473,6 @@ PyErr_WarnExplicitObject(PyObject *category, PyObject *message,
14731473
return 0;
14741474
}
14751475

1476-
/* Like PyErr_WarnExplicitObject, but automatically sets up context */
1477-
int
1478-
_PyErr_WarnExplicitObjectWithContext(PyObject *category, PyObject *message,
1479-
PyObject *filename, int lineno)
1480-
{
1481-
PyObject *unused_filename, *module, *registry;
1482-
int unused_lineno;
1483-
int stack_level = 1;
1484-
1485-
if (!setup_context(stack_level, NULL, &unused_filename, &unused_lineno,
1486-
&module, &registry)) {
1487-
return -1;
1488-
}
1489-
1490-
int rc = PyErr_WarnExplicitObject(category, message, filename, lineno,
1491-
module, registry);
1492-
Py_DECREF(unused_filename);
1493-
Py_DECREF(registry);
1494-
Py_DECREF(module);
1495-
return rc;
1496-
}
1497-
14981476
int
14991477
PyErr_WarnExplicit(PyObject *category, const char *text,
15001478
const char *filename_str, int lineno,

Python/compile.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ typedef struct _PyCompiler {
103103
bool c_save_nested_seqs; /* if true, construct recursive instruction sequences
104104
* (including instructions for nested code objects)
105105
*/
106+
int c_disable_warning;
106107
} compiler;
107108

108109
static int
@@ -765,6 +766,9 @@ _PyCompile_PushFBlock(compiler *c, location loc,
765766
f->fb_loc = loc;
766767
f->fb_exit = exit;
767768
f->fb_datum = datum;
769+
if (t == COMPILE_FBLOCK_FINALLY_END) {
770+
c->c_disable_warning++;
771+
}
768772
return SUCCESS;
769773
}
770774

@@ -776,6 +780,9 @@ _PyCompile_PopFBlock(compiler *c, fblocktype t, jump_target_label block_label)
776780
u->u_nfblocks--;
777781
assert(u->u_fblock[u->u_nfblocks].fb_type == t);
778782
assert(SAME_JUMP_TARGET_LABEL(u->u_fblock[u->u_nfblocks].fb_block, block_label));
783+
if (t == COMPILE_FBLOCK_FINALLY_END) {
784+
c->c_disable_warning--;
785+
}
779786
}
780787

781788
fblockinfo *
@@ -1203,6 +1210,9 @@ _PyCompile_Error(compiler *c, location loc, const char *format, ...)
12031210
int
12041211
_PyCompile_Warn(compiler *c, location loc, const char *format, ...)
12051212
{
1213+
if (c->c_disable_warning) {
1214+
return 0;
1215+
}
12061216
va_list vargs;
12071217
va_start(vargs, format);
12081218
PyObject *msg = PyUnicode_FromFormatV(format, vargs);

Python/errors.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1962,8 +1962,8 @@ int
19621962
_PyErr_EmitSyntaxWarning(PyObject *msg, PyObject *filename, int lineno, int col_offset,
19631963
int end_lineno, int end_col_offset)
19641964
{
1965-
if (_PyErr_WarnExplicitObjectWithContext(PyExc_SyntaxWarning, msg,
1966-
filename, lineno) < 0)
1965+
if (PyErr_WarnExplicitObject(PyExc_SyntaxWarning, msg,
1966+
filename, lineno, NULL, NULL) < 0)
19671967
{
19681968
if (PyErr_ExceptionMatches(PyExc_SyntaxWarning)) {
19691969
/* Replace the SyntaxWarning exception with a SyntaxError

0 commit comments

Comments
 (0)