Commit 212646ca authored by Victor Stinner's avatar Victor Stinner Committed by GitHub

bpo-37261: Document sys.unraisablehook corner cases (GH-14059)

Document reference cycle and resurrected objects issues in
sys.unraisablehook() and threading.excepthook() documentation.

Fix test.support.catch_unraisable_exception(): __exit__() no longer
ignores unraisable exceptions.

Fix test_io test_writer_close_error_on_close(): use a second
catch_unraisable_exception() to catch the BufferedWriter unraisable
exception.
parent 9765efcb
......@@ -1514,13 +1514,21 @@ always available.
* *err_msg*: Error message, can be ``None``.
* *object*: Object causing the exception, can be ``None``.
:func:`sys.unraisablehook` can be overridden to control how unraisable
exceptions are handled.
The default hook formats *err_msg* and *object* as:
``f'{err_msg}: {object!r}'``; use "Exception ignored in" error message
if *err_msg* is ``None``.
:func:`sys.unraisablehook` can be overridden to control how unraisable
exceptions are handled.
Storing *exc_value* using a custom hook can create a reference cycle. It
should be cleared explicitly to break the reference cycle when the
exception is no longer needed.
Storing *object* using a custom hook can resurrect it if it is set to an
object which is being finalized. Avoid storing *object* after the custom
hook completes to avoid resurrecting objects.
See also :func:`excepthook` which handles uncaught exceptions.
.. versionadded:: 3.8
......
......@@ -1086,17 +1086,13 @@ 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.
Storing the object (``cm.unraisable.object``) can resurrect it if it is set
to an object which is being finalized. Exiting the context manager clears
the stored object.
Usage::
......
......@@ -58,6 +58,14 @@ This module defines the following functions:
:func:`threading.excepthook` can be overridden to control how uncaught
exceptions raised by :func:`Thread.run` are handled.
Storing *exc_value* using a custom hook can create a reference cycle. It
should be cleared explicitly to break the reference cycle when the
exception is no longer needed.
Storing *object* using a custom hook can resurrect it if it is set to an
object which is being finalized. Avoid storing *object* after the custom
hook completes to avoid resurrecting objects.
.. seealso::
:func:`sys.excepthook` handles uncaught exceptions.
......
......@@ -3040,17 +3040,13 @@ 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.
Storing the object (cm.unraisable.object) can resurrect it if it is set to
an object which is being finalized. Exiting the context manager clears the
stored object.
Usage:
......@@ -3080,10 +3076,5 @@ class catch_unraisable_exception:
return self
def __exit__(self, *exc_info):
# 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
......@@ -2072,8 +2072,12 @@ class BufferedRWPairTest(unittest.TestCase):
writer.close = lambda: None
writer = None
# Ignore BufferedWriter (of the BufferedRWPair) unraisable exception
with support.catch_unraisable_exception():
pair = None
# Ignore BufferedRWPair unraisable exception
with support.catch_unraisable_exception():
pair = None
support.gc_collect()
support.gc_collect()
def test_reader_writer_close_error_on_close(self):
......
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