Commit 6d22cc8e authored by Victor Stinner's avatar Victor Stinner Committed by GitHub

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.
parent 63ab4ba0
......@@ -1086,6 +1086,18 @@ The :mod:`test.support` module defines the following functions:
Context manager catching unraisable exception using
: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::
with support.catch_unraisable_exception() as cm:
......
......@@ -3040,6 +3040,18 @@ class catch_unraisable_exception:
"""
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:
with support.catch_unraisable_exception() as cm:
......@@ -3058,6 +3070,8 @@ class catch_unraisable_exception:
self._old_hook = None
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
def __enter__(self):
......@@ -3066,6 +3080,10 @@ class catch_unraisable_exception:
return self
def __exit__(self, *exc_info):
# Clear the unraisable exception to explicitly break a reference cycle
del self.unraisable
# Clear the unraisable exception to explicitly break a reference cycle.
# It can call _hook() again: ignore the new unraisable exception in
# this case.
self.unraisable = None
sys.unraisablehook = self._old_hook
del self.unraisable
Fix :func:`test.support.catch_unraisable_exception`: its __exit__() method
now ignores unraisable exception raised when clearing its ``unraisable``
attribute.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment