https://github.com/python/cpython/commit/a25042e6d2b71651e93ff90c361ad763c0368872
commit: a25042e6d2b71651e93ff90c361ad763c0368872
branch: main
author: Victor Stinner <[email protected]>
committer: vstinner <[email protected]>
date: 2025-02-05T10:31:59Z
summary:
gh-129354: Use PyErr_FormatUnraisable() function (#129523)
Replace PyErr_WriteUnraisable() with PyErr_FormatUnraisable().
Update tests:
* test_coroutines
* test_exceptions
* test_generators
* test_struct
files:
M Lib/test/test_coroutines.py
M Lib/test/test_exceptions.py
M Lib/test/test_generators.py
M Lib/test/test_struct.py
M Objects/genobject.c
M Objects/typeobject.c
M Python/_warnings.c
diff --git a/Lib/test/test_coroutines.py b/Lib/test/test_coroutines.py
index 840043d5271224..5566c9803d43ed 100644
--- a/Lib/test/test_coroutines.py
+++ b/Lib/test/test_coroutines.py
@@ -2136,8 +2136,10 @@ async def func(): pass
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 @@ async def corofn():
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
diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py
index 2d324827451b54..3838eb5b27c9e6 100644
--- a/Lib/test/test_exceptions.py
+++ b/Lib/test/test_exceptions.py
@@ -1678,10 +1678,13 @@ def __del__(self):
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):
diff --git a/Lib/test/test_generators.py b/Lib/test/test_generators.py
index b6985054c33d10..bf4b88cd9c4450 100644
--- a/Lib/test/test_generators.py
+++ b/Lib/test/test_generators.py
@@ -2664,14 +2664,18 @@ def printsolution(self, x):
>>> 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 @@ def printsolution(self, x):
... 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
diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py
index 5fee9fbb92acf4..b99391e482ff70 100644
--- a/Lib/test/test_struct.py
+++ b/Lib/test/test_struct.py
@@ -694,7 +694,7 @@ def __del__(self):
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):
diff --git a/Objects/genobject.c b/Objects/genobject.c
index 73bbf86588c457..79aed8571c35e7 100644
--- a/Objects/genobject.c
+++ b/Objects/genobject.c
@@ -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);
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 93920341a179e8..f3238da8a642e4 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -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);
}
diff --git a/Python/_warnings.c b/Python/_warnings.c
index 283f203c72c9bf..bb195da9512caf 100644
--- a/Python/_warnings.c
+++ b/Python/_warnings.c
@@ -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);
}
}
}
_______________________________________________
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]