Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ Israël Hallé
Itxaso Aizpurua
Iwan Briquemont
Jaap Broekhuizen
JaeHyuck Sa
Jake VanderPlas
Jakob van Santen
Jakub Mitoraj
Expand Down
1 change: 1 addition & 0 deletions changelog/11225.improvement.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
:func:`pytest.warns` showed "Regex pattern did not match" instead of "DID NOT WARN" when warnings were emitted but the ``match`` pattern did not match.
Comment thread
nicoddemus marked this conversation as resolved.
Outdated
4 changes: 3 additions & 1 deletion doc/en/how-to/capture-warnings.rst
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,9 @@ Some examples:
...
Traceback (most recent call last):
...
Failed: DID NOT WARN. No warnings of type ...UserWarning... were emitted...
Failed: Regex pattern did not match.
Regex: ...
Emitted warnings: ...UserWarning...

>>> with warns(UserWarning, match=re.escape("issue with foo() func")):
... warnings.warn("issue with foo() func")
Expand Down
17 changes: 13 additions & 4 deletions src/_pytest/recwarn.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,9 @@ def warns(
... warnings.warn("this is not here", UserWarning)
Traceback (most recent call last):
...
Failed: DID NOT WARN. No warnings of type ...UserWarning... were emitted...
Failed: Regex pattern did not match.
Regex: ...
Emitted warnings: ...UserWarning...

**Using with** ``pytest.mark.parametrize``

Expand Down Expand Up @@ -321,10 +323,17 @@ def found_str() -> str:
f" Emitted warnings: {found_str()}."
)
elif not any(self.matches(w) for w in self):
escape_hint = ""
if isinstance(self.match_expr, str) and any(
self.match_expr == str(w.message)
for w in self
if issubclass(w.category, self.expected_warning)
):
escape_hint = "\n Did you mean to `re.escape()` the regex?"
fail(
f"DID NOT WARN. No warnings of type {self.expected_warning} matching the regex were emitted.\n"
f" Regex: {self.match_expr}\n"
f" Emitted warnings: {found_str()}."
"Regex pattern did not match.\n"
Comment thread
nicoddemus marked this conversation as resolved.
Outdated
f" Regex: {self.match_expr!r}\n"
f" Emitted warnings: {found_str()}.{escape_hint}"
)
finally:
# Whether or not any warnings matched, we want to re-emit all unmatched warnings.
Expand Down
39 changes: 35 additions & 4 deletions testing/test_recwarn.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,9 @@ def test_deprecated_call_supports_match(self) -> None:
warnings.warn("value must be 42", DeprecationWarning)

with pytest.deprecated_call():
with pytest.raises(pytest.fail.Exception, match="DID NOT WARN"):
with pytest.raises(
pytest.fail.Exception, match="Regex pattern did not match"
):
with pytest.deprecated_call(match=r"must be \d+$"):
warnings.warn("this is not here", DeprecationWarning)

Expand Down Expand Up @@ -406,7 +408,9 @@ def test_match_regex(self) -> None:

def test_one_from_multiple_warns(self) -> None:
with pytest.warns():
with pytest.raises(pytest.fail.Exception, match="DID NOT WARN"):
with pytest.raises(
pytest.fail.Exception, match="Regex pattern did not match"
):
with pytest.warns(UserWarning, match=r"aaa"):
with pytest.warns(UserWarning, match=r"aaa"):
warnings.warn("cccccccccc", UserWarning)
Expand All @@ -415,11 +419,38 @@ def test_one_from_multiple_warns(self) -> None:

def test_none_of_multiple_warns(self) -> None:
with pytest.warns():
with pytest.raises(pytest.fail.Exception, match="DID NOT WARN"):
with pytest.raises(
pytest.fail.Exception, match="Regex pattern did not match"
):
with pytest.warns(UserWarning, match=r"aaa"):
warnings.warn("bbbbbbbbbb", UserWarning)
warnings.warn("cccccccccc", UserWarning)

def test_warns_match_failure_message_detail(self) -> None:
with pytest.warns():
with pytest.raises(pytest.fail.Exception) as excinfo:
with pytest.warns(UserWarning, match=r"must be \d+$"):
warnings.warn("this is not here", UserWarning)
msg = str(excinfo.value)
assert "Regex pattern did not match" in msg
assert "this is not here" in msg
assert "DID NOT WARN" not in msg

def test_warns_match_re_escape_hint(self) -> None:
with pytest.warns():
with pytest.raises(pytest.fail.Exception) as excinfo:
with pytest.warns(UserWarning, match="foo (bar)"):
warnings.warn("foo (bar)", UserWarning)
assert "re.escape()" in str(excinfo.value)

def test_warns_match_re_escape_hint_no_false_positive(self) -> None:
with pytest.warns():
with pytest.raises(pytest.fail.Exception) as excinfo:
with pytest.warns(DeprecationWarning, match="foo (bar)"):
warnings.warn("some deprecation msg", DeprecationWarning)
warnings.warn("foo (bar)", UserWarning)
assert "re.escape()" not in str(excinfo.value)

@pytest.mark.filterwarnings("ignore")
def test_can_capture_previously_warned(self) -> None:
def f() -> int:
Expand Down Expand Up @@ -589,7 +620,7 @@ def __init__(self, a, b):
pass

with pytest.warns(CustomWarning):
with pytest.raises(pytest.fail.Exception, match="DID NOT WARN"):
with pytest.raises(pytest.fail.Exception, match="Regex pattern did not match"):
with pytest.warns(CustomWarning, match="not gonna match"):
a, b = 1, 2
warnings.warn(CustomWarning(a, b))
Loading