From 92f7965cf6f36dd9218512172f8d48cccd71ccfa Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 14 Oct 2025 18:46:11 +0300 Subject: [PATCH] [3.13] gh-139640: Fix swallowing syntax warnings in different modules (GH-139755) (GH-140119) 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. Fix duplicated warnings in the "finally" block. (cherry picked from commit 279db6bede30be3a1b86803585eb4404d27800da) --- Include/cpython/warnings.h | 6 -- Lib/test/test_compile.py | 66 ++++++++++++++----- ...-10-06-10-03-37.gh-issue-139640.gY5oTb.rst | 3 + Python/_warnings.c | 22 ------- Python/compile.c | 14 +++- 5 files changed, 63 insertions(+), 48 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2025-10-06-10-03-37.gh-issue-139640.gY5oTb.rst diff --git a/Include/cpython/warnings.h b/Include/cpython/warnings.h index 8731fd2e96b7..4e3eb88e8ff4 100644 --- a/Include/cpython/warnings.h +++ b/Include/cpython/warnings.h @@ -18,9 +18,3 @@ PyAPI_FUNC(int) PyErr_WarnExplicitFormat( // DEPRECATED: Use PyErr_WarnEx() instead. #define PyErr_Warn(category, msg) PyErr_WarnEx((category), (msg), 1) - -int _PyErr_WarnExplicitObjectWithContext( - PyObject *category, - PyObject *message, - PyObject *filename, - int lineno); diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index eda2c0c40494..06b5fd5bbc83 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -1528,22 +1528,21 @@ class TestSpecifics(unittest.TestCase): [[]] def test_compile_warnings(self): - # See gh-131927 - # Compile warnings originating from the same file and - # line are now only emitted once. + # Each invocation of compile() emits compiler warnings, even if they + # have the same message and line number. + source = textwrap.dedent(r""" + # tokenizer + 1or 0 # line 3 + # code generator + 1 is 1 # line 5 + """) with warnings.catch_warnings(record=True) as caught: warnings.simplefilter("default") - compile('1 is 1', '', 'eval') - compile('1 is 1', '', 'eval') - - self.assertEqual(len(caught), 1) + for i in range(2): + # Even if compile() is at the same line. + compile(source, '', 'exec') - with warnings.catch_warnings(record=True) as caught: - warnings.simplefilter("always") - compile('1 is 1', '', 'eval') - compile('1 is 1', '', 'eval') - - self.assertEqual(len(caught), 2) + self.assertEqual([wm.lineno for wm in caught], [3, 5] * 2) def test_compile_warning_in_finally(self): # Ensure that warnings inside finally blocks are @@ -1554,16 +1553,47 @@ class TestSpecifics(unittest.TestCase): try: pass finally: - 1 is 1 + 1 is 1 # line 5 + try: + pass + finally: # nested + 1 is 1 # line 9 """) with warnings.catch_warnings(record=True) as caught: - warnings.simplefilter("default") + warnings.simplefilter("always") compile(source, '', 'exec') - self.assertEqual(len(caught), 1) - self.assertEqual(caught[0].category, SyntaxWarning) - self.assertIn("\"is\" with 'int' literal", str(caught[0].message)) + self.assertEqual(sorted(wm.lineno for wm in caught), [5, 9]) + for wm in caught: + self.assertEqual(wm.category, SyntaxWarning) + self.assertIn("\"is\" with 'int' literal", str(wm.message)) + + # Other code path is used for "try" with "except*". + source = textwrap.dedent(""" + try: + pass + except *Exception: + pass + finally: + 1 is 1 # line 7 + try: + pass + except *Exception: + pass + finally: # nested + 1 is 1 # line 13 + """) + + with warnings.catch_warnings(record=True) as caught: + warnings.simplefilter("always") + compile(source, '', 'exec') + + self.assertEqual(sorted(wm.lineno for wm in caught), [7, 13]) + for wm in caught: + self.assertEqual(wm.category, SyntaxWarning) + self.assertIn("\"is\" with 'int' literal", str(wm.message)) + @requires_debug_ranges() class TestSourcePositions(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Core and Builtins/2025-10-06-10-03-37.gh-issue-139640.gY5oTb.rst b/Misc/NEWS.d/next/Core and Builtins/2025-10-06-10-03-37.gh-issue-139640.gY5oTb.rst new file mode 100644 index 000000000000..396e40f0e136 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2025-10-06-10-03-37.gh-issue-139640.gY5oTb.rst @@ -0,0 +1,3 @@ +Fix swallowing some syntax warnings in different modules if they +accidentally have the same message and are emitted from the same line. +Fix duplicated warnings in the ``finally`` block. diff --git a/Python/_warnings.c b/Python/_warnings.c index 5bbd4a9c19f6..4bb83b214ae6 100644 --- a/Python/_warnings.c +++ b/Python/_warnings.c @@ -1317,28 +1317,6 @@ PyErr_WarnExplicitObject(PyObject *category, PyObject *message, return 0; } -/* Like PyErr_WarnExplicitObject, but automatically sets up context */ -int -_PyErr_WarnExplicitObjectWithContext(PyObject *category, PyObject *message, - PyObject *filename, int lineno) -{ - PyObject *unused_filename, *module, *registry; - int unused_lineno; - int stack_level = 1; - - if (!setup_context(stack_level, NULL, &unused_filename, &unused_lineno, - &module, ®istry)) { - return -1; - } - - int rc = PyErr_WarnExplicitObject(category, message, filename, lineno, - module, registry); - Py_DECREF(unused_filename); - Py_DECREF(registry); - Py_DECREF(module); - return rc; -} - int PyErr_WarnExplicit(PyObject *category, const char *text, const char *filename_str, int lineno, diff --git a/Python/compile.c b/Python/compile.c index bb2c2293a38c..8f8b6773440d 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -291,6 +291,7 @@ struct compiler { bool c_save_nested_seqs; /* if true, construct recursive instruction sequences * (including instructions for nested code objects) */ + int c_disable_warning; }; #define INSTR_SEQUENCE(C) ((C)->u->u_instr_sequence) @@ -1437,6 +1438,9 @@ compiler_push_fblock(struct compiler *c, location loc, f->fb_loc = loc; f->fb_exit = exit; f->fb_datum = datum; + if (t == FINALLY_END) { + c->c_disable_warning++; + } return SUCCESS; } @@ -1448,6 +1452,9 @@ compiler_pop_fblock(struct compiler *c, enum fblocktype t, jump_target_label blo u->u_nfblocks--; assert(u->u_fblock[u->u_nfblocks].fb_type == t); assert(SAME_LABEL(u->u_fblock[u->u_nfblocks].fb_block, block_label)); + if (t == FINALLY_END) { + c->c_disable_warning--; + } } static int @@ -6609,6 +6616,9 @@ static int compiler_warn(struct compiler *c, location loc, const char *format, ...) { + if (c->c_disable_warning) { + return SUCCESS; + } va_list vargs; va_start(vargs, format); PyObject *msg = PyUnicode_FromFormatV(format, vargs); @@ -6616,8 +6626,8 @@ compiler_warn(struct compiler *c, location loc, if (msg == NULL) { return ERROR; } - if (_PyErr_WarnExplicitObjectWithContext(PyExc_SyntaxWarning, msg, - c->c_filename, loc.lineno) < 0) + if (PyErr_WarnExplicitObject(PyExc_SyntaxWarning, msg, + c->c_filename, loc.lineno, NULL, NULL) < 0) { if (PyErr_ExceptionMatches(PyExc_SyntaxWarning)) { /* Replace the SyntaxWarning exception with a SyntaxError -- 2.47.3