Skip to content

Commit f84e1bd

Browse files
[3.13] gh-139640: Fix swallowing syntax warnings in different modules (GH-139755)
Revert GH-131993. Fix swallowing some syntax warnings in different modules if they accidentally have the same message and are emitted from the same line. (cherry picked from commit 279db6b) Co-authored-by: Serhiy Storchaka <[email protected]>
1 parent c5ec267 commit f84e1bd

File tree

5 files changed

+62
-48
lines changed

5 files changed

+62
-48
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/test/test_compile.py

Lines changed: 48 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1528,22 +1528,21 @@ async def name_4():
15281528
[[]]
15291529

15301530
def test_compile_warnings(self):
1531-
# See gh-131927
1532-
# Compile warnings originating from the same file and
1533-
# line are now only emitted once.
1531+
# Each invocation of compile() emits compiler warnings, even if they
1532+
# have the same message and line number.
1533+
source = textwrap.dedent(r"""
1534+
# tokenizer
1535+
1or 0 # line 3
1536+
# code generator
1537+
1 is 1 # line 5
1538+
""")
15341539
with warnings.catch_warnings(record=True) as caught:
15351540
warnings.simplefilter("default")
1536-
compile('1 is 1', '<stdin>', 'eval')
1537-
compile('1 is 1', '<stdin>', 'eval')
1538-
1539-
self.assertEqual(len(caught), 1)
1541+
for i in range(2):
1542+
# Even if compile() is at the same line.
1543+
compile(source, '<stdin>', 'exec')
15401544

1541-
with warnings.catch_warnings(record=True) as caught:
1542-
warnings.simplefilter("always")
1543-
compile('1 is 1', '<stdin>', 'eval')
1544-
compile('1 is 1', '<stdin>', 'eval')
1545-
1546-
self.assertEqual(len(caught), 2)
1545+
self.assertEqual([wm.lineno for wm in caught], [3, 5] * 2)
15471546

15481547
def test_compile_warning_in_finally(self):
15491548
# Ensure that warnings inside finally blocks are
@@ -1554,16 +1553,47 @@ def test_compile_warning_in_finally(self):
15541553
try:
15551554
pass
15561555
finally:
1557-
1 is 1
1556+
1 is 1 # line 5
1557+
try:
1558+
pass
1559+
finally: # nested
1560+
1 is 1 # line 9
15581561
""")
15591562

15601563
with warnings.catch_warnings(record=True) as caught:
1561-
warnings.simplefilter("default")
1564+
warnings.simplefilter("always")
15621565
compile(source, '<stdin>', 'exec')
15631566

1564-
self.assertEqual(len(caught), 1)
1565-
self.assertEqual(caught[0].category, SyntaxWarning)
1566-
self.assertIn("\"is\" with 'int' literal", str(caught[0].message))
1567+
self.assertEqual(sorted(wm.lineno for wm in caught), [5, 9])
1568+
for wm in caught:
1569+
self.assertEqual(wm.category, SyntaxWarning)
1570+
self.assertIn("\"is\" with 'int' literal", str(wm.message))
1571+
1572+
# Other code path is used for "try" with "except*".
1573+
source = textwrap.dedent("""
1574+
try:
1575+
pass
1576+
except *Exception:
1577+
pass
1578+
finally:
1579+
1 is 1 # line 7
1580+
try:
1581+
pass
1582+
except *Exception:
1583+
pass
1584+
finally: # nested
1585+
1 is 1 # line 13
1586+
""")
1587+
1588+
with warnings.catch_warnings(record=True) as caught:
1589+
warnings.simplefilter("always")
1590+
compile(source, '<stdin>', 'exec')
1591+
1592+
self.assertEqual(sorted(wm.lineno for wm in caught), [7, 13])
1593+
for wm in caught:
1594+
self.assertEqual(wm.category, SyntaxWarning)
1595+
self.assertIn("\"is\" with 'int' literal", str(wm.message))
1596+
15671597

15681598
@requires_debug_ranges()
15691599
class TestSourcePositions(unittest.TestCase):
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
@@ -1317,28 +1317,6 @@ PyErr_WarnExplicitObject(PyObject *category, PyObject *message,
13171317
return 0;
13181318
}
13191319

1320-
/* Like PyErr_WarnExplicitObject, but automatically sets up context */
1321-
int
1322-
_PyErr_WarnExplicitObjectWithContext(PyObject *category, PyObject *message,
1323-
PyObject *filename, int lineno)
1324-
{
1325-
PyObject *unused_filename, *module, *registry;
1326-
int unused_lineno;
1327-
int stack_level = 1;
1328-
1329-
if (!setup_context(stack_level, NULL, &unused_filename, &unused_lineno,
1330-
&module, &registry)) {
1331-
return -1;
1332-
}
1333-
1334-
int rc = PyErr_WarnExplicitObject(category, message, filename, lineno,
1335-
module, registry);
1336-
Py_DECREF(unused_filename);
1337-
Py_DECREF(registry);
1338-
Py_DECREF(module);
1339-
return rc;
1340-
}
1341-
13421320
int
13431321
PyErr_WarnExplicit(PyObject *category, const char *text,
13441322
const char *filename_str, int lineno,

Python/compile.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,7 @@ struct compiler {
291291
bool c_save_nested_seqs; /* if true, construct recursive instruction sequences
292292
* (including instructions for nested code objects)
293293
*/
294+
int c_disable_warning;
294295
};
295296

296297
#define INSTR_SEQUENCE(C) ((C)->u->u_instr_sequence)
@@ -1437,6 +1438,9 @@ compiler_push_fblock(struct compiler *c, location loc,
14371438
f->fb_loc = loc;
14381439
f->fb_exit = exit;
14391440
f->fb_datum = datum;
1441+
if (t == FINALLY_END) {
1442+
c->c_disable_warning++;
1443+
}
14401444
return SUCCESS;
14411445
}
14421446

@@ -1448,6 +1452,9 @@ compiler_pop_fblock(struct compiler *c, enum fblocktype t, jump_target_label blo
14481452
u->u_nfblocks--;
14491453
assert(u->u_fblock[u->u_nfblocks].fb_type == t);
14501454
assert(SAME_LABEL(u->u_fblock[u->u_nfblocks].fb_block, block_label));
1455+
if (t == FINALLY_END) {
1456+
c->c_disable_warning--;
1457+
}
14511458
}
14521459

14531460
static int
@@ -6609,15 +6616,18 @@ static int
66096616
compiler_warn(struct compiler *c, location loc,
66106617
const char *format, ...)
66116618
{
6619+
if (c->c_disable_warning) {
6620+
return SUCCESS;
6621+
}
66126622
va_list vargs;
66136623
va_start(vargs, format);
66146624
PyObject *msg = PyUnicode_FromFormatV(format, vargs);
66156625
va_end(vargs);
66166626
if (msg == NULL) {
66176627
return ERROR;
66186628
}
6619-
if (_PyErr_WarnExplicitObjectWithContext(PyExc_SyntaxWarning, msg,
6620-
c->c_filename, loc.lineno) < 0)
6629+
if (PyErr_WarnExplicitObject(PyExc_SyntaxWarning, msg,
6630+
c->c_filename, loc.lineno, NULL, NULL) < 0)
66216631
{
66226632
if (PyErr_ExceptionMatches(PyExc_SyntaxWarning)) {
66236633
/* Replace the SyntaxWarning exception with a SyntaxError

0 commit comments

Comments
 (0)