This is an issue when test code verifies that a warning was emitted without specifying its type and without checking its message, or when it uses the overly broad base Warning type without checking the message.

In Python with pytest, this refers to underspecified pytest.warns() usage, such as:

More specific warning types such as UserWarning or DeprecationWarning are not covered by this rule when used without match=.

Omitting the warning type while providing an effective match= is not an issue, because pytest.warns defaults to Warning and the message pattern narrows the expectation.

Why is this an issue?

When testing that code emits a warning, it is not sufficient to verify only that some warning was raised. Tests should also validate the warning type or message to differentiate expected warnings from unexpected ones.

Consider a function that should emit a DeprecationWarning when given a legacy argument. If your test only checks that a warning occurred, it cannot distinguish between:

All three scenarios would make the test pass, even though two represent unintended behavior.

In pytest, the following patterns lead to insufficiently specific warning testing:

The base Warning class is the root of the warning hierarchy and catches every warning subtype. More specific types such as UserWarning or DeprecationWarning are accepted without match=.

Omitting the warning type while providing match= is accepted: pytest.warns defaults to Warning, and the message pattern already narrows the expectation.

These patterns create fragile tests that may pass for the wrong reasons, allowing regressions to slip through undetected.

What is the potential impact?

Tests that underspecify expected warnings can pass when an unrelated warning is emitted, leaving regressions undetected. Narrowing the expected type and message keeps warning tests as a reliable safety net.

How to fix it

Pass a specific warning type to pytest.warns. When using the base Warning type (explicitly or via the default), add match= with a pattern for the message.

Code examples

Noncompliant code example

import warnings
import pytest

def test_warns_without_type():
    with pytest.warns():  # Noncompliant: no expected warning type
        warnings.warn("x", UserWarning)

def test_warns_broad_type():
    with pytest.warns(Warning):  # Noncompliant: base Warning without match=
        warnings.warn("deprecated", DeprecationWarning)

Compliant solution

import warnings
import pytest

def test_warns_without_type():
    with pytest.warns(UserWarning):
        warnings.warn("x", UserWarning)

def test_warns_broad_type():
    # Base Warning is allowed when match= narrows the expected message
    with pytest.warns(Warning, match="deprecated"):
        warnings.warn("deprecated", DeprecationWarning)

def test_warns_match_only():
    # Omitting the type is allowed when match= is provided
    with pytest.warns(match="deprecated"):
        warnings.warn("deprecated", DeprecationWarning)

Resources

Documentation

Related rules