Never Disable Warnings in Pytest
You silenced the warning that predicted your outage. It's a common move: the test run gets noisy, someone (or some AI agent) adds --disable-warnings or -p no:warnings to the config, and the output goes clean. The warnings didn't go away — you just stopped being told about them.
Why pytest shows warnings at all
Python itself ignores DeprecationWarning by default unless the code triggering it lives in __main__ — library authors warn you, and the interpreter swallows it. Pytest deliberately reverses this: since version 3.1 it captures warnings during test execution and prints a summary at the end of the session, including DeprecationWarning and PendingDeprecationWarning from your code and the libraries you call.
That's not noise. That's the one place in your workflow where deprecations are guaranteed to surface. A deprecation warning is a library author telling you, one release early, exactly which of your call sites will break on the next upgrade. Silence the channel and the first time you hear about it is a stack trace — possibly in production, possibly during an urgent security update you can't delay.
The blanket switches — and what they actually do
| Switch | What it does | Verdict |
|---|---|---|
--disable-warnings | Suppresses the warning summary from the run output | The docs themselves say it's not recommended |
-p no:warnings | Disables pytest's warning capture entirely | Same problem, more thorough |
filterwarnings = ignore | Ignores every warning via config | Blanket blindness, but at least visible in the repo |
filterwarnings = error | Turns warnings into test failures | The strict default worth aspiring to |
This matters double when an AI coding agent maintains your config. "Make the tests pass cleanly" is exactly the kind of instruction that tempts an agent to add a blanket suppression — it satisfies the request and hides the cost. Review any diff that touches filterwarnings, addopts, or warning plugins like any other production change.
Filter with a scalpel, not a switch
Pytest's filterwarnings ini option takes the same filter grammar as Python's warnings module, and when a warning matches multiple lines, the last match wins. That ordering is the whole trick — start strict, then carve out only what you've triaged:
[pytest]
filterwarnings =
error
ignore::UserWarning
ignore:function ham\(\) is deprecated:DeprecationWarning
Line 1 promotes every warning to an error, so new deprecations fail the build the day they appear. Lines 2–3 are deliberate, reviewable exceptions: a specific category, or a specific message regex from one dependency you've already filed an issue against. Every ignore line in the config is a documented decision, not a shrug.
For a one-test exception, keep the scope even tighter with the mark: @pytest.mark.filterwarnings("ignore:api v1:DeprecationWarning").
Power moves
- Assert the warning. When your own code deprecates something, test the deprecation itself with
pytest.warns(DeprecationWarning)— the warning becomes a contract, not clutter. - Know your flags apart.
-W/--pythonwarningson the CLI matches messages literally, while thefilterwarningsini option treats them as regex patterns. Copy-pasting between the two silently changes what gets filtered. - Ratchet, don't leap. On a legacy suite,
erroron day one can mean hundreds of failures. Adderror, then temporarilyignorethe current offenders as explicit lines, and delete one line per week. The list only shrinks. - Budget the noise. If a run prints 300 warnings, count the distinct sources — it's usually 3–5 upgrade tasks, not 300 problems.
Resources
- How to capture warnings — pytest docs
filterwarningsini option — pytest referencepytest.mark.filterwarnings— pytest referencepytest.warns— pytest reference- The
warningsmodule — Python docs
Building an AI-assisted engineering workflow? Yeda AI designs, audits, and ships production LLM systems.