]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.13] gh-131927: Prevent emitting compiler warnings twice (GH-131993) (GH-132463)
authorTomas R. <tomas.roun8@gmail.com>
Sun, 13 Apr 2025 08:42:04 +0000 (10:42 +0200)
committerGitHub <noreply@github.com>
Sun, 13 Apr 2025 08:42:04 +0000 (08:42 +0000)
(cherry picked from commit 3d08c8ad20dfabd4864be139cd9c2eb5602ccdfe)

Include/cpython/warnings.h
Lib/test/test_compile.py
Python/_warnings.c
Python/compile.c

index 4e3eb88e8ff4472b37f1903184097757271d6c5b..8731fd2e96b716fd87d988d40320e0ab4b15651f 100644 (file)
@@ -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);
index ed4e6265eac438c590f58eb030a1411b86829042..b57adfadb5af5f945ec2bf45b23de1624c8d8e37 100644 (file)
@@ -1512,6 +1512,24 @@ class TestSpecifics(unittest.TestCase):
                     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
index 4bb83b214ae6cc75bffd60a6185da40e38deccdf..5bbd4a9c19f6c99329da09a40e5db72caf55693a 100644 (file)
@@ -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,
index ba780927eff9d60b6e2c3af8ffeb00e7efddac68..bb2c2293a38c9a3fe291c96b32062f201f64180e 100644 (file)
@@ -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