Skip to content

Commit 06d7596

Browse files
authored
Merge pull request #10906 from pytest-dev/backport-10904-to-7.3.x
[7.3.x] Revert "Correctly handle tracebackhide for chained exceptions (#10772)"
2 parents 6e26c2b + a4121aa commit 06d7596

File tree

7 files changed

+34
-49
lines changed

7 files changed

+34
-49
lines changed

Diff for: AUTHORS

-1
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,6 @@ Erik M. Bray
128128
Evan Kepner
129129
Fabien Zarifian
130130
Fabio Zadrozny
131-
Felix Hofstätter
132131
Felix Nieuwenhuizen
133132
Feng Ma
134133
Florian Bruhin

Diff for: changelog/10903.bugfix.rst

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix crash ``INTERNALERROR IndexError: list index out of range`` which happens when displaying an exception where all entries are hidden.
2+
This reverts the change "Correctly handle ``__tracebackhide__`` for chained exceptions." introduced in version 7.3.0.

Diff for: doc/en/changelog.rst

+1
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ Bug Fixes
8282

8383

8484
- `#1904 <https://github.com/pytest-dev/pytest/issues/1904>`_: Correctly handle ``__tracebackhide__`` for chained exceptions.
85+
NOTE: This change was reverted in version 7.3.1.
8586

8687

8788

Diff for: src/_pytest/_code/code.py

+10-17
Original file line numberDiff line numberDiff line change
@@ -411,13 +411,13 @@ def filter(
411411
"""
412412
return Traceback(filter(fn, self), self._excinfo)
413413

414-
def getcrashentry(self) -> Optional[TracebackEntry]:
414+
def getcrashentry(self) -> TracebackEntry:
415415
"""Return last non-hidden traceback entry that lead to the exception of a traceback."""
416416
for i in range(-1, -len(self) - 1, -1):
417417
entry = self[i]
418418
if not entry.ishidden():
419419
return entry
420-
return None
420+
return self[-1]
421421

422422
def recursionindex(self) -> Optional[int]:
423423
"""Return the index of the frame/TracebackEntry where recursion originates if
@@ -602,13 +602,11 @@ def errisinstance(
602602
"""
603603
return isinstance(self.value, exc)
604604

605-
def _getreprcrash(self) -> Optional["ReprFileLocation"]:
605+
def _getreprcrash(self) -> "ReprFileLocation":
606606
exconly = self.exconly(tryshort=True)
607607
entry = self.traceback.getcrashentry()
608-
if entry:
609-
path, lineno = entry.frame.code.raw.co_filename, entry.lineno
610-
return ReprFileLocation(path, lineno + 1, exconly)
611-
return None
608+
path, lineno = entry.frame.code.raw.co_filename, entry.lineno
609+
return ReprFileLocation(path, lineno + 1, exconly)
612610

613611
def getrepr(
614612
self,
@@ -946,23 +944,18 @@ def repr_excinfo(
946944
)
947945
else:
948946
reprtraceback = self.repr_traceback(excinfo_)
949-
950-
# will be None if all traceback entries are hidden
951-
reprcrash: Optional[ReprFileLocation] = excinfo_._getreprcrash()
952-
if reprcrash:
953-
if self.style == "value":
954-
repr_chain += [(reprtraceback, None, descr)]
955-
else:
956-
repr_chain += [(reprtraceback, reprcrash, descr)]
947+
reprcrash: Optional[ReprFileLocation] = (
948+
excinfo_._getreprcrash() if self.style != "value" else None
949+
)
957950
else:
958951
# Fallback to native repr if the exception doesn't have a traceback:
959952
# ExceptionInfo objects require a full traceback to work.
960953
reprtraceback = ReprTracebackNative(
961954
traceback.format_exception(type(e), e, None)
962955
)
963956
reprcrash = None
964-
repr_chain += [(reprtraceback, reprcrash, descr)]
965957

958+
repr_chain += [(reprtraceback, reprcrash, descr)]
966959
if e.__cause__ is not None and self.chain:
967960
e = e.__cause__
968961
excinfo_ = (
@@ -1053,7 +1046,7 @@ def toterminal(self, tw: TerminalWriter) -> None:
10531046
@dataclasses.dataclass(eq=False)
10541047
class ReprExceptionInfo(ExceptionRepr):
10551048
reprtraceback: "ReprTraceback"
1056-
reprcrash: Optional["ReprFileLocation"]
1049+
reprcrash: "ReprFileLocation"
10571050

10581051
def toterminal(self, tw: TerminalWriter) -> None:
10591052
self.reprtraceback.toterminal(tw)

Diff for: src/_pytest/reports.py

-4
Original file line numberDiff line numberDiff line change
@@ -347,10 +347,6 @@ def from_item_and_call(cls, item: Item, call: "CallInfo[None]") -> "TestReport":
347347
elif isinstance(excinfo.value, skip.Exception):
348348
outcome = "skipped"
349349
r = excinfo._getreprcrash()
350-
if r is None:
351-
raise ValueError(
352-
"There should always be a traceback entry for skipping a test."
353-
)
354350
if excinfo.value._use_item_location:
355351
path, line = item.reportinfo()[:2]
356352
assert line is not None

Diff for: testing/code/test_excinfo.py

+21-2
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,6 @@ def f():
294294
excinfo = pytest.raises(ValueError, f)
295295
tb = excinfo.traceback
296296
entry = tb.getcrashentry()
297-
assert entry is not None
298297
co = _pytest._code.Code.from_function(h)
299298
assert entry.frame.code.path == co.path
300299
assert entry.lineno == co.firstlineno + 1
@@ -312,7 +311,10 @@ def f():
312311
excinfo = pytest.raises(ValueError, f)
313312
tb = excinfo.traceback
314313
entry = tb.getcrashentry()
315-
assert entry is None
314+
co = _pytest._code.Code.from_function(g)
315+
assert entry.frame.code.path == co.path
316+
assert entry.lineno == co.firstlineno + 2
317+
assert entry.frame.code.name == "g"
316318

317319

318320
def test_excinfo_exconly():
@@ -1573,3 +1575,20 @@ def test_exceptiongroup(pytester: Pytester, outer_chain, inner_chain) -> None:
15731575
# with py>=3.11 does not depend on exceptiongroup, though there is a toxenv for it
15741576
pytest.importorskip("exceptiongroup")
15751577
_exceptiongroup_common(pytester, outer_chain, inner_chain, native=False)
1578+
1579+
1580+
def test_all_entries_hidden_doesnt_crash(pytester: Pytester) -> None:
1581+
"""Regression test for #10903.
1582+
1583+
We're not really sure what should be *displayed* here, so this test
1584+
just verified that at least it doesn't crash.
1585+
"""
1586+
pytester.makepyfile(
1587+
"""
1588+
def test():
1589+
__tracebackhide__ = True
1590+
1 / 0
1591+
"""
1592+
)
1593+
result = pytester.runpytest()
1594+
assert result.ret == 1

Diff for: testing/test_tracebackhide.py

-25
This file was deleted.

0 commit comments

Comments
 (0)