Skip to content

Commit b11bfa1

Browse files
blueyedbluetech
andauthored
Use attrs with all Repr classes (#6739)
Co-authored-by: Ran Benita <[email protected]>
1 parent bd7e332 commit b11bfa1

File tree

3 files changed

+35
-43
lines changed

3 files changed

+35
-43
lines changed

src/_pytest/_code/code.py

+30-38
Original file line numberDiff line numberDiff line change
@@ -789,9 +789,9 @@ def repr_traceback_entry(
789789
else:
790790
message = excinfo and excinfo.typename or ""
791791
path = self._makepath(entry.path)
792-
filelocrepr = ReprFileLocation(path, entry.lineno + 1, message)
792+
reprfileloc = ReprFileLocation(path, entry.lineno + 1, message)
793793
localsrepr = self.repr_locals(entry.locals)
794-
return ReprEntry(lines, reprargs, localsrepr, filelocrepr, style)
794+
return ReprEntry(lines, reprargs, localsrepr, reprfileloc, style)
795795
if excinfo:
796796
lines.extend(self.get_exconly(excinfo, indent=4))
797797
return ReprEntry(lines, None, None, None, style)
@@ -911,6 +911,7 @@ def repr_excinfo(self, excinfo: ExceptionInfo) -> "ExceptionChainRepr":
911911
return ExceptionChainRepr(repr_chain)
912912

913913

914+
@attr.s
914915
class TerminalRepr:
915916
def __str__(self) -> str:
916917
# FYI this is called from pytest-xdist's serialization of exception
@@ -927,8 +928,9 @@ def toterminal(self, tw: TerminalWriter) -> None:
927928
raise NotImplementedError()
928929

929930

931+
@attr.s
930932
class ExceptionRepr(TerminalRepr):
931-
def __init__(self) -> None:
933+
def __attrs_post_init__(self):
932934
self.sections = [] # type: List[Tuple[str, str, str]]
933935

934936
def addsection(self, name: str, content: str, sep: str = "-") -> None:
@@ -940,19 +942,20 @@ def toterminal(self, tw: TerminalWriter) -> None:
940942
tw.line(content)
941943

942944

945+
@attr.s
943946
class ExceptionChainRepr(ExceptionRepr):
944-
def __init__(
945-
self,
946-
chain: Sequence[
947+
chain = attr.ib(
948+
type=Sequence[
947949
Tuple["ReprTraceback", Optional["ReprFileLocation"], Optional[str]]
948-
],
949-
) -> None:
950-
super().__init__()
951-
self.chain = chain
950+
]
951+
)
952+
953+
def __attrs_post_init__(self):
954+
super().__attrs_post_init__()
952955
# reprcrash and reprtraceback of the outermost (the newest) exception
953956
# in the chain
954-
self.reprtraceback = chain[-1][0]
955-
self.reprcrash = chain[-1][1]
957+
self.reprtraceback = self.chain[-1][0]
958+
self.reprcrash = self.chain[-1][1]
956959

957960
def toterminal(self, tw: TerminalWriter) -> None:
958961
for element in self.chain:
@@ -963,13 +966,10 @@ def toterminal(self, tw: TerminalWriter) -> None:
963966
super().toterminal(tw)
964967

965968

969+
@attr.s
966970
class ReprExceptionInfo(ExceptionRepr):
967-
def __init__(
968-
self, reprtraceback: "ReprTraceback", reprcrash: "ReprFileLocation"
969-
) -> None:
970-
super().__init__()
971-
self.reprtraceback = reprtraceback
972-
self.reprcrash = reprcrash
971+
reprtraceback = attr.ib(type="ReprTraceback")
972+
reprcrash = attr.ib(type="ReprFileLocation")
973973

974974
def toterminal(self, tw: TerminalWriter) -> None:
975975
self.reprtraceback.toterminal(tw)
@@ -1010,30 +1010,22 @@ def __init__(self, tblines: Sequence[str]) -> None:
10101010
self.extraline = None
10111011

10121012

1013+
@attr.s
10131014
class ReprEntryNative(TerminalRepr):
1015+
lines = attr.ib(type=Sequence[str])
10141016
style = "native" # type: _TracebackStyle
10151017

1016-
def __init__(self, tblines: Sequence[str]) -> None:
1017-
self.lines = tblines
1018-
10191018
def toterminal(self, tw: TerminalWriter) -> None:
10201019
tw.write("".join(self.lines))
10211020

10221021

1022+
@attr.s
10231023
class ReprEntry(TerminalRepr):
1024-
def __init__(
1025-
self,
1026-
lines: Sequence[str],
1027-
reprfuncargs: Optional["ReprFuncArgs"],
1028-
reprlocals: Optional["ReprLocals"],
1029-
filelocrepr: Optional["ReprFileLocation"],
1030-
style: "_TracebackStyle",
1031-
) -> None:
1032-
self.lines = lines
1033-
self.reprfuncargs = reprfuncargs
1034-
self.reprlocals = reprlocals
1035-
self.reprfileloc = filelocrepr
1036-
self.style = style
1024+
lines = attr.ib(type=Sequence[str])
1025+
reprfuncargs = attr.ib(type=Optional["ReprFuncArgs"])
1026+
reprlocals = attr.ib(type=Optional["ReprLocals"])
1027+
reprfileloc = attr.ib(type=Optional["ReprFileLocation"])
1028+
style = attr.ib(type="_TracebackStyle")
10371029

10381030
def _write_entry_lines(self, tw: TerminalWriter) -> None:
10391031
"""Writes the source code portions of a list of traceback entries with syntax highlighting.
@@ -1118,18 +1110,18 @@ def toterminal(self, tw: TerminalWriter) -> None:
11181110
tw.line(":{}: {}".format(self.lineno, msg))
11191111

11201112

1113+
@attr.s
11211114
class ReprLocals(TerminalRepr):
1122-
def __init__(self, lines: Sequence[str]) -> None:
1123-
self.lines = lines
1115+
lines = attr.ib(type=Sequence[str])
11241116

11251117
def toterminal(self, tw: TerminalWriter, indent="") -> None:
11261118
for line in self.lines:
11271119
tw.line(indent + line)
11281120

11291121

1122+
@attr.s
11301123
class ReprFuncArgs(TerminalRepr):
1131-
def __init__(self, args: Sequence[Tuple[str, object]]) -> None:
1132-
self.args = args
1124+
args = attr.ib(type=Sequence[Tuple[str, object]])
11331125

11341126
def toterminal(self, tw: TerminalWriter) -> None:
11351127
if self.args:

src/_pytest/reports.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -369,10 +369,10 @@ def _report_to_json(report):
369369
"""
370370

371371
def serialize_repr_entry(entry):
372-
entry_data = {"type": type(entry).__name__, "data": entry.__dict__.copy()}
372+
entry_data = {"type": type(entry).__name__, "data": attr.asdict(entry)}
373373
for key, value in entry_data["data"].items():
374374
if hasattr(value, "__dict__"):
375-
entry_data["data"][key] = value.__dict__.copy()
375+
entry_data["data"][key] = attr.asdict(value)
376376
return entry_data
377377

378378
def serialize_repr_traceback(reprtraceback: ReprTraceback):
@@ -451,7 +451,7 @@ def deserialize_repr_entry(entry_data):
451451
lines=data["lines"],
452452
reprfuncargs=reprfuncargs,
453453
reprlocals=reprlocals,
454-
filelocrepr=reprfileloc,
454+
reprfileloc=reprfileloc,
455455
style=data["style"],
456456
) # type: Union[ReprEntry, ReprEntryNative]
457457
elif entry_type == "ReprEntryNative":

src/_pytest/runner.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
from .reports import CollectErrorRepr
1515
from .reports import CollectReport
1616
from .reports import TestReport
17+
from _pytest._code.code import ExceptionChainRepr
1718
from _pytest._code.code import ExceptionInfo
18-
from _pytest._code.code import ExceptionRepr
1919
from _pytest.compat import TYPE_CHECKING
2020
from _pytest.nodes import Collector
2121
from _pytest.nodes import Node
@@ -276,7 +276,7 @@ def pytest_make_collect_report(collector: Collector) -> CollectReport:
276276
if call.excinfo.errisinstance(tuple(skip_exceptions)):
277277
outcome = "skipped"
278278
r_ = collector._repr_failure_py(call.excinfo, "line")
279-
assert isinstance(r_, ExceptionRepr), r_
279+
assert isinstance(r_, ExceptionChainRepr), repr(r_)
280280
r = r_.reprcrash
281281
assert r
282282
longrepr = (str(r.path), r.lineno, r.message)

0 commit comments

Comments
 (0)