Unraisable Exception Management

Purpose

Unraisable Exception Management addresses the challenge of capturing and reporting exceptions that Python’s runtime silently ignores. These "unraisable exceptions" typically occur in contexts where exceptions cannot be propagated normally—such as during object finalization (`__del__` methods) or in background cleanup operations. Without special handling, such exceptions are lost and can obscure underlying issues in test code.

This subtopic provides mechanisms to intercept these exceptions via Python’s `sys.unraisablehook`, collect their context and tracebacks, and then surface them as warnings during test execution. This ensures that even exceptions ignored by Python’s default mechanisms are visible to users, improving test diagnostics and reliability.

Functionality

The core workflow of unraisable exception management involves:

This approach ensures unraisable exceptions are systematically detected and reported, integrating seamlessly into pytest’s warning and reporting infrastructure.

Key Code Snippets Illustrating Core Steps

**Hook installation on pytest configuration:**

def pytest_configure(config: Config) -> None:
    prev_hook = sys.unraisablehook
    deque = collections.deque()
    config.stash[unraisable_exceptions] = deque
    config.add_cleanup(functools.partial(cleanup, config=config, prev_hook=prev_hook))
    sys.unraisablehook = functools.partial(unraisable_hook, append=deque.append)

**Custom unraisable hook capturing exception metadata:**

def unraisable_hook(unraisable, *, append) -> None:
    msg = ...  # formatted summary + traceback + tracemalloc info
    cause_msg = ...
    append(UnraisableMeta(msg=msg, cause_msg=cause_msg, exc_value=unraisable.exc_value))

**Collecting and emitting warnings for unraisable exceptions:**

def collect_unraisable(config: Config) -> None:
    while True:
        meta = config.stash[unraisable_exceptions].pop()
        warnings.warn(pytest.PytestUnraisableExceptionWarning(meta.msg))

Integration

Unraisable Exception Management integrates tightly with the parent topic of warnings and unraisable exception handling by:

This subtopic introduces a unique mechanism—replacing and managing `sys.unraisablehook`—not covered in other parts of the warnings or exception handling system, providing comprehensive visibility into otherwise silent test failures.

Diagram

sequenceDiagram
    participant Pytest as Pytest Config
    participant Sys as sys.unraisablehook
    participant GC as Garbage Collector
    participant Stash as Unraisable Exception Stash
    participant Warn as Warning System
    participant Test as Test Execution Phases

    Pytest->>Sys: Replace unraisablehook with custom handler
    Note right of Sys: Custom hook captures unraisable exceptions\nadds metadata to stash

    Test->>GC: Trigger garbage collection during cleanup
    GC->>Sys: Finalize objects, unraisable exceptions may occur
    Sys->>Stash: Append exception metadata

    Test->>Pytest: At setup/call/teardown phases
    Pytest->>Stash: Pop collected exceptions
    Pytest->>Warn: Emit PytestUnraisableExceptionWarning for each
    Warn->>User: Display warnings or raise errors if configured

    Pytest->>Sys: Restore original unraisablehook on cleanup

This sequence diagram illustrates how pytest installs a custom unraisable exception hook, collects exceptions during garbage collection and test execution phases, emits warnings for users, and finally restores the original system hook.