Skip to content

Commit 2b05faf

Browse files
committed
Improve types around repr_failure()
1 parent 54ad048 commit 2b05faf

File tree

6 files changed

+31
-15
lines changed

6 files changed

+31
-15
lines changed

src/_pytest/_code/code.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
from typing_extensions import Literal
4848
from weakref import ReferenceType
4949

50-
_TracebackStyle = Literal["long", "short", "line", "no", "native", "value"]
50+
_TracebackStyle = Literal["long", "short", "line", "no", "native", "value", "auto"]
5151

5252

5353
class Code:

src/_pytest/doctest.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,10 @@ def _disable_output_capturing_for_darwin(self) -> None:
300300
sys.stdout.write(out)
301301
sys.stderr.write(err)
302302

303-
def repr_failure(self, excinfo):
303+
# TODO: Type ignored -- breaks Liskov Substitution.
304+
def repr_failure( # type: ignore[override] # noqa: F821
305+
self, excinfo: ExceptionInfo[BaseException],
306+
) -> Union[str, TerminalRepr]:
304307
import doctest
305308

306309
failures = (

src/_pytest/nodes.py

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,8 @@
1717

1818
import _pytest._code
1919
from _pytest._code import getfslineno
20-
from _pytest._code.code import ExceptionChainRepr
2120
from _pytest._code.code import ExceptionInfo
22-
from _pytest._code.code import ReprExceptionInfo
21+
from _pytest._code.code import TerminalRepr
2322
from _pytest.compat import cached_property
2423
from _pytest.compat import overload
2524
from _pytest.compat import TYPE_CHECKING
@@ -29,7 +28,6 @@
2928
from _pytest.deprecated import NODE_USE_FROM_PARENT
3029
from _pytest.fixtures import FixtureDef
3130
from _pytest.fixtures import FixtureLookupError
32-
from _pytest.fixtures import FixtureLookupErrorRepr
3331
from _pytest.mark.structures import Mark
3432
from _pytest.mark.structures import MarkDecorator
3533
from _pytest.mark.structures import NodeKeywords
@@ -43,6 +41,7 @@
4341
# Imported here due to circular import.
4442
from _pytest.main import Session
4543
from _pytest.warning_types import PytestWarning
44+
from _pytest._code.code import _TracebackStyle
4645

4746

4847
SEP = "/"
@@ -355,8 +354,10 @@ def _prunetraceback(self, excinfo):
355354
pass
356355

357356
def _repr_failure_py(
358-
self, excinfo: ExceptionInfo[BaseException], style=None,
359-
) -> Union[str, ReprExceptionInfo, ExceptionChainRepr, FixtureLookupErrorRepr]:
357+
self,
358+
excinfo: ExceptionInfo[BaseException],
359+
style: "Optional[_TracebackStyle]" = None,
360+
) -> TerminalRepr:
360361
if isinstance(excinfo.value, ConftestImportFailure):
361362
excinfo = ExceptionInfo(excinfo.value.excinfo)
362363
if isinstance(excinfo.value, fail.Exception):
@@ -406,8 +407,10 @@ def _repr_failure_py(
406407
)
407408

408409
def repr_failure(
409-
self, excinfo, style=None
410-
) -> Union[str, ReprExceptionInfo, ExceptionChainRepr, FixtureLookupErrorRepr]:
410+
self,
411+
excinfo: ExceptionInfo[BaseException],
412+
style: "Optional[_TracebackStyle]" = None,
413+
) -> Union[str, TerminalRepr]:
411414
"""
412415
Return a representation of a collection or test failure.
413416
@@ -453,13 +456,16 @@ def collect(self) -> Iterable[Union["Item", "Collector"]]:
453456
"""
454457
raise NotImplementedError("abstract")
455458

456-
def repr_failure(self, excinfo):
459+
# TODO: This omits the style= parameter which breaks Liskov Substitution.
460+
def repr_failure( # type: ignore[override] # noqa: F821
461+
self, excinfo: ExceptionInfo[BaseException]
462+
) -> Union[str, TerminalRepr]:
457463
"""
458464
Return a representation of a collection failure.
459465
460466
:param excinfo: Exception information for the failure.
461467
"""
462-
if excinfo.errisinstance(self.CollectError) and not self.config.getoption(
468+
if isinstance(excinfo.value, self.CollectError) and not self.config.getoption(
463469
"fulltrace", False
464470
):
465471
exc = excinfo.value

src/_pytest/python.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
from _pytest.outcomes import fail
6161
from _pytest.outcomes import skip
6262
from _pytest.pathlib import parts
63+
from _pytest.reports import TerminalRepr
6364
from _pytest.warning_types import PytestCollectionWarning
6465
from _pytest.warning_types import PytestUnhandledCoroutineWarning
6566

@@ -1591,7 +1592,10 @@ def _prunetraceback(self, excinfo: ExceptionInfo) -> None:
15911592
for entry in excinfo.traceback[1:-1]:
15921593
entry.set_repr_style("short")
15931594

1594-
def repr_failure(self, excinfo, outerr=None):
1595+
# TODO: Type ignored -- breaks Liskov Substitution.
1596+
def repr_failure( # type: ignore[override] # noqa: F821
1597+
self, excinfo: ExceptionInfo[BaseException], outerr: None = None
1598+
) -> Union[str, TerminalRepr]:
15951599
assert outerr is None, "XXX outerr usage is deprecated"
15961600
style = self.config.getoption("tbstyle", "auto")
15971601
if style == "auto":

src/_pytest/runner.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import bdb
33
import os
44
import sys
5+
from typing import Any
56
from typing import Callable
67
from typing import cast
78
from typing import Dict
@@ -256,7 +257,7 @@ class CallInfo(Generic[_T]):
256257
"""
257258

258259
_result = attr.ib(type="Optional[_T]")
259-
excinfo = attr.ib(type=Optional[ExceptionInfo])
260+
excinfo = attr.ib(type=Optional[ExceptionInfo[BaseException]])
260261
start = attr.ib(type=float)
261262
stop = attr.ib(type=float)
262263
duration = attr.ib(type=float)
@@ -313,7 +314,8 @@ def pytest_runtest_makereport(item: Item, call: CallInfo[None]) -> TestReport:
313314

314315
def pytest_make_collect_report(collector: Collector) -> CollectReport:
315316
call = CallInfo.from_call(lambda: list(collector.collect()), "collect")
316-
longrepr = None
317+
# TODO: Better typing for longrepr.
318+
longrepr = None # type: Optional[Any]
317319
if not call.excinfo:
318320
outcome = "passed" # type: Literal["passed", "skipped", "failed"]
319321
else:

src/_pytest/skipping.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,8 @@ def pytest_runtest_makereport(item: Item, call: CallInfo[None]):
148148

149149
elif item.config.option.runxfail:
150150
pass # don't interfere
151-
elif call.excinfo and call.excinfo.errisinstance(xfail.Exception):
151+
elif call.excinfo and isinstance(call.excinfo.value, xfail.Exception):
152+
assert call.excinfo.value.msg is not None
152153
rep.wasxfail = "reason: " + call.excinfo.value.msg
153154
rep.outcome = "skipped"
154155
elif evalxfail and not rep.skipped and evalxfail.wasvalid() and evalxfail.istrue():

0 commit comments

Comments
 (0)