Skip to content

Commit a98d093

Browse files
authored
improve raisesgroup code coverage (#13275)
* improve raisesgroup code coverage * fix coverage of a weird branch in python_api, explicitify match in other test * remove comment
1 parent 31d64fc commit a98d093

File tree

4 files changed

+43
-19
lines changed

4 files changed

+43
-19
lines changed

src/_pytest/_code/code.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -470,7 +470,8 @@ def stringify_exception(
470470
HTTPError = getattr(sys.modules.get("urllib.error", None), "HTTPError", ())
471471
if sys.version_info < (3, 12) and isinstance(exc, HTTPError):
472472
notes = []
473-
else:
473+
else: # pragma: no cover
474+
# exception not related to above bug, reraise
474475
raise
475476
if not include_subexception_msg and isinstance(exc, BaseExceptionGroup):
476477
message = exc.message

src/_pytest/raises_group.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,6 @@ def _parse_exc(
213213
self.is_baseexception = True
214214
return cast(type[BaseExcT_1], origin_exc)
215215
else:
216-
# I kinda think this should be a TypeError...
217216
raise ValueError(
218217
f"Only `ExceptionGroup[Exception]` or `BaseExceptionGroup[BaseExeption]` "
219218
f"are accepted as generic types but got `{exc}`. "
@@ -424,11 +423,6 @@ def __enter__(self) -> ExceptionInfo[BaseExcT_co_default]:
424423
self.excinfo: ExceptionInfo[BaseExcT_co_default] = ExceptionInfo.for_later()
425424
return self.excinfo
426425

427-
def expected_type(self) -> str:
428-
if self.expected_exceptions == ():
429-
return "BaseException"
430-
return _exception_type_name(self.expected_exceptions)
431-
432426
# TODO: move common code into superclass
433427
def __exit__(
434428
self,

testing/python/raises.py

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,19 @@ def test_raises_does_not_allow_none(self):
3636
# so we can ignore Mypy telling us that None is invalid.
3737
pytest.raises(expected_exception=None) # type: ignore
3838

39+
# it's unclear if this message is helpful, and if it is, should it trigger more
40+
# liberally? Usually you'd get a TypeError here
41+
def test_raises_false_and_arg(self):
42+
with pytest.raises(
43+
ValueError,
44+
match=wrap_escape(
45+
"Expected an exception type or a tuple of exception types, but got `False`. "
46+
"Raising exceptions is already understood as failing the test, so you don't need "
47+
"any special code to say 'this should never raise an exception'."
48+
),
49+
):
50+
pytest.raises(False, int) # type: ignore[call-overload]
51+
3952
def test_raises_does_not_allow_empty_tuple(self):
4053
with pytest.raises(
4154
ValueError,
@@ -219,7 +232,7 @@ def __call__(self):
219232
elif method == "with_group":
220233
with pytest.RaisesGroup(ValueError, allow_unwrapped=True):
221234
t()
222-
else:
235+
else: # pragma: no cover
223236
raise AssertionError("bad parametrization")
224237

225238
# ensure both forms of pytest.raises don't leave exceptions in sys.exc_info()
@@ -337,10 +350,15 @@ def __class__(self):
337350
def test_raises_context_manager_with_kwargs(self):
338351
with pytest.raises(expected_exception=ValueError):
339352
raise ValueError
340-
with pytest.raises(TypeError) as excinfo:
353+
with pytest.raises(
354+
TypeError,
355+
match=wrap_escape(
356+
"Unexpected keyword arguments passed to pytest.raises: foo\n"
357+
"Use context-manager form instead?"
358+
),
359+
):
341360
with pytest.raises(OSError, foo="bar"): # type: ignore[call-overload]
342361
pass
343-
assert "Unexpected keyword arguments" in str(excinfo.value)
344362

345363
def test_expected_exception_is_not_a_baseexception(self) -> None:
346364
with pytest.raises(TypeError) as excinfo:

testing/python/raises_group.py

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -458,12 +458,16 @@ def my_check(e: object) -> bool: # pragma: no cover
458458
assert RaisesGroup(ValueError, match="bar").matches(exc.value)
459459

460460

461-
def test_RaisesGroup_matches() -> None:
461+
def test_matches() -> None:
462462
rg = RaisesGroup(ValueError)
463463
assert not rg.matches(None)
464464
assert not rg.matches(ValueError())
465465
assert rg.matches(ExceptionGroup("", (ValueError(),)))
466466

467+
re = RaisesExc(ValueError)
468+
assert not re.matches(None)
469+
assert re.matches(ValueError())
470+
467471

468472
def test_message() -> None:
469473
def check_message(
@@ -884,11 +888,13 @@ def test_assert_message_nested() -> None:
884888
)
885889

886890

891+
# CI always runs with hypothesis, but this is not a critical test - it overlaps
892+
# with several others
887893
@pytest.mark.skipif(
888894
"hypothesis" in sys.modules,
889895
reason="hypothesis may have monkeypatched _check_repr",
890896
)
891-
def test_check_no_patched_repr() -> None:
897+
def test_check_no_patched_repr() -> None: # pragma: no cover
892898
# We make `_check_repr` monkeypatchable to avoid this very ugly and verbose
893899
# repr. The other tests that use `check` make use of `_check_repr` so they'll
894900
# continue passing in case it is patched - but we have this one test that
@@ -1288,15 +1294,20 @@ def test_parametrizing_conditional_raisesgroup(
12881294
def test_annotated_group() -> None:
12891295
# repr depends on if exceptiongroup backport is being used or not
12901296
t = repr(ExceptionGroup[ValueError])
1291-
fail_msg = wrap_escape(
1292-
f"Only `ExceptionGroup[Exception]` or `BaseExceptionGroup[BaseExeption]` are accepted as generic types but got `{t}`. As `raises` will catch all instances of the specified group regardless of the generic argument specific nested exceptions has to be checked with `RaisesGroup`."
1293-
)
1297+
msg = "Only `ExceptionGroup[Exception]` or `BaseExceptionGroup[BaseExeption]` are accepted as generic types but got `{}`. As `raises` will catch all instances of the specified group regardless of the generic argument specific nested exceptions has to be checked with `RaisesGroup`."
1298+
1299+
fail_msg = wrap_escape(msg.format(t))
12941300
with pytest.raises(ValueError, match=fail_msg):
1295-
with RaisesGroup(ExceptionGroup[ValueError]):
1296-
... # pragma: no cover
1301+
RaisesGroup(ExceptionGroup[ValueError])
12971302
with pytest.raises(ValueError, match=fail_msg):
1298-
with RaisesExc(ExceptionGroup[ValueError]):
1299-
... # pragma: no cover
1303+
RaisesExc(ExceptionGroup[ValueError])
1304+
with pytest.raises(
1305+
ValueError,
1306+
match=wrap_escape(msg.format(repr(BaseExceptionGroup[KeyboardInterrupt]))),
1307+
):
1308+
with RaisesExc(BaseExceptionGroup[KeyboardInterrupt]):
1309+
raise BaseExceptionGroup("", [KeyboardInterrupt()])
1310+
13001311
with RaisesGroup(ExceptionGroup[Exception]):
13011312
raise ExceptionGroup(
13021313
"", [ExceptionGroup("", [ValueError(), ValueError(), ValueError()])]

0 commit comments

Comments
 (0)