Skip to content
Elephant House Logo

March 25, 2026

Efficient Filtering of Third-Party Deprecation Warnings in pytest

If you’ve spent any time maintaining a Python project with a non-trivial dependency tree, you’ve probably accumulated a filterwarnings block full of one-off ignore patterns — one for ninja_extra, one for asyncio, one for some SWIG-generated type you’ve never heard of. It works, but every new dependency potentially adds another line. There’s a cleaner approach.

The Problem with Per-Warning Suppression

The traditional pattern looks like this:

# pyproject.toml
[tool.pytest.ini_options]
filterwarnings = [
    "ignore:get_api_controller\\(\\) is deprecated:DeprecationWarning",
    "ignore:'asyncio.iscoroutinefunction' is deprecated:DeprecationWarning",
    "ignore:builtin type SwigPyPacked has no __module__ attribute:DeprecationWarning",
    "ignore:pathlib.PurePath.as_uri\\(\\) is deprecated:DeprecationWarning",
]

Each new third-party deprecation requires a new entry. You’re also making a judgment call every time: is this warning something we need to act on, or is it upstream noise that’ll be fixed in a future release of that library? Manually tracking that distinction doesn’t scale.

A Two-Rule Filter

pytest processes filterwarnings top-to-bottom, with the last matching rule winning. That behavior makes a two-rule approach possible:

[tool.pytest.ini_options]
filterwarnings = [
    # Suppress all DeprecationWarnings by default (covers third-party noise)
    "ignore::DeprecationWarning",
    # Treat DeprecationWarnings originating from our own code as errors
    "error::DeprecationWarning:myproject",
]

The filter string format is action:message_regex:category:module_regex. The :myproject at the end of rule 2 matches any warning whose origin module starts with myproject. Since last match wins, third-party warnings stop at rule 1 and warnings from your own code are overridden by rule 2 and fail the test.

Trade-offs

This approach silences all third-party DeprecationWarnings, including ones that might indicate an upcoming breaking change in a dependency you need to handle. If you want to stay informed about a specific library’s deprecations, you can add a targeted error rule before the blanket ignore:

filterwarnings = [
    "error::DeprecationWarning:some_library_you_track",
    "ignore::DeprecationWarning",
    "error::DeprecationWarning:myproject",
]

This isn’t the right fit for every project, but for codebases with large, stable dependency trees where third-party deprecation noise is common, it significantly reduces filter maintenance overhead while keeping your own code accountable.

Conclusion: Two lines replace an unbounded list of per-warning suppressions, and new third-party deprecations are silenced automatically — without any action required on your end.

See all thoughts