bpo-43843: libregrtest uses threading.excepthook (GH-25400)
test.libregrtest now marks a test as ENV_CHANGED (altered the
execution environment) if a thread raises an exception but does not
catch it. It sets a hook on threading.excepthook. Use
--fail-env-changed option to mark the test as failed.
libregrtest regrtest_unraisable_hook() explicitly flushs
sys.stdout, sys.stderr and sys.__stderr__.
diff --git a/Lib/test/libregrtest/utils.py b/Lib/test/libregrtest/utils.py
index 13efdb4..89d7e7e 100644
--- a/Lib/test/libregrtest/utils.py
+++ b/Lib/test/libregrtest/utils.py
@@ -68,14 +68,23 @@ def print_warning(msg):
orig_unraisablehook = None
+def flush_std_streams():
+ if sys.stdout is not None:
+ sys.stdout.flush()
+ if sys.stderr is not None:
+ sys.stderr.flush()
+
+
def regrtest_unraisable_hook(unraisable):
global orig_unraisablehook
support.environment_altered = True
print_warning("Unraisable exception")
old_stderr = sys.stderr
try:
+ flush_std_streams()
sys.stderr = sys.__stderr__
orig_unraisablehook(unraisable)
+ sys.stderr.flush()
finally:
sys.stderr = old_stderr
@@ -86,6 +95,30 @@ def setup_unraisable_hook():
sys.unraisablehook = regrtest_unraisable_hook
+orig_threading_excepthook = None
+
+
+def regrtest_threading_excepthook(args):
+ global orig_threading_excepthook
+ support.environment_altered = True
+ print_warning(f"Uncaught thread exception: {args.exc_type.__name__}")
+ old_stderr = sys.stderr
+ try:
+ flush_std_streams()
+ sys.stderr = sys.__stderr__
+ orig_threading_excepthook(args)
+ sys.stderr.flush()
+ finally:
+ sys.stderr = old_stderr
+
+
+def setup_threading_excepthook():
+ global orig_threading_excepthook
+ import threading
+ orig_threading_excepthook = threading.excepthook
+ threading.excepthook = regrtest_threading_excepthook
+
+
def clear_caches():
# Clear the warnings registry, so they can be displayed again
for mod in sys.modules.values():