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.