test_threadexception.py
Overview
This test file is part of the Pytest testing framework codebase and focuses on verifying the behavior of Pytest when dealing with **unhandled exceptions raised in threads** during test execution. It specifically tests Pytest's ability to:
Detect exceptions thrown in child threads spawned during tests.
Emit the appropriate warnings (PytestUnhandledThreadExceptionWarning) when thread exceptions occur.
Treat such warnings as errors when configured to do so.
Handle exceptions raised in thread exception hooks or during test setup/teardown phases.
Aggregate multiple thread exceptions into a grouped error.
Gracefully handle failures in collecting thread exception information.
Through a series of test cases, the file ensures Pytest correctly reports, warns, or fails tests when thread exceptions happen, thus improving robustness and developer awareness of concurrency issues in tests.
Detailed Explanation of Tests
All tests use the `pytester` fixture (`Pytester` class instance) which provides an isolated environment to create and run test files dynamically and capture their results.
1. test_unhandled_thread_exception(pytester: Pytester) -> None
**Purpose:** Verifies that an unhandled exception raised in a thread during a test is detected by Pytest and results in a warning.
**Implementation details:**
A test file is created with a test function test_it which launches a thread running a function
oopsthat raisesValueError("Oops").The thread is started and joined within the test.
A second test function test_2 is defined that passes.
The test file is run using
pytester.runpytest().Assertions check:
The run completes successfully (
ret == 0).Both tests passed.
Exactly one warning of type PytestUnhandledThreadExceptionWarning is issued.
The warning message and traceback include the thread name and the exception.
**Usage example:** This test verifies core Pytest behavior and is not called directly by users but run during Pytest development.
2. test_unhandled_thread_exception_in_setup(pytester: Pytester) -> None
**Purpose:** Tests detection of thread exceptions raised during a fixture's setup phase.
**Implementation details:**
A fixture
threadexcis defined that runs a thread which raises an exception.A test test_it uses the fixture.
A second test test_2 does nothing.
The test file is executed and checked for the expected warning.
3. test_unhandled_thread_exception_in_teardown(pytester: Pytester) -> None
**Purpose:** Tests detection of thread exceptions raised during fixture teardown (after `yield`).
**Implementation details:**
Fixture
threadexcyields control and then runs a thread that raises an exception.Similar assertions as previous tests.
4. test_unhandled_thread_exception_warning_error(pytester: Pytester) -> None
**Purpose:** Ensures warnings of unhandled thread exceptions are treated as errors when the warning filter is set to `error`.
**Implementation details:**
Same test structure as
test_unhandled_thread_exception.The warning filter is set to
"error::pytest.PytestUnhandledThreadExceptionWarning".The run must fail (
ret == TESTS_FAILED).Exactly one test passes, one fails.
5. test_threadexception_warning_multiple_errors(pytester: Pytester) -> None
**Purpose:** Tests behavior when multiple thread exceptions occur during a single test run.
**Implementation details:**
Within one test function, two threads are launched sequentially, each raising exceptions.
The run should fail with multiple warnings grouped as an
ExceptionGroup.The output is checked for the grouping message.
6. test_unraisable_collection_failure(pytester: Pytester) -> None
**Purpose:** Tests Pytest's handling of failures to collect thread exception information (e.g., thread name property raising).
**Implementation details:**
A custom Thread subclass overrides .name property to raise
RuntimeError.The thread raises a normal exception, but name retrieval fails.
Pytest should fail the test run with an error indicating failure to process the thread exception.
7. test_unhandled_thread_exception_after_teardown(pytester: Pytester) -> None
**Purpose:** Tests behavior when thread exceptions occur after all tests and teardown have finished (in cleanups).
**Implementation details:**
A cleanup function registered via request.config.add_cleanup starts a thread that raises an exception.
The test run is executed with warnings treated as errors.
The current behavior results in an internal error exit code (not a test failure).
Output should include the exception traceback.
8. test_possibly_none_excinfo(pytester: Pytester) -> None
**Purpose:** Tests handling of [threading.excepthook](/projects/286/67223) when given an exception info object with [None](/projects/286/67505) values.
**Implementation details:**
Calls threading.excepthook directly with a SimpleNamespace mimicking an excinfo with None values.
Run with warnings as errors.
The test should fail with a PytestUnhandledThreadExceptionWarning.
Output includes a warning mentioning an unknown thread and a NoneType: None message.
Implementation Details and Algorithms
The tests rely heavily on Pytest's ability to intercept and warn about unhandled exceptions in threads using the PytestUnhandledThreadExceptionWarning.
The
pytesterfixture is leveraged to create isolated test files on the fly, run them, and inspect results.The tests systematically cover different lifecycle moments where thread exceptions can occur: test body, fixture setup, fixture teardown, and cleanup.
They verify that Pytest's warning system correctly identifies and reports exceptions, including the aggregation of multiple exceptions.
Some tests simulate failure modes like inability to retrieve thread names to test robustness.
The use of @pytest.mark.filterwarnings decorator configures warning filters for each test to check both default warning and error-on-warning behaviors.
Output assertions match traceback lines and warning summaries to ensure correctness.
Interaction with Other Parts of the System
This file tests the integration of Pytest's thread exception handling mechanism with the core Pytest test runner and warning system.
The warnings raised (PytestUnhandledThreadExceptionWarning) are defined elsewhere in Pytest's warning modules.
It indirectly tests the threading.excepthook integration implemented in Pytest to catch thread exceptions.
The tests interact with Pytest's fixture system to check thread exceptions in setup/teardown phases.
The results of these tests ensure that Pytest users get clear feedback about thread errors which otherwise might be silently swallowed.
The file depends on the _pytest.pytester.Pytester utility for test environment setup and execution.
Mermaid Class Diagram
classDiagram
class test_threadexception.py {
+test_unhandled_thread_exception(pytester: Pytester) void
+test_unhandled_thread_exception_in_setup(pytester: Pytester) void
+test_unhandled_thread_exception_in_teardown(pytester: Pytester) void
+test_unhandled_thread_exception_warning_error(pytester: Pytester) void
+test_threadexception_warning_multiple_errors(pytester: Pytester) void
+test_unraisable_collection_failure(pytester: Pytester) void
+test_unhandled_thread_exception_after_teardown(pytester: Pytester) void
+test_possibly_none_excinfo(pytester: Pytester) void
}
Summary
`test_threadexception.py` is a focused test suite ensuring Pytest's robust handling and reporting of unhandled exceptions in threads spawned during test execution. It covers multiple phases of test lifecycle, warning and error modes, and edge cases. This contributes to Pytest's reliability in concurrent testing scenarios and improves developer experience by surfacing subtle threading errors clearly.