[Python-checkins] bpo-37261: Fix support.catch_unraisable_exception() (GH-14052)

Miss Islington (bot) webhook-mailer at python.org
Thu Jun 13 09:26:05 EDT 2019


https://github.com/python/cpython/commit/b4f5b212535e75503fc33513676837089037bb48
commit: b4f5b212535e75503fc33513676837089037bb48
branch: 3.8
author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com>
committer: GitHub <noreply at github.com>
date: 2019-06-13T06:25:59-07:00
summary:

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 6d22cc8e90ccb1e1965b1a4bc79456e2cc1e5a3e)

Co-authored-by: Victor Stinner <vstinner at redhat.com>

files:
A Misc/NEWS.d/next/Tests/2019-06-13-12-19-56.bpo-37261.NuKFVo.rst
M Doc/library/test.rst
M Lib/test/support/__init__.py

diff --git a/Doc/library/test.rst b/Doc/library/test.rst
index b7a2595708d0..0a98c882465d 100644
--- a/Doc/library/test.rst
+++ b/Doc/library/test.rst
@@ -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:
diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py
index d6ed2215f383..174e0456dc71 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 @@ def __init__(self):
         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 @@ def __enter__(self):
         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
diff --git a/Misc/NEWS.d/next/Tests/2019-06-13-12-19-56.bpo-37261.NuKFVo.rst b/Misc/NEWS.d/next/Tests/2019-06-13-12-19-56.bpo-37261.NuKFVo.rst
new file mode 100644
index 000000000000..27ce78a70f2b
--- /dev/null
+++ b/Misc/NEWS.d/next/Tests/2019-06-13-12-19-56.bpo-37261.NuKFVo.rst
@@ -0,0 +1,3 @@
+Fix :func:`test.support.catch_unraisable_exception`: its __exit__() method
+now ignores unraisable exception raised when clearing its ``unraisable``
+attribute.



More information about the Python-checkins mailing list