From 750c5abf43b7b1627ab59ead237bef4c2314d29e Mon Sep 17 00:00:00 2001 From: Mario Corchero Date: Thu, 12 Nov 2020 18:27:44 +0100 Subject: bpo-42308: Add threading.__excepthook__ (GH-23218) Add threading.__excepthook__ to allow retrieving the original value of threading.excepthook in case it is set to a broken or a different value. --- Doc/library/threading.rst | 7 +++++++ Doc/whatsnew/3.10.rst | 5 +++++ Lib/test/test_threading.py | 21 +++++++++++++++++++++ Lib/threading.py | 4 ++++ .../2020-11-10-12-09-13.bpo-42308.yaJHH9.rst | 3 +++ 5 files changed, 40 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2020-11-10-12-09-13.bpo-42308.yaJHH9.rst diff --git a/Doc/library/threading.rst b/Doc/library/threading.rst index e05486f..6907354 100644 --- a/Doc/library/threading.rst +++ b/Doc/library/threading.rst @@ -71,6 +71,13 @@ This module defines the following functions: .. versionadded:: 3.8 +.. data:: __excepthook__ + + Holds the original value of :func:`threading.excepthook`. It is saved so that the + original value can be restored in case they happen to get replaced with + broken or alternative objects. + + .. versionadded:: 3.10 .. function:: get_ident() diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst index 74c1c28..4d77200 100644 --- a/Doc/whatsnew/3.10.rst +++ b/Doc/whatsnew/3.10.rst @@ -263,6 +263,11 @@ retrieve the functions set by :func:`threading.settrace` and :func:`threading.setprofile` respectively. (Contributed by Mario Corchero in :issue:`42251`.) +Add :data:`threading.__excepthook__` to allow retrieving the original value +of :func:`threading.excepthook` in case it is set to a broken or a different +value. +(Contributed by Mario Corchero in :issue:`42308`.) + traceback --------- diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py index e0e5406..db440d4 100644 --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -1352,6 +1352,27 @@ class ExceptHookTests(BaseTestCase): 'Exception in threading.excepthook:\n') self.assertEqual(err_str, 'threading_hook failed') + def test_original_excepthook(self): + def run_thread(): + with support.captured_output("stderr") as output: + thread = ThreadRunFail(name="excepthook thread") + thread.start() + thread.join() + return output.getvalue() + + def threading_hook(args): + print("Running a thread failed", file=sys.stderr) + + default_output = run_thread() + with support.swap_attr(threading, 'excepthook', threading_hook): + custom_hook_output = run_thread() + threading.excepthook = threading.__excepthook__ + recovered_output = run_thread() + + self.assertEqual(default_output, recovered_output) + self.assertNotEqual(default_output, custom_hook_output) + self.assertEqual(custom_hook_output, "Running a thread failed\n") + class TimerTests(BaseTestCase): diff --git a/Lib/threading.py b/Lib/threading.py index d4fe649..7dae77d 100644 --- a/Lib/threading.py +++ b/Lib/threading.py @@ -1200,6 +1200,10 @@ except ImportError: stderr.flush() +# Original value of threading.excepthook +__excepthook__ = excepthook + + def _make_invoke_excepthook(): # Create a local namespace to ensure that variables remain alive # when _invoke_excepthook() is called, even if it is called late during diff --git a/Misc/NEWS.d/next/Library/2020-11-10-12-09-13.bpo-42308.yaJHH9.rst b/Misc/NEWS.d/next/Library/2020-11-10-12-09-13.bpo-42308.yaJHH9.rst new file mode 100644 index 0000000..3460b0c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-11-10-12-09-13.bpo-42308.yaJHH9.rst @@ -0,0 +1,3 @@ +Add :data:`threading.__excepthook__` to allow retrieving the original value +of :func:`threading.excepthook` in case it is set to a broken or a different +value. Patch by Mario Corchero. -- cgit v0.12