https://github.com/python/cpython/commit/3d08c8ad20dfabd4864be139cd9c2eb5602ccdfe
commit: 3d08c8ad20dfabd4864be139cd9c2eb5602ccdfe
branch: main
author: Tomas R. <[email protected]>
committer: iritkatriel <[email protected]>
date: 2025-04-12T11:34:36+01:00
summary:
gh-131927: Prevent emitting optimizer warnings twice in the REPL (#131993)
files:
M Include/cpython/warnings.h
M Lib/test/test_compile.py
M Lib/test/test_pyrepl/test_interact.py
M Python/_warnings.c
M Python/errors.c
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 9cc025d85e168a..0377b3f954f44b 100644
--- a/Lib/test/test_compile.py
+++ b/Lib/test/test_compile.py
@@ -1646,6 +1646,24 @@ class WeirdDict(dict):
self.assertRaises(NameError, ns['foo'])
+ 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', '<stdin>', 'eval')
+ compile('1 is 1', '<stdin>', 'eval')
+
+ self.assertEqual(len(caught), 1)
+
+ with warnings.catch_warnings(record=True) as caught:
+ warnings.simplefilter("always")
+ compile('1 is 1', '<stdin>', 'eval')
+ compile('1 is 1', '<stdin>', 'eval')
+
+ self.assertEqual(len(caught), 2)
+
class TestBooleanExpression(unittest.TestCase):
class Value:
def __init__(self):
diff --git a/Lib/test/test_pyrepl/test_interact.py
b/Lib/test/test_pyrepl/test_interact.py
index af5d4d0e67632a..a20719033fc9b7 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
@@ -273,3 +274,28 @@ def test_incomplete_statement(self):
code = "if foo:"
console = InteractiveColoredConsole(namespace, filename="<stdin>")
self.assertTrue(_more_lines(console, code))
+
+
+class TestWarnings(unittest.TestCase):
+ def test_pep_765_warning(self):
+ """
+ Test that a SyntaxWarning emitted from the
+ AST optimizer is only shown once in the REPL.
+ """
+ # gh-131927
+ console = InteractiveColoredConsole()
+ code = dedent("""\
+ def f():
+ try:
+ return 1
+ finally:
+ return 2
+ """)
+
+ with warnings.catch_warnings(record=True) as caught:
+ warnings.simplefilter("default")
+ console.runsource(code)
+
+ count = sum("'return' in a 'finally' block" in str(w.message)
+ for w in caught)
+ self.assertEqual(count, 1)
diff --git a/Python/_warnings.c b/Python/_warnings.c
index 912468d2a59a95..39bf1b225ccb0c 100644
--- a/Python/_warnings.c
+++ b/Python/_warnings.c
@@ -1479,6 +1479,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/errors.c b/Python/errors.c
index 14999d6dbaf72e..2b088e2f3888a1 100644
--- a/Python/errors.c
+++ b/Python/errors.c
@@ -1906,8 +1906,8 @@ int
_PyErr_EmitSyntaxWarning(PyObject *msg, PyObject *filename, int lineno, int
col_offset,
int end_lineno, int end_col_offset)
{
- if (PyErr_WarnExplicitObject(PyExc_SyntaxWarning, msg, filename,
- lineno, NULL, NULL) < 0)
+ if (_PyErr_WarnExplicitObjectWithContext(PyExc_SyntaxWarning, msg,
+ filename, lineno) < 0)
{
if (PyErr_ExceptionMatches(PyExc_SyntaxWarning)) {
/* Replace the SyntaxWarning exception with a SyntaxError
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]