unraisableexception.py


Overview

The [unraisableexception.py](/projects/286/67428) module in pytest is dedicated to **capturing, managing, and reporting unraisable exceptions** that occur during test execution. Unraisable exceptions are errors that happen in contexts where Python cannot raise them normally, such as during object finalization (`__del__`) or in background cleanup, where exceptions are simply logged or ignored by the interpreter.

Python 3.4+ introduced `sys.unraisablehook` to intercept these exceptions. This module overrides that hook within pytest to **record unraisable exceptions as structured metadata**, stash them temporarily, and then **emit them as warnings** during test phases. This mechanism improves test diagnostics by surfacing otherwise silent failures, integrating them seamlessly into pytest’s warning and reporting system.

The module also performs additional **garbage collection iterations** during cleanup to help flush out any lingering unraisable exceptions before the test session ends.


Detailed Explanation of Components

Constants and Keys


Class: UnraisableMeta

class UnraisableMeta(NamedTuple):
    msg: str
    cause_msg: str
    exc_value: BaseException | None

Function: gc_collect_harder(iterations: int) -> None


Function: unraisable_hook(unraisable: sys.UnraisableHookArgs, /, *, append: Callable[[UnraisableMeta | BaseException], object]) -> None


Function: collect_unraisable(config: Config) -> None


Function: cleanup(*, config: Config, prev_hook: Callable[[sys.UnraisableHookArgs], object]) -> None


Hook Function: pytest_configure(config: Config) -> None


Hook Functions: pytest_runtest_setup, pytest_runtest_call, pytest_runtest_teardown

@pytest.hookimpl(trylast=True)
def pytest_runtest_setup(item: Item) -> None:
    collect_unraisable(item.config)

@pytest.hookimpl(trylast=True)
def pytest_runtest_call(item: Item) -> None:
    collect_unraisable(item.config)

@pytest.hookimpl(trylast=True)
def pytest_runtest_teardown(item: Item) -> None:
    collect_unraisable(item.config)

Implementation Details and Algorithms


Interaction with Other System Components


Usage Example

This module is used internally by pytest and not typically invoked directly by users. However, the workflow can be summarized as:

# During pytest startup
pytest_configure(config)

# During test execution phases:
pytest_runtest_setup(item)   # Collect unraisable exceptions and emit warnings
pytest_runtest_call(item)    # Same as above
pytest_runtest_teardown(item)  # Same as above

# During cleanup:
cleanup(config=config, prev_hook=original_unraisablehook)

If an unraisable exception occurs during test execution (for instance, in an object's `__del__` method), it will be captured and later emitted as a warning during one of these phases. If warnings are treated as errors, pytest will fail the test accordingly, making hidden errors visible.


Visual Diagram: Class and Function Structure

classDiagram
    class UnraisableMeta {
        +msg: str
        +cause_msg: str
        +exc_value: BaseException | None
    }

    class gc_collect_harder {
        +iterations: int
        +__call__()
    }

    class unraisable_hook {
        +unraisable: sys.UnraisableHookArgs
        +append: Callable
        +__call__()
    }

    class collect_unraisable {
        +config: Config
        +__call__()
    }

    class cleanup {
        +config: Config
        +prev_hook: Callable
        +__call__()
    }

    class pytest_configure {
        +config: Config
        +__call__()
    }

    class pytest_runtest_setup {
        +item: Item
        +__call__()
    }

    class pytest_runtest_call {
        +item: Item
        +__call__()
    }

    class pytest_runtest_teardown {
        +item: Item
        +__call__()
    }

    pytest_configure --> unraisable_hook : sets as sys.unraisablehook
    pytest_configure --> cleanup : registers as cleanup callback
    cleanup --> gc_collect_harder : calls multiple times
    cleanup --> collect_unraisable : calls to emit warnings
    pytest_runtest_setup --> collect_unraisable : calls to flush exceptions
    pytest_runtest_call --> collect_unraisable
    pytest_runtest_teardown --> collect_unraisable

Summary

The [unraisableexception.py](/projects/286/67428) module enhances pytest’s ability to detect and report **unraisable exceptions** by:

This improves the reliability and observability of tests, making otherwise silent errors visible and actionable.


End of Documentation for unraisableexception.py