Skip to content

[3.13] gh-131927: Prevent emitting optimizer warnings twice in the REPL (GH-131993) #132463

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Include/cpython/warnings.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
18 changes: 18 additions & 0 deletions Lib/test/test_compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -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', '<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)

@requires_debug_ranges()
class TestSourcePositions(unittest.TestCase):
# Ensure that compiled code snippets have correct line and column numbers
Expand Down
22 changes: 22 additions & 0 deletions Python/_warnings.c
Original file line number Diff line number Diff line change
Expand Up @@ -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, &registry)) {
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,
Expand Down
4 changes: 2 additions & 2 deletions Python/compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a note, 3.13 uses compiler_warn instead of _PyErr_EmitSyntaxWarning to emit warnings.

c->c_filename, loc.lineno) < 0)
{
if (PyErr_ExceptionMatches(PyExc_SyntaxWarning)) {
/* Replace the SyntaxWarning exception with a SyntaxError
Expand Down
Loading