summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/library/test.rst20
-rw-r--r--Lib/test/support/__init__.py8
-rw-r--r--Lib/test/test_io.py20
3 files changed, 31 insertions, 17 deletions
diff --git a/Doc/library/test.rst b/Doc/library/test.rst
index 054521d..b7a2595 100644
--- a/Doc/library/test.rst
+++ b/Doc/library/test.rst
@@ -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
diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py
index 2fe9d9d..d6ed221 100644
--- a/Lib/test/support/__init__.py
+++ b/Lib/test/support/__init__.py
@@ -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
diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py
index 6f22b35..3a1f5ba 100644
--- a/Lib/test/test_io.py
+++ b/Lib/test/test_io.py
@@ -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