bpo-36829: Document test.support.catch_unraisable_exception() (GH-13554)
authorVictor Stinner <vstinner@redhat.com>
Fri, 24 May 2019 22:09:38 +0000 (00:09 +0200)
committerGitHub <noreply@github.com>
Fri, 24 May 2019 22:09:38 +0000 (00:09 +0200)
catch_unraisable_exception() now also removes its 'unraisable'
attribute at the context manager exit.

Doc/library/test.rst
Lib/test/support/__init__.py
Lib/test/test_io.py

index 054521dcc5d3ebaf40cf7d5a97e38ba90ddbfc5c..b7a2595708d0ce907b35aa61587e86933ab751b7 100644 (file)
@@ -1081,6 +1081,26 @@ The :mod:`test.support` module defines the following functions:
    :exc:`PermissionError` is raised.
 
 
+.. function:: catch_unraisable_exception()
+
+   Context manager catching unraisable exception using
+   :func:`sys.unraisablehook`.
+
+   Usage::
+
+       with support.catch_unraisable_exception() as cm:
+           # code creating an "unraisable exception"
+           ...
+
+           # check the unraisable exception: use cm.unraisable
+           ...
+
+       # cm.unraisable attribute no longer exists at this point
+       # (to break a reference cycle)
+
+   .. versionadded:: 3.8
+
+
 .. function:: find_unused_port(family=socket.AF_INET, socktype=socket.SOCK_STREAM)
 
    Returns an unused port that should be suitable for binding.  This is
index 2fe9d9dc80998f23653516b62cb1bed345026a5e..d6ed2215f38340a8bd0a5540c6ab71c76cfe004e 100644 (file)
@@ -3043,12 +3043,14 @@ class catch_unraisable_exception:
     Usage:
 
         with support.catch_unraisable_exception() as cm:
+            # code creating an "unraisable exception"
             ...
 
-            # check the expected unraisable exception: use cm.unraisable
+            # check the unraisable exception: use cm.unraisable
             ...
 
-        # cm.unraisable is None here (to break a reference cycle)
+        # cm.unraisable attribute no longer exists at this point
+        # (to break a reference cycle)
     """
 
     def __init__(self):
@@ -3065,5 +3067,5 @@ class catch_unraisable_exception:
 
     def __exit__(self, *exc_info):
         # Clear the unraisable exception to explicitly break a reference cycle
-        self.unraisable = None
+        del self.unraisable
         sys.unraisablehook = self._old_hook
index 6f22b35a9ab9f1561eca1075fa5c8cccc5178557..3a1f5ba5b6663d5cea385179dc46ad3fb0336dba 100644 (file)
@@ -1098,18 +1098,14 @@ class CommonBufferedTests:
         # Test that the exception state is not modified by a destructor,
         # even if close() fails.
         rawio = self.CloseFailureIO()
-        try:
-            with support.catch_unraisable_exception() as cm:
-                with self.assertRaises(AttributeError):
-                    self.tp(rawio).xyzzy
+        with support.catch_unraisable_exception() as cm:
+            with self.assertRaises(AttributeError):
+                self.tp(rawio).xyzzy
 
             if not IOBASE_EMITS_UNRAISABLE:
                 self.assertIsNone(cm.unraisable)
             elif cm.unraisable is not None:
                 self.assertEqual(cm.unraisable.exc_type, OSError)
-        finally:
-            # Explicitly break reference cycle
-            cm = None
 
     def test_repr(self):
         raw = self.MockRawIO()
@@ -2854,18 +2850,14 @@ class TextIOWrapperTest(unittest.TestCase):
         # Test that the exception state is not modified by a destructor,
         # even if close() fails.
         rawio = self.CloseFailureIO()
-        try:
-            with support.catch_unraisable_exception() as cm:
-                with self.assertRaises(AttributeError):
-                    self.TextIOWrapper(rawio).xyzzy
+        with support.catch_unraisable_exception() as cm:
+            with self.assertRaises(AttributeError):
+                self.TextIOWrapper(rawio).xyzzy
 
             if not IOBASE_EMITS_UNRAISABLE:
                 self.assertIsNone(cm.unraisable)
             elif cm.unraisable is not None:
                 self.assertEqual(cm.unraisable.exc_type, OSError)
-        finally:
-            # Explicitly break reference cycle
-            cm = None
 
     # Systematic tests of the text I/O API