bpo-37261: Fix support.catch_unraisable_exception() (GH-14052)
The __exit__() method of test.support.catch_unraisable_exception
context manager now ignores unraisable exception raised when clearing
self.unraisable attribute.
(cherry picked from commit 6d22cc8e90
)
Co-authored-by: Victor Stinner <vstinner@redhat.com>
This commit is contained in:
parent
0a9baec16c
commit
b4f5b21253
|
@ -1086,6 +1086,18 @@ The :mod:`test.support` module defines the following functions:
|
||||||
Context manager catching unraisable exception using
|
Context manager catching unraisable exception using
|
||||||
:func:`sys.unraisablehook`.
|
:func:`sys.unraisablehook`.
|
||||||
|
|
||||||
|
If the *object* attribute of the unraisable hook is set and the object is
|
||||||
|
being finalized, the object is resurrected because the context manager
|
||||||
|
stores a strong reference to it (``cm.unraisable.object``).
|
||||||
|
|
||||||
|
Storing the exception value (``cm.unraisable.exc_value``) creates a
|
||||||
|
reference cycle. The reference cycle is broken explicitly when the context
|
||||||
|
manager exits.
|
||||||
|
|
||||||
|
Exiting the context manager clears the stored unraisable exception. It can
|
||||||
|
trigger a new unraisable exception (ex: the resurrected object is finalized
|
||||||
|
again and raises the same exception): it is silently ignored in this case.
|
||||||
|
|
||||||
Usage::
|
Usage::
|
||||||
|
|
||||||
with support.catch_unraisable_exception() as cm:
|
with support.catch_unraisable_exception() as cm:
|
||||||
|
|
|
@ -3040,6 +3040,18 @@ class catch_unraisable_exception:
|
||||||
"""
|
"""
|
||||||
Context manager catching unraisable exception using sys.unraisablehook.
|
Context manager catching unraisable exception using sys.unraisablehook.
|
||||||
|
|
||||||
|
If the *object* attribute of the unraisable hook is set and the object is
|
||||||
|
being finalized, the object is resurrected because the context manager
|
||||||
|
stores a strong reference to it (cm.unraisable.object).
|
||||||
|
|
||||||
|
Storing the exception value (cm.unraisable.exc_value) creates a reference
|
||||||
|
cycle. The reference cycle is broken explicitly when the context manager
|
||||||
|
exits.
|
||||||
|
|
||||||
|
Exiting the context manager clears the stored unraisable exception. It can
|
||||||
|
trigger a new unraisable exception (ex: the resurrected object is finalized
|
||||||
|
again and raises the same exception): it is silently ignored in this case.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
|
|
||||||
with support.catch_unraisable_exception() as cm:
|
with support.catch_unraisable_exception() as cm:
|
||||||
|
@ -3058,6 +3070,8 @@ class catch_unraisable_exception:
|
||||||
self._old_hook = None
|
self._old_hook = None
|
||||||
|
|
||||||
def _hook(self, unraisable):
|
def _hook(self, unraisable):
|
||||||
|
# Storing unraisable.object can resurrect an object which is being
|
||||||
|
# finalized. Storing unraisable.exc_value creates a reference cycle.
|
||||||
self.unraisable = unraisable
|
self.unraisable = unraisable
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
|
@ -3066,6 +3080,10 @@ class catch_unraisable_exception:
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def __exit__(self, *exc_info):
|
def __exit__(self, *exc_info):
|
||||||
# Clear the unraisable exception to explicitly break a reference cycle
|
# Clear the unraisable exception to explicitly break a reference cycle.
|
||||||
del self.unraisable
|
# It can call _hook() again: ignore the new unraisable exception in
|
||||||
|
# this case.
|
||||||
|
self.unraisable = None
|
||||||
|
|
||||||
sys.unraisablehook = self._old_hook
|
sys.unraisablehook = self._old_hook
|
||||||
|
del self.unraisable
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
Fix :func:`test.support.catch_unraisable_exception`: its __exit__() method
|
||||||
|
now ignores unraisable exception raised when clearing its ``unraisable``
|
||||||
|
attribute.
|
Loading…
Reference in New Issue