Skip to content

Commit 80da427

Browse files
Remove thread join from threadexception plugin (#13027)
As per review comment: #13016 (comment). Closes #13028. --------- Co-authored-by: Bruno Oliveira <[email protected]>
1 parent ea1a79a commit 80da427

File tree

3 files changed

+4
-21
lines changed

3 files changed

+4
-21
lines changed

changelog/13016.improvement.rst

-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
A number of :ref:`threadexception <unraisable>` enhancements:
22

33
* Set the excepthook as early as possible and unset it as late as possible, to collect the most possible number of unhandled exceptions from threads.
4-
* join threads for 1 second just before unsetting the excepthook, to collect any straggling exceptions
54
* Collect multiple thread exceptions per test phase.
65
* Report the :mod:`tracemalloc` allocation traceback (if available).
76
* Avoid using a generator based hook to allow handling :class:`StopIteration` in test failures.

src/_pytest/threadexception.py

+3-18
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import functools
66
import sys
77
import threading
8-
import time
98
import traceback
109
from typing import NamedTuple
1110
from typing import TYPE_CHECKING
@@ -25,22 +24,6 @@
2524
from exceptiongroup import ExceptionGroup
2625

2726

28-
def join_threads() -> None:
29-
start = time.monotonic()
30-
current_thread = threading.current_thread()
31-
# This function is executed right at the end of the pytest run, just
32-
# before we return an exit code, which is where the interpreter joins
33-
# any remaining non-daemonic threads anyway, so it's ok to join all the
34-
# threads. However there might be threads that depend on some shutdown
35-
# signal that happens after pytest finishes, so we want to limit the
36-
# join time somewhat. A one second timeout seems reasonable.
37-
timeout = 1
38-
for thread in threading.enumerate():
39-
if thread is not current_thread and not thread.daemon:
40-
# TODO: raise an error/warning if there's dangling threads.
41-
thread.join(timeout - (time.monotonic() - start))
42-
43-
4427
class ThreadExceptionMeta(NamedTuple):
4528
msg: str
4629
cause_msg: str
@@ -96,7 +79,9 @@ def cleanup(
9679
) -> None:
9780
try:
9881
try:
99-
join_threads()
82+
# We don't join threads here, so exceptions raised from any
83+
# threads still running by the time _threading_atexits joins them
84+
# do not get captured (see #13027).
10085
collect_thread_exception(config)
10186
finally:
10287
threading.excepthook = prev_hook

testing/test_threadexception.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -195,17 +195,16 @@ def test_2(): pass
195195
def test_unhandled_thread_exception_after_teardown(pytester: Pytester) -> None:
196196
pytester.makepyfile(
197197
test_it="""
198-
import time
199198
import threading
200199
import pytest
201200
202201
def thread():
203202
def oops():
204-
time.sleep(0.5)
205203
raise ValueError("Oops")
206204
207205
t = threading.Thread(target=oops, name="MyThread")
208206
t.start()
207+
t.join()
209208
210209
def test_it(request):
211210
request.config.add_cleanup(thread)

0 commit comments

Comments
 (0)