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.
This commit is contained in:
Victor Stinner 2019-06-14 18:03:22 +02:00 committed by GitHub
parent 9765efcb39
commit 212646cae6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 30 additions and 23 deletions

View file

@ -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

View file

@ -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::

View file

@ -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.

View file

@ -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

View file

@ -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):