Warnings and Unraisable Exception Handling

This module provides comprehensive support for capturing, recording, filtering, and reporting Python warnings and unraisable exceptions during test runs. It ensures that warnings and exceptions that are normally difficult to detect or manage are surfaced in a controlled and user-friendly manner within the pytest testing lifecycle. This enhances test diagnostics and helps maintain code quality by making deprecations, runtime warnings, and unraisable exceptions visible and actionable.


Core Concepts and Purpose

Why This Module Exists


How the Module Works

Warning Capture and Assertion

Example usage of the `recwarn` fixture:

def test_myfunc(recwarn):
    import warnings
    warnings.warn("deprecated", DeprecationWarning)
    w = recwarn.pop(DeprecationWarning)
    assert "deprecated" in str(w.message)

Unraisable Exception Management

Warning Filters and Reporting


Interactions with Other Parts of the System


Important Concepts and Design Patterns


Code References

Warning Capture Context Manager

@contextmanager
def catch_warnings_for_item(
    config: Config,
    ihook,
    when: Literal["config", "collect", "runtest"],
    item: Item | None,
    *,
    record: bool = True,
) -> Generator[None]:
    ...
    with warnings.catch_warnings(record=record) as log:
        ...
        yield
    ...
    for warning_message in log:
        ihook.pytest_warning_recorded.call_historic(...)

This is used as a wrapper around test collection, execution, and reporting phases to catch warnings.

Unraisable Exception Hook Override

def unraisable_hook(
    unraisable: sys.UnraisableHookArgs,
    /,
    *,
    append: Callable[[UnraisableMeta | BaseException], object],
) -> None:
    ...
    append(
        UnraisableMeta(
            msg=msg,
            cause_msg=cause_msg,
            exc_value=unraisable.exc_value,
        )
    )

This function replaces `sys.unraisablehook` to capture unraisable exceptions into a pytest stash queue.

WarningsRecorder Fixture Usage

@fixture
def recwarn() -> Generator[WarningsRecorder]:
    wrec = WarningsRecorder(_ispytest=True)
    with wrec:
        warnings.simplefilter("default")
        yield wrec

Test functions can use the `recwarn` fixture to record and assert warnings explicitly.


Visual Diagram: Warning and Unraisable Exception Handling Workflow

sequenceDiagram
    participant TestRunner as Pytest Test Runner
    participant WarningSys as Python Warnings System
    participant UnraisableHook as sys.unraisablehook
    participant PytestHooks as Pytest Hooks
    participant Stash as Pytest Stash Storage
    participant Reporter as Reporting Plugins

    TestRunner->>WarningSys: Enter catch_warnings_for_item context
    WarningSys-->>TestRunner: Capture warnings emitted during test phases
    TestRunner->>PytestHooks: Yield to wrapped pytest hook (e.g., runtest, collection)
    PytestHooks->>WarningSys: Emit warnings inside hook
    WarningSys-->>PytestHooks: Warnings recorded in log
    TestRunner->>Reporter: Call pytest_warning_recorded hook for each warning

    Note over UnraisableHook,Stash: Unraisable exception occurs at any time
    UnraisableHook->>Stash: Append unraisable exception metadata
    TestRunner->>Stash: On test setup/call/teardown phases
    Stash->>WarningSys: Process and convert unraisable exceptions to warnings
    WarningSys->>Reporter: Emit warnings for unraisable exceptions

    TestRunner->>WarningSys: Exit catch_warnings_for_item context
    WarningSys-->>TestRunner: Restore original warning filters

This diagram illustrates the flow of warning capture during test execution and the interception and processing of unraisable exceptions within pytest.


This documentation covers the fundamental mechanisms by which pytest captures, records, filters, asserts, and reports Python warnings and unraisable exceptions, integrating these into the test lifecycle to provide enhanced visibility and control over runtime warnings and exceptional conditions.