From f0d89175ad7ef7afde35ce7838ff71298d04b8a5 Mon Sep 17 00:00:00 2001 From: "Tomas R." Date: Sat, 12 Apr 2025 12:34:36 +0200 Subject: [PATCH 1/2] [3.13] gh-131927: Prevent emitting optimizer warnings twice in the REPL (GH-131993) (cherry picked from commit 3d08c8ad20dfabd4864be139cd9c2eb5602ccdfe) Co-authored-by: Tomas R. --- Include/cpython/warnings.h | 6 ++++++ Lib/test/test_compile.py | 18 ++++++++++++++++++ Lib/test/test_pyrepl/test_interact.py | 1 + Python/_warnings.c | 22 ++++++++++++++++++++++ Python/compile.c | 4 ++-- 5 files changed, 49 insertions(+), 2 deletions(-) diff --git a/Include/cpython/warnings.h b/Include/cpython/warnings.h index 4e3eb88e8ff447..8731fd2e96b716 100644 --- a/Include/cpython/warnings.h +++ b/Include/cpython/warnings.h @@ -18,3 +18,9 @@ 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 ed4e6265eac438..b57adfadb5af5f 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -1512,6 +1512,24 @@ async def name_4(): pass [[]] + def test_compile_warnings(self): + # See gh-131927 + # Compile warnings originating from the same file and + # line are now only emitted once. + 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) + + 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) + @requires_debug_ranges() class TestSourcePositions(unittest.TestCase): # Ensure that compiled code snippets have correct line and column numbers diff --git a/Lib/test/test_pyrepl/test_interact.py b/Lib/test/test_pyrepl/test_interact.py index 2041a35c8a472b..dce79256d7045d 100644 --- a/Lib/test/test_pyrepl/test_interact.py +++ b/Lib/test/test_pyrepl/test_interact.py @@ -1,6 +1,7 @@ import contextlib import io import unittest +import warnings from unittest.mock import patch from textwrap import dedent diff --git a/Python/_warnings.c b/Python/_warnings.c index 4bb83b214ae6cc..5bbd4a9c19f6c9 100644 --- a/Python/_warnings.c +++ b/Python/_warnings.c @@ -1317,6 +1317,28 @@ 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 ba780927eff9d6..bb2c2293a38c9a 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -6616,8 +6616,8 @@ compiler_warn(struct compiler *c, location loc, if (msg == NULL) { return ERROR; } - if (PyErr_WarnExplicitObject(PyExc_SyntaxWarning, msg, c->c_filename, - loc.lineno, NULL, NULL) < 0) + if (_PyErr_WarnExplicitObjectWithContext(PyExc_SyntaxWarning, msg, + c->c_filename, loc.lineno) < 0) { if (PyErr_ExceptionMatches(PyExc_SyntaxWarning)) { /* Replace the SyntaxWarning exception with a SyntaxError From 99d3b5be93da85d449a4745b7489a39bc856660c Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 13 Apr 2025 11:18:26 +0300 Subject: [PATCH 2/2] Update test_interact.py --- Lib/test/test_pyrepl/test_interact.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Lib/test/test_pyrepl/test_interact.py b/Lib/test/test_pyrepl/test_interact.py index dce79256d7045d..2041a35c8a472b 100644 --- a/Lib/test/test_pyrepl/test_interact.py +++ b/Lib/test/test_pyrepl/test_interact.py @@ -1,7 +1,6 @@ import contextlib import io import unittest -import warnings from unittest.mock import patch from textwrap import dedent