warnings.py
Overview
The `warnings.py` file is a core utility module within the pytest testing framework responsible for **capturing, filtering, recording, and reporting Python warnings** during various phases of a test run. It integrates Python's built-in warnings system with pytest's lifecycle hooks, allowing warnings to be reliably intercepted and emitted as pytest events. This ensures that warnings such as deprecations or runtime alerts are surfaced during test collection, execution, and teardown, improving test diagnostics and user awareness.
Key functionalities include:
A context manager (
catch_warnings_for_item) that captures warnings during specific pytest phases.Application of warning filters from pytest configuration, command-line options, and test markers.
Dispatching of captured warnings through the
pytest_warning_recordedhook.Hook wrappers around pytest lifecycle events to transparently enable warning capture.
Formatting captured warnings as strings for reporting.
Adding the
filterwarningsmarker to pytest’s configuration for test-level filter customization.
This module ensures seamless integration of Python warnings into the pytest ecosystem, improving warning visibility and control.
Detailed Explanations
Function: catch_warnings_for_item
@contextmanager
def catch_warnings_for_item(
config: Config,
ihook,
when: Literal["config", "collect", "runtest"],
item: Item | None,
*,
record: bool = True,
) -> Generator[None]:
Purpose
A context manager that captures Python warnings emitted during a block of code executed within pytest. It applies configured warning filters from pytest ini files, command-line options, and test markers, then records warnings if requested and triggers the `pytest_warning_recorded` hook for each captured warning.
Parameters
config(Config): The pytest configuration object, providing access to ini options and command line arguments.ihook: The pytest hook caller object, used to callpytest_warning_recorded.when(Literal["config", "collect", "runtest"]): A string indicating the pytest phase during which warnings are captured.item(Item | None): The pytest test item context. Can beNoneif not in a test item context (e.g., during collection).record(bool, optional): Whether to record warnings or just apply filters. Defaults toTrue. WhenFalse, warnings are filtered but not recorded.
Returns
A generator context manager that yields control back to the caller while warnings are caught inside.
Usage Example
with catch_warnings_for_item(config, ihook, "runtest", item):
# Code executed here will have warnings captured,
# filtered, and recorded according to configuration
run_test_function()
Implementation Details
Uses
warnings.catch_warnings(record=record)to intercept warnings.If no explicit warning filters are set by the user (
sys.warnoptionsis empty), it enablesDeprecationWarningandPendingDeprecationWarningto always show by default.Applies filters from:
filterwarningsini option in pytest config.Command-line Python warnings options.
filterwarningsmarkers on the test item (if any).
After the wrapped block finishes, if recording is enabled, calls the
pytest_warning_recordedhook for each captured warning, passing metadata such as warning message, node ID, and phase.
Function: warning_record_to_str
def warning_record_to_str(warning_message: warnings.WarningMessage) -> str:
Purpose
Converts a captured `warnings.WarningMessage` object into a formatted string suitable for terminal output or logging, including traceback memory allocation info if available.
Parameters
warning_message(warnings.WarningMessage): The warning message object captured by Python's warnings module.
Returns
str: A formatted string containing the warning message, category, filename, line number, code line, and any tracemalloc information.
Usage Example
formatted_warning = warning_record_to_str(warning_message)
print(formatted_warning)
Hook Wrapper: pytest_runtest_protocol
@pytest.hookimpl(wrapper=True, tryfirst=True)
def pytest_runtest_protocol(item: Item) -> Generator[None, object, object]:
Purpose
Wraps the test execution phase (`runtest`) in the `catch_warnings_for_item` context manager to capture warnings emitted during individual test execution.
Parameters
item(Item): The test item being executed.
Returns
A generator yielding control back to pytest’s runtest protocol machinery.
Usage
Automatically called by pytest during test execution; test authors do not call this directly.
Hook Wrapper: pytest_collection
@pytest.hookimpl(wrapper=True, tryfirst=True)
def pytest_collection(session: Session) -> Generator[None, object, object]:
Purpose
Wraps the test collection phase in the `catch_warnings_for_item` context manager to capture warnings emitted during test discovery.
Parameters
session(Session): The pytest test session object.
Returns
A generator yielding control back to pytest collection machinery.
Hook Wrappers: pytest_terminal_summary, pytest_sessionfinish, pytest_load_initial_conftests
These hooks similarly wrap their respective pytest phases (`terminal_summary`, `sessionfinish`, `load_initial_conftests`) in the warning capture context, ensuring warnings emitted late in the test lifecycle are captured and reported.
Function: pytest_configure
def pytest_configure(config: Config) -> None:
Purpose
Performs pytest configuration initialization related to warnings:
Adds the
filterwarningsmarker to pytest’s known markers with an explanatory message.Sets up a non-recording warning capture context for config cleanup phases.
Registers a cleanup callback to close the warning capture context properly.
Parameters
config(Config): The pytest configuration object.
Important Implementation Details and Algorithms
Dynamic Warning Filters Application: Filters are sourced from multiple places in order of precedence:
filterwarningsini options (config.getini("filterwarnings"))Command-line warning filters (
config.known_args_namespace.pythonwarnings)@pytest.mark.filterwarningsmarkers attached to test items.
Default Filters for Deprecations: When users have not specified any Python warning configurations (
sys.warnoptionsis empty), pytest forcesDeprecationWarningandPendingDeprecationWarningto always trigger to improve visibility.Warning Recording and Hook Emission: Captured warnings are recorded in a list by
warnings.catch_warnings(record=True). After the wrapped block completes, each warning is passed to the pytest warning recording hookpytest_warning_recorded.Hook Wrapping Pattern: The file uses pytest’s
@hookimpl(wrapper=True, tryfirst=True)decorator to wrap lifecycle hooks, injecting warning capture without altering their normal behavior.Marker-based Filtering: Test authors can add fine-grained warning filters using the
filterwarningsmarker on tests, allowing per-test control over warnings.Non-recording Context for Late Phases: For phases like config cleanup, recording is disabled to avoid issues with reporting after terminal output has finished, but filters are still applied.
Interaction with Other Parts of the System
ConfigandSessionObjects: Access pytest configuration and session information to determine warning filters and hook callers.ItemObjects: Provide test item context for per-test warning filtering and reporting.Pytest Hooks (
pytest_warning_recorded): Captured warnings are dispatched through this hook, allowing reporting plugins to consume and show warnings.Warning Filters Utilities: Uses internal pytest functions
apply_warning_filtersandparse_warning_filterto parse and apply filters from various sources.Terminal Reporting: Works alongside pytest’s
TerminalReporterto ensure warnings are surfaced in terminal summaries.Traceback Memory Profiling (
tracemalloc_message): Augments warnings with memory allocation information for improved diagnostics.
Visual Diagram: Class and Function Structure
flowchart TD
A[catch_warnings_for_item] -->|uses| B[warnings.catch_warnings]
A --> C[apply_warning_filters]
A --> D[pytest_warning_recorded hook]
E[pytest_runtest_protocol] -->|wraps with| A
F[pytest_collection] -->|wraps with| A
G[pytest_terminal_summary] -->|wraps with| A
H[pytest_sessionfinish] -->|wraps with| A
I[pytest_load_initial_conftests] -->|wraps with| A
J[pytest_configure] -->|adds filterwarnings marker and sets up non-recording context| A
K[warning_record_to_str] -->|formats| L[warnings.WarningMessage]
subgraph Warnings Handling
A
K
end
subgraph Pytest Hooks Wrappers
E
F
G
H
I
J
end
Summary
The `warnings.py` file provides pytest with a robust mechanism to **capture, filter, record, and report Python warnings** during test execution. By wrapping core pytest lifecycle hooks with a specialized context manager, it ensures that warnings are not lost but instead processed according to user configuration and test-specific markers. The integration with pytest’s hook system allows flexible reporting and further processing by plugins. Additionally, it enhances warning messages with memory tracing data for improved diagnostics. This module is essential for maintaining high code quality and developer awareness by making runtime warnings visible and actionable within pytest.
Appendix: Example Usage in Tests
Although the functions in this file are mostly internal to pytest, users can benefit from the `filterwarnings` marker added by `pytest_configure`:
import pytest
@pytest.mark.filterwarnings("ignore::DeprecationWarning")
def test_deprecated_usage():
import warnings
warnings.warn("deprecated feature used", DeprecationWarning)
# This warning will be ignored due to the marker
This marker allows per-test customization of which warnings are filtered, complementing global configuration.