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.
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 @@ def sys_hook(exc_type, exc_value, exc_traceback):
'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 @@ def excepthook(args, /):
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