Efficent 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.

Martin Mahner

About the author

Martin Mahner

Martin is an active member and contributor to the Django community where he is mostly known as bartTC. It's likely that you have stumbled over one of his apps or snippets. Besides coding, Martin also has …

View Martin's profile