]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-129354: Use PyErr_FormatUnraisable() function (#129523)
authorVictor Stinner <vstinner@python.org>
Wed, 5 Feb 2025 10:31:59 +0000 (11:31 +0100)
committerGitHub <noreply@github.com>
Wed, 5 Feb 2025 10:31:59 +0000 (10:31 +0000)
Replace PyErr_WriteUnraisable() with PyErr_FormatUnraisable().

Update tests:

* test_coroutines
* test_exceptions
* test_generators
* test_struct

Lib/test/test_coroutines.py
Lib/test/test_exceptions.py
Lib/test/test_generators.py
Lib/test/test_struct.py
Objects/genobject.c
Objects/typeobject.c
Python/_warnings.c

index 840043d5271224955e302d7ba6f07f00748b0d56..5566c9803d43ed10ce2494a127095e4d2e21982d 100644 (file)
@@ -2136,8 +2136,10 @@ class CoroutineTest(unittest.TestCase):
             coro = None
             support.gc_collect()
 
+            self.assertEqual(cm.unraisable.err_msg,
+                             f"Exception ignored while finalizing "
+                             f"coroutine {coro_repr}")
             self.assertIn("was never awaited", str(cm.unraisable.exc_value))
-            self.assertEqual(repr(cm.unraisable.object), coro_repr)
 
     def test_for_assign_raising_stop_async_iteration(self):
         class BadTarget:
@@ -2411,10 +2413,13 @@ class OriginTrackingTest(unittest.TestCase):
                 coro_repr = repr(coro)
 
                 # clear reference to the coroutine without awaiting for it
+                coro_repr = repr(coro)
                 del coro
                 support.gc_collect()
 
-                self.assertEqual(repr(cm.unraisable.object), coro_repr)
+                self.assertEqual(cm.unraisable.err_msg,
+                                 f"Exception ignored while finalizing "
+                                 f"coroutine {coro_repr}")
                 self.assertEqual(cm.unraisable.exc_type, ZeroDivisionError)
 
             del warnings._warn_unawaited_coroutine
index 2d324827451b5458a14d98096c2a6f799dfd7ed9..3838eb5b27c9e6af13aec86364316e5313b5ec32 100644 (file)
@@ -1678,10 +1678,13 @@ class ExceptionTests(unittest.TestCase):
 
         obj = BrokenDel()
         with support.catch_unraisable_exception() as cm:
+            obj_repr = repr(type(obj).__del__)
             del obj
 
             gc_collect()  # For PyPy or other GCs.
-            self.assertEqual(cm.unraisable.object, BrokenDel.__del__)
+            self.assertEqual(cm.unraisable.err_msg,
+                             f"Exception ignored while calling "
+                             f"deallocator {obj_repr}")
             self.assertIsNotNone(cm.unraisable.exc_traceback)
 
     def test_unhandled(self):
index b6985054c33d106a7086cd03c6c344a077df6fed..bf4b88cd9c4450bdea3f3c10b33a3172fdd740f5 100644 (file)
@@ -2664,14 +2664,18 @@ Our ill-behaved code should be invoked during GC:
 >>> with support.catch_unraisable_exception() as cm:
 ...     g = f()
 ...     next(g)
+...     gen_repr = repr(g)
 ...     del g
 ...
+...     cm.unraisable.err_msg == (f'Exception ignored while closing '
+...                               f'generator {gen_repr}')
 ...     cm.unraisable.exc_type == RuntimeError
 ...     "generator ignored GeneratorExit" in str(cm.unraisable.exc_value)
 ...     cm.unraisable.exc_traceback is not None
 True
 True
 True
+True
 
 And errors thrown during closing should propagate:
 
@@ -2776,10 +2780,12 @@ to test.
 ...         invoke("del failed")
 ...
 >>> with support.catch_unraisable_exception() as cm:
-...     l = Leaker()
-...     del l
+...     leaker = Leaker()
+...     del_repr = repr(type(leaker).__del__)
+...     del leaker
 ...
-...     cm.unraisable.object == Leaker.__del__
+...     cm.unraisable.err_msg == (f'Exception ignored while '
+...                               f'calling deallocator {del_repr}')
 ...     cm.unraisable.exc_type == RuntimeError
 ...     str(cm.unraisable.exc_value) == "del failed"
 ...     cm.unraisable.exc_traceback is not None
index 5fee9fbb92acf41e7e4021bf07f67c07ec41f1fc..b99391e482ff7089e1c65e7180246395f056b917 100644 (file)
@@ -694,7 +694,7 @@ class StructTest(ComplexesAreIdenticalMixin, unittest.TestCase):
         rc, stdout, stderr = assert_python_ok("-c", code)
         self.assertEqual(rc, 0)
         self.assertEqual(stdout.rstrip(), b"")
-        self.assertIn(b"Exception ignored in:", stderr)
+        self.assertIn(b"Exception ignored while calling deallocator", stderr)
         self.assertIn(b"C.__del__", stderr)
 
     def test__struct_reference_cycle_cleaned_up(self):
index 73bbf86588c45719229517dac769703801b0bd3c..79aed8571c35e7df6f73ce865e2dc5ae0829cb0c 100644 (file)
@@ -97,8 +97,10 @@ _PyGen_Finalize(PyObject *self)
 
             PyObject *res = PyObject_CallOneArg(finalizer, self);
             if (res == NULL) {
-                PyErr_WriteUnraisable(self);
-            } else {
+                PyErr_FormatUnraisable("Exception ignored while "
+                                       "finalizing generator %R", self);
+            }
+            else {
                 Py_DECREF(res);
             }
             /* Restore the saved exception. */
@@ -122,7 +124,8 @@ _PyGen_Finalize(PyObject *self)
         PyObject *res = gen_close((PyObject*)gen, NULL);
         if (res == NULL) {
             if (PyErr_Occurred()) {
-                PyErr_WriteUnraisable(self);
+                PyErr_FormatUnraisable("Exception ignored while "
+                                       "closing generator %R", self);
             }
         }
         else {
@@ -338,7 +341,8 @@ gen_close_iter(PyObject *yf)
     else {
         PyObject *meth;
         if (PyObject_GetOptionalAttr(yf, &_Py_ID(close), &meth) < 0) {
-            PyErr_WriteUnraisable(yf);
+            PyErr_FormatUnraisable("Exception ignored while "
+                                   "closing generator %R", yf);
         }
         if (meth) {
             retval = _PyObject_CallNoArgs(meth);
index 93920341a179e88862ab2ba1937bdded45dd5f73..f3238da8a642e497d6545cc330f75480a51153cb 100644 (file)
@@ -10288,10 +10288,13 @@ slot_tp_finalize(PyObject *self)
     del = lookup_maybe_method(self, &_Py_ID(__del__), &unbound);
     if (del != NULL) {
         res = call_unbound_noarg(unbound, del, self);
-        if (res == NULL)
-            PyErr_WriteUnraisable(del);
-        else
+        if (res == NULL) {
+            PyErr_FormatUnraisable("Exception ignored while "
+                                   "calling deallocator %R", del);
+        }
+        else {
             Py_DECREF(res);
+        }
         Py_DECREF(del);
     }
 
index 283f203c72c9bff8ff98d2abacd014a384df6fa5..bb195da9512caf9e377cdb9d55dbd27878ab8717 100644 (file)
@@ -1445,7 +1445,8 @@ _PyErr_WarnUnawaitedAgenMethod(PyAsyncGenObject *agen, PyObject *method)
                           "coroutine method %R of %R was never awaited",
                           method, agen->ag_qualname) < 0)
     {
-        PyErr_WriteUnraisable((PyObject *)agen);
+        PyErr_FormatUnraisable("Exception ignored while "
+                               "finalizing async generator %R", agen);
     }
     PyErr_SetRaisedException(exc);
 }
@@ -1487,14 +1488,17 @@ _PyErr_WarnUnawaitedCoroutine(PyObject *coro)
     }
 
     if (PyErr_Occurred()) {
-        PyErr_WriteUnraisable(coro);
+        PyErr_FormatUnraisable("Exception ignored while "
+                               "finalizing coroutine %R", coro);
     }
+
     if (!warned) {
         if (_PyErr_WarnFormat(coro, PyExc_RuntimeWarning, 1,
                               "coroutine '%S' was never awaited",
                               ((PyCoroObject *)coro)->cr_qualname) < 0)
         {
-            PyErr_WriteUnraisable(coro);
+            PyErr_FormatUnraisable("Exception ignored while "
+                                   "finalizing coroutine %R", coro);
         }
     }
 }