diff options
author | Victor Stinner <vstinner@redhat.com> | 2019-06-13 12:44:54 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-06-13 12:44:54 (GMT) |
commit | 6d22cc8e90ccb1e1965b1a4bc79456e2cc1e5a3e (patch) | |
tree | 5cabdc22f81daacb1ce82a3975580dc3f4261a3c /Lib | |
parent | 63ab4ba07b492448844940c347787ba30735b7f2 (diff) | |
download | cpython-6d22cc8e90ccb1e1965b1a4bc79456e2cc1e5a3e.zip cpython-6d22cc8e90ccb1e1965b1a4bc79456e2cc1e5a3e.tar.gz cpython-6d22cc8e90ccb1e1965b1a4bc79456e2cc1e5a3e.tar.bz2 |
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.
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/test/support/__init__.py | 22 |
1 files changed, 20 insertions, 2 deletions
diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index d6ed221..174e045 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -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 |