Skip to content

Commit b3f3263

Browse files
authored
Clarify regex match error in pytest.raises (#13859)
1 parent 3daf6bf commit b3f3263

File tree

6 files changed

+64
-56
lines changed

6 files changed

+64
-56
lines changed

changelog/13859.improvement.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Clarify the error message for `pytest.raises()` when a regex `match` fails.

src/_pytest/_code/code.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -772,7 +772,11 @@ def match(self, regexp: str | re.Pattern[str]) -> Literal[True]:
772772
"""
773773
__tracebackhide__ = True
774774
value = stringify_exception(self.value)
775-
msg = f"Regex pattern did not match.\n Regex: {regexp!r}\n Input: {value!r}"
775+
msg = (
776+
f"Regex pattern did not match.\n"
777+
f" Expected regex: {regexp!r}\n"
778+
f" Actual message: {value!r}"
779+
)
776780
if regexp == value:
777781
msg += "\n Did you mean to `re.escape()` the regex?"
778782
assert re.search(regexp, value), msg

src/_pytest/raises.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -519,12 +519,10 @@ def _check_match(self, e: BaseException) -> bool:
519519
self._fail_reason = ("\n" if diff[0][0] == "-" else "") + "\n".join(diff)
520520
return False
521521

522-
# I don't love "Regex"+"Input" vs something like "expected regex"+"exception message"
523-
# when they're similar it's not always obvious which is which
524522
self._fail_reason = (
525523
f"Regex pattern did not match{maybe_specify_type}.\n"
526-
f" Regex: {_match_pattern(self.match)!r}\n"
527-
f" Input: {stringified_exception!r}"
524+
f" Expected regex: {_match_pattern(self.match)!r}\n"
525+
f" Actual message: {stringified_exception!r}"
528526
)
529527
if _match_pattern(self.match) == stringified_exception:
530528
self._fail_reason += "\n Did you mean to `re.escape()` the regex?"

testing/code/test_excinfo.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -442,9 +442,9 @@ def test_division_zero():
442442
assert result.ret != 0
443443

444444
match = [
445-
r"E .* AssertionError: Regex pattern did not match.",
446-
r"E .* Regex: '\[123\]\+'",
447-
r"E .* Input: 'division by zero'",
445+
r"E\s+AssertionError: Regex pattern did not match.",
446+
r"E\s+Expected regex: '\[123\]\+'",
447+
r"E\s+Actual message: 'division by zero'",
448448
]
449449
result.stdout.re_match_lines(match)
450450
result.stdout.no_fnmatch_line("*__tracebackhide__ = True*")

testing/python/raises.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -253,8 +253,8 @@ def test_raises_match(self) -> None:
253253
msg = "with base 16"
254254
expr = (
255255
"Regex pattern did not match.\n"
256-
f" Regex: {msg!r}\n"
257-
" Input: \"invalid literal for int() with base 10: 'asdf'\""
256+
f" Expected regex: {msg!r}\n"
257+
f" Actual message: \"invalid literal for int() with base 10: 'asdf'\""
258258
)
259259
with pytest.raises(AssertionError, match="^" + re.escape(expr) + "$"):
260260
with pytest.raises(ValueError, match=msg):
@@ -289,7 +289,10 @@ def test_match_failure_string_quoting(self):
289289
with pytest.raises(AssertionError, match="'foo"):
290290
raise AssertionError("'bar")
291291
(msg,) = excinfo.value.args
292-
assert msg == '''Regex pattern did not match.\n Regex: "'foo"\n Input: "'bar"'''
292+
assert (
293+
msg
294+
== '''Regex pattern did not match.\n Expected regex: "'foo"\n Actual message: "'bar"'''
295+
)
293296

294297
def test_match_failure_exact_string_message(self):
295298
message = "Oh here is a message with (42) numbers in parameters"
@@ -299,8 +302,8 @@ def test_match_failure_exact_string_message(self):
299302
(msg,) = excinfo.value.args
300303
assert msg == (
301304
"Regex pattern did not match.\n"
302-
" Regex: 'Oh here is a message with (42) numbers in parameters'\n"
303-
" Input: 'Oh here is a message with (42) numbers in parameters'\n"
305+
" Expected regex: 'Oh here is a message with (42) numbers in parameters'\n"
306+
" Actual message: 'Oh here is a message with (42) numbers in parameters'\n"
304307
" Did you mean to `re.escape()` the regex?"
305308
)
306309

testing/python/raises_group.py

Lines changed: 45 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -382,8 +382,8 @@ def test_match() -> None:
382382
with (
383383
fails_raises_group(
384384
"Regex pattern did not match the `ExceptionGroup()`.\n"
385-
" Regex: 'foo'\n"
386-
" Input: 'bar'"
385+
" Expected regex: 'foo'\n"
386+
" Actual message: 'bar'"
387387
),
388388
RaisesGroup(ValueError, match="foo"),
389389
):
@@ -396,8 +396,8 @@ def test_match() -> None:
396396
with (
397397
fails_raises_group(
398398
"Regex pattern did not match the `ExceptionGroup()`.\n"
399-
" Regex: 'foo'\n"
400-
" Input: 'bar'\n"
399+
" Expected regex: 'foo'\n"
400+
" Actual message: 'bar'\n"
401401
" but matched the expected `ValueError`.\n"
402402
" You might want `RaisesGroup(RaisesExc(ValueError, match='foo'))`"
403403
),
@@ -570,8 +570,8 @@ def test_assert_message() -> None:
570570
" ExceptionGroup('', [RuntimeError()]):\n"
571571
" RaisesGroup(ValueError): `RuntimeError()` is not an instance of `ValueError`\n"
572572
" RaisesGroup(ValueError, match='a'): Regex pattern did not match the `ExceptionGroup()`.\n"
573-
" Regex: 'a'\n"
574-
" Input: ''\n"
573+
" Expected regex: 'a'\n"
574+
" Actual message: ''\n"
575575
" RuntimeError():\n"
576576
" RaisesGroup(ValueError): `RuntimeError()` is not an exception group\n"
577577
" RaisesGroup(ValueError, match='a'): `RuntimeError()` is not an exception group",
@@ -634,8 +634,8 @@ def test_assert_message() -> None:
634634
fails_raises_group(
635635
# TODO: did not match Exceptiongroup('h(ell)o', ...) ?
636636
"Raised exception group did not match: Regex pattern did not match the `ExceptionGroup()`.\n"
637-
" Regex: 'h(ell)o'\n"
638-
" Input: 'h(ell)o'\n"
637+
" Expected regex: 'h(ell)o'\n"
638+
" Actual message: 'h(ell)o'\n"
639639
" Did you mean to `re.escape()` the regex?",
640640
add_prefix=False, # to see the full structure
641641
),
@@ -645,8 +645,8 @@ def test_assert_message() -> None:
645645
with (
646646
fails_raises_group(
647647
"RaisesExc(match='h(ell)o'): Regex pattern did not match.\n"
648-
" Regex: 'h(ell)o'\n"
649-
" Input: 'h(ell)o'\n"
648+
" Expected regex: 'h(ell)o'\n"
649+
" Actual message: 'h(ell)o'\n"
650650
" Did you mean to `re.escape()` the regex?",
651651
),
652652
RaisesGroup(RaisesExc(match="h(ell)o")),
@@ -799,8 +799,8 @@ def test_suggestion_on_nested_and_brief_error() -> None:
799799
"The following raised exceptions did not find a match\n"
800800
" ExceptionGroup('^hello', [Exception()]):\n"
801801
" RaisesGroup(Exception, match='^hello'): Regex pattern did not match the `ExceptionGroup()`.\n"
802-
" Regex: '^hello'\n"
803-
" Input: '^hello'\n"
802+
" Expected regex: '^hello'\n"
803+
" Actual message: '^hello'\n"
804804
" Did you mean to `re.escape()` the regex?\n"
805805
" Unexpected nested `ExceptionGroup()`, expected `ValueError`"
806806
),
@@ -830,8 +830,8 @@ def test_assert_message_nested() -> None:
830830
" RaisesGroup(ValueError): `TypeError()` is not an instance of `ValueError`\n"
831831
" RaisesGroup(RaisesGroup(ValueError)): RaisesGroup(ValueError): `TypeError()` is not an exception group\n"
832832
" RaisesGroup(RaisesExc(TypeError, match='foo')): RaisesExc(TypeError, match='foo'): Regex pattern did not match.\n"
833-
" Regex: 'foo'\n"
834-
" Input: 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'\n"
833+
" Expected regex: 'foo'\n"
834+
" Actual message: 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'\n"
835835
" RaisesGroup(TypeError, ValueError): 1 matched exception. Too few exceptions raised, found no match for: [ValueError]\n"
836836
" ExceptionGroup('Exceptions from Trio nursery', [TypeError('cccccccccccccccccccccccccccccc'), TypeError('dddddddddddddddddddddddddddddd')]):\n"
837837
" RaisesGroup(ValueError): \n"
@@ -856,12 +856,12 @@ def test_assert_message_nested() -> None:
856856
" The following raised exceptions did not find a match\n"
857857
" TypeError('cccccccccccccccccccccccccccccc'):\n"
858858
" RaisesExc(TypeError, match='foo'): Regex pattern did not match.\n"
859-
" Regex: 'foo'\n"
860-
" Input: 'cccccccccccccccccccccccccccccc'\n"
859+
" Expected regex: 'foo'\n"
860+
" Actual message: 'cccccccccccccccccccccccccccccc'\n"
861861
" TypeError('dddddddddddddddddddddddddddddd'):\n"
862862
" RaisesExc(TypeError, match='foo'): Regex pattern did not match.\n"
863-
" Regex: 'foo'\n"
864-
" Input: 'dddddddddddddddddddddddddddddd'\n"
863+
" Expected regex: 'foo'\n"
864+
" Actual message: 'dddddddddddddddddddddddddddddd'\n"
865865
" RaisesGroup(TypeError, ValueError): \n"
866866
" 1 matched exception. \n"
867867
" The following expected exceptions did not find a match:\n"
@@ -945,8 +945,8 @@ def test_misordering_example() -> None:
945945
" It matches `ValueError` which was paired with `ValueError('foo')`\n"
946946
" It matches `ValueError` which was paired with `ValueError('foo')`\n"
947947
" RaisesExc(ValueError, match='foo'): Regex pattern did not match.\n"
948-
" Regex: 'foo'\n"
949-
" Input: 'bar'\n"
948+
" Expected regex: 'foo'\n"
949+
" Actual message: 'bar'\n"
950950
"There exist a possible match when attempting an exhaustive check, but RaisesGroup uses a greedy algorithm. Please make your expected exceptions more stringent with `RaisesExc` etc so the greedy algorithm can function."
951951
),
952952
RaisesGroup(
@@ -1036,34 +1036,34 @@ def test_identity_oopsies() -> None:
10361036
"The following raised exceptions did not find a match\n"
10371037
" ValueError('foo'):\n"
10381038
" RaisesExc(match='bar'): Regex pattern did not match.\n"
1039-
" Regex: 'bar'\n"
1040-
" Input: 'foo'\n"
1039+
" Expected regex: 'bar'\n"
1040+
" Actual message: 'foo'\n"
10411041
" RaisesExc(match='bar'): Regex pattern did not match.\n"
1042-
" Regex: 'bar'\n"
1043-
" Input: 'foo'\n"
1042+
" Expected regex: 'bar'\n"
1043+
" Actual message: 'foo'\n"
10441044
" RaisesExc(match='bar'): Regex pattern did not match.\n"
1045-
" Regex: 'bar'\n"
1046-
" Input: 'foo'\n"
1045+
" Expected regex: 'bar'\n"
1046+
" Actual message: 'foo'\n"
10471047
" ValueError('foo'):\n"
10481048
" RaisesExc(match='bar'): Regex pattern did not match.\n"
1049-
" Regex: 'bar'\n"
1050-
" Input: 'foo'\n"
1049+
" Expected regex: 'bar'\n"
1050+
" Actual message: 'foo'\n"
10511051
" RaisesExc(match='bar'): Regex pattern did not match.\n"
1052-
" Regex: 'bar'\n"
1053-
" Input: 'foo'\n"
1052+
" Expected regex: 'bar'\n"
1053+
" Actual message: 'foo'\n"
10541054
" RaisesExc(match='bar'): Regex pattern did not match.\n"
1055-
" Regex: 'bar'\n"
1056-
" Input: 'foo'\n"
1055+
" Expected regex: 'bar'\n"
1056+
" Actual message: 'foo'\n"
10571057
" ValueError('foo'):\n"
10581058
" RaisesExc(match='bar'): Regex pattern did not match.\n"
1059-
" Regex: 'bar'\n"
1060-
" Input: 'foo'\n"
1059+
" Expected regex: 'bar'\n"
1060+
" Actual message: 'foo'\n"
10611061
" RaisesExc(match='bar'): Regex pattern did not match.\n"
1062-
" Regex: 'bar'\n"
1063-
" Input: 'foo'\n"
1062+
" Expected regex: 'bar'\n"
1063+
" Actual message: 'foo'\n"
10641064
" RaisesExc(match='bar'): Regex pattern did not match.\n"
1065-
" Regex: 'bar'\n"
1066-
" Input: 'foo'"
1065+
" Expected regex: 'bar'\n"
1066+
" Actual message: 'foo'"
10671067
),
10681068
RaisesGroup(m, m, m),
10691069
):
@@ -1120,7 +1120,9 @@ def test_raisesexc() -> None:
11201120
# currently RaisesGroup says "Raised exception did not match" but RaisesExc doesn't...
11211121
with pytest.raises(
11221122
AssertionError,
1123-
match=wrap_escape("Regex pattern did not match.\n Regex: 'foo'\n Input: 'bar'"),
1123+
match=wrap_escape(
1124+
"Regex pattern did not match.\n Expected regex: 'foo'\n Actual message: 'bar'"
1125+
),
11241126
):
11251127
with RaisesExc(TypeError, match="foo"):
11261128
raise TypeError("bar")
@@ -1132,8 +1134,8 @@ def test_raisesexc_match() -> None:
11321134
with (
11331135
fails_raises_group(
11341136
"RaisesExc(ValueError, match='foo'): Regex pattern did not match.\n"
1135-
" Regex: 'foo'\n"
1136-
" Input: 'bar'"
1137+
" Expected regex: 'foo'\n"
1138+
" Actual message: 'bar'"
11371139
),
11381140
RaisesGroup(RaisesExc(ValueError, match="foo")),
11391141
):
@@ -1145,8 +1147,8 @@ def test_raisesexc_match() -> None:
11451147
with (
11461148
fails_raises_group(
11471149
"RaisesExc(match='foo'): Regex pattern did not match.\n"
1148-
" Regex: 'foo'\n"
1149-
" Input: 'bar'"
1150+
" Expected regex: 'foo'\n"
1151+
" Actual message: 'bar'"
11501152
),
11511153
RaisesGroup(RaisesExc(match="foo")),
11521154
):

0 commit comments

Comments
 (0)