code: make TracebackEntry immutable

TracebackEntry being mutable caught me by surprise and makes reasoning
about the exception formatting code harder. Make it a proper value.
This commit is contained in:
Ran Benita 2023-04-12 22:58:57 +03:00
parent 0a20452f78
commit 6f7f89f3c4
3 changed files with 20 additions and 10 deletions

View File

@ -49,6 +49,7 @@ from _pytest.pathlib import absolutepath
from _pytest.pathlib import bestrelpath
if TYPE_CHECKING:
from typing_extensions import Final
from typing_extensions import Literal
from typing_extensions import SupportsIndex
@ -197,18 +198,20 @@ class TracebackEntry:
def __init__(
self,
rawentry: TracebackType,
repr_style: Optional['Literal["short", "long"]'] = None,
) -> None:
self._rawentry = rawentry
self._repr_style: Optional['Literal["short", "long"]'] = None
self._rawentry: "Final" = rawentry
self._repr_style: "Final" = repr_style
def with_repr_style(
self, repr_style: Optional['Literal["short", "long"]']
) -> "TracebackEntry":
return TracebackEntry(self._rawentry, repr_style)
@property
def lineno(self) -> int:
return self._rawentry.tb_lineno - 1
def set_repr_style(self, mode: "Literal['short', 'long']") -> None:
assert mode in ("short", "long")
self._repr_style = mode
@property
def frame(self) -> Frame:
return Frame(self._rawentry.tb_frame)

View File

@ -35,6 +35,7 @@ from _pytest._code import filter_traceback
from _pytest._code import getfslineno
from _pytest._code.code import ExceptionInfo
from _pytest._code.code import TerminalRepr
from _pytest._code.code import Traceback
from _pytest._io import TerminalWriter
from _pytest._io.saferepr import saferepr
from _pytest.compat import ascii_escaped
@ -1819,8 +1820,12 @@ class Function(PyobjMixin, nodes.Item):
# only show a single-line message for each frame.
if self.config.getoption("tbstyle", "auto") == "auto":
if len(excinfo.traceback) > 2:
for entry in excinfo.traceback[1:-1]:
entry.set_repr_style("short")
excinfo.traceback = Traceback(
entry
if i == 0 or i == len(excinfo.traceback) - 1
else entry.with_repr_style("short")
for i, entry in enumerate(excinfo.traceback)
)
# TODO: Type ignored -- breaks Liskov Substitution.
def repr_failure( # type: ignore[override]

View File

@ -1122,8 +1122,10 @@ raise ValueError()
)
excinfo = pytest.raises(ValueError, mod.f)
excinfo.traceback = excinfo.traceback.filter(excinfo)
excinfo.traceback[1].set_repr_style("short")
excinfo.traceback[2].set_repr_style("short")
excinfo.traceback = _pytest._code.Traceback(
entry if i not in (1, 2) else entry.with_repr_style("short")
for i, entry in enumerate(excinfo.traceback)
)
r = excinfo.getrepr(style="long")
r.toterminal(tw_mock)
for line in tw_mock.lines: