Use attrs with all Repr classes (#6739)
Co-authored-by: Ran Benita <ran234@gmail.com>
This commit is contained in:
parent
bd7e33277b
commit
b11bfa106c
|
@ -789,9 +789,9 @@ class FormattedExcinfo:
|
||||||
else:
|
else:
|
||||||
message = excinfo and excinfo.typename or ""
|
message = excinfo and excinfo.typename or ""
|
||||||
path = self._makepath(entry.path)
|
path = self._makepath(entry.path)
|
||||||
filelocrepr = ReprFileLocation(path, entry.lineno + 1, message)
|
reprfileloc = ReprFileLocation(path, entry.lineno + 1, message)
|
||||||
localsrepr = self.repr_locals(entry.locals)
|
localsrepr = self.repr_locals(entry.locals)
|
||||||
return ReprEntry(lines, reprargs, localsrepr, filelocrepr, style)
|
return ReprEntry(lines, reprargs, localsrepr, reprfileloc, style)
|
||||||
if excinfo:
|
if excinfo:
|
||||||
lines.extend(self.get_exconly(excinfo, indent=4))
|
lines.extend(self.get_exconly(excinfo, indent=4))
|
||||||
return ReprEntry(lines, None, None, None, style)
|
return ReprEntry(lines, None, None, None, style)
|
||||||
|
@ -911,6 +911,7 @@ class FormattedExcinfo:
|
||||||
return ExceptionChainRepr(repr_chain)
|
return ExceptionChainRepr(repr_chain)
|
||||||
|
|
||||||
|
|
||||||
|
@attr.s
|
||||||
class TerminalRepr:
|
class TerminalRepr:
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
# FYI this is called from pytest-xdist's serialization of exception
|
# FYI this is called from pytest-xdist's serialization of exception
|
||||||
|
@ -927,8 +928,9 @@ class TerminalRepr:
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
|
||||||
|
@attr.s
|
||||||
class ExceptionRepr(TerminalRepr):
|
class ExceptionRepr(TerminalRepr):
|
||||||
def __init__(self) -> None:
|
def __attrs_post_init__(self):
|
||||||
self.sections = [] # type: List[Tuple[str, str, str]]
|
self.sections = [] # type: List[Tuple[str, str, str]]
|
||||||
|
|
||||||
def addsection(self, name: str, content: str, sep: str = "-") -> None:
|
def addsection(self, name: str, content: str, sep: str = "-") -> None:
|
||||||
|
@ -940,19 +942,20 @@ class ExceptionRepr(TerminalRepr):
|
||||||
tw.line(content)
|
tw.line(content)
|
||||||
|
|
||||||
|
|
||||||
|
@attr.s
|
||||||
class ExceptionChainRepr(ExceptionRepr):
|
class ExceptionChainRepr(ExceptionRepr):
|
||||||
def __init__(
|
chain = attr.ib(
|
||||||
self,
|
type=Sequence[
|
||||||
chain: Sequence[
|
|
||||||
Tuple["ReprTraceback", Optional["ReprFileLocation"], Optional[str]]
|
Tuple["ReprTraceback", Optional["ReprFileLocation"], Optional[str]]
|
||||||
],
|
]
|
||||||
) -> None:
|
)
|
||||||
super().__init__()
|
|
||||||
self.chain = chain
|
def __attrs_post_init__(self):
|
||||||
|
super().__attrs_post_init__()
|
||||||
# reprcrash and reprtraceback of the outermost (the newest) exception
|
# reprcrash and reprtraceback of the outermost (the newest) exception
|
||||||
# in the chain
|
# in the chain
|
||||||
self.reprtraceback = chain[-1][0]
|
self.reprtraceback = self.chain[-1][0]
|
||||||
self.reprcrash = chain[-1][1]
|
self.reprcrash = self.chain[-1][1]
|
||||||
|
|
||||||
def toterminal(self, tw: TerminalWriter) -> None:
|
def toterminal(self, tw: TerminalWriter) -> None:
|
||||||
for element in self.chain:
|
for element in self.chain:
|
||||||
|
@ -963,13 +966,10 @@ class ExceptionChainRepr(ExceptionRepr):
|
||||||
super().toterminal(tw)
|
super().toterminal(tw)
|
||||||
|
|
||||||
|
|
||||||
|
@attr.s
|
||||||
class ReprExceptionInfo(ExceptionRepr):
|
class ReprExceptionInfo(ExceptionRepr):
|
||||||
def __init__(
|
reprtraceback = attr.ib(type="ReprTraceback")
|
||||||
self, reprtraceback: "ReprTraceback", reprcrash: "ReprFileLocation"
|
reprcrash = attr.ib(type="ReprFileLocation")
|
||||||
) -> None:
|
|
||||||
super().__init__()
|
|
||||||
self.reprtraceback = reprtraceback
|
|
||||||
self.reprcrash = reprcrash
|
|
||||||
|
|
||||||
def toterminal(self, tw: TerminalWriter) -> None:
|
def toterminal(self, tw: TerminalWriter) -> None:
|
||||||
self.reprtraceback.toterminal(tw)
|
self.reprtraceback.toterminal(tw)
|
||||||
|
@ -1010,30 +1010,22 @@ class ReprTracebackNative(ReprTraceback):
|
||||||
self.extraline = None
|
self.extraline = None
|
||||||
|
|
||||||
|
|
||||||
|
@attr.s
|
||||||
class ReprEntryNative(TerminalRepr):
|
class ReprEntryNative(TerminalRepr):
|
||||||
|
lines = attr.ib(type=Sequence[str])
|
||||||
style = "native" # type: _TracebackStyle
|
style = "native" # type: _TracebackStyle
|
||||||
|
|
||||||
def __init__(self, tblines: Sequence[str]) -> None:
|
|
||||||
self.lines = tblines
|
|
||||||
|
|
||||||
def toterminal(self, tw: TerminalWriter) -> None:
|
def toterminal(self, tw: TerminalWriter) -> None:
|
||||||
tw.write("".join(self.lines))
|
tw.write("".join(self.lines))
|
||||||
|
|
||||||
|
|
||||||
|
@attr.s
|
||||||
class ReprEntry(TerminalRepr):
|
class ReprEntry(TerminalRepr):
|
||||||
def __init__(
|
lines = attr.ib(type=Sequence[str])
|
||||||
self,
|
reprfuncargs = attr.ib(type=Optional["ReprFuncArgs"])
|
||||||
lines: Sequence[str],
|
reprlocals = attr.ib(type=Optional["ReprLocals"])
|
||||||
reprfuncargs: Optional["ReprFuncArgs"],
|
reprfileloc = attr.ib(type=Optional["ReprFileLocation"])
|
||||||
reprlocals: Optional["ReprLocals"],
|
style = attr.ib(type="_TracebackStyle")
|
||||||
filelocrepr: Optional["ReprFileLocation"],
|
|
||||||
style: "_TracebackStyle",
|
|
||||||
) -> None:
|
|
||||||
self.lines = lines
|
|
||||||
self.reprfuncargs = reprfuncargs
|
|
||||||
self.reprlocals = reprlocals
|
|
||||||
self.reprfileloc = filelocrepr
|
|
||||||
self.style = style
|
|
||||||
|
|
||||||
def _write_entry_lines(self, tw: TerminalWriter) -> None:
|
def _write_entry_lines(self, tw: TerminalWriter) -> None:
|
||||||
"""Writes the source code portions of a list of traceback entries with syntax highlighting.
|
"""Writes the source code portions of a list of traceback entries with syntax highlighting.
|
||||||
|
@ -1118,18 +1110,18 @@ class ReprFileLocation(TerminalRepr):
|
||||||
tw.line(":{}: {}".format(self.lineno, msg))
|
tw.line(":{}: {}".format(self.lineno, msg))
|
||||||
|
|
||||||
|
|
||||||
|
@attr.s
|
||||||
class ReprLocals(TerminalRepr):
|
class ReprLocals(TerminalRepr):
|
||||||
def __init__(self, lines: Sequence[str]) -> None:
|
lines = attr.ib(type=Sequence[str])
|
||||||
self.lines = lines
|
|
||||||
|
|
||||||
def toterminal(self, tw: TerminalWriter, indent="") -> None:
|
def toterminal(self, tw: TerminalWriter, indent="") -> None:
|
||||||
for line in self.lines:
|
for line in self.lines:
|
||||||
tw.line(indent + line)
|
tw.line(indent + line)
|
||||||
|
|
||||||
|
|
||||||
|
@attr.s
|
||||||
class ReprFuncArgs(TerminalRepr):
|
class ReprFuncArgs(TerminalRepr):
|
||||||
def __init__(self, args: Sequence[Tuple[str, object]]) -> None:
|
args = attr.ib(type=Sequence[Tuple[str, object]])
|
||||||
self.args = args
|
|
||||||
|
|
||||||
def toterminal(self, tw: TerminalWriter) -> None:
|
def toterminal(self, tw: TerminalWriter) -> None:
|
||||||
if self.args:
|
if self.args:
|
||||||
|
|
|
@ -369,10 +369,10 @@ def _report_to_json(report):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def serialize_repr_entry(entry):
|
def serialize_repr_entry(entry):
|
||||||
entry_data = {"type": type(entry).__name__, "data": entry.__dict__.copy()}
|
entry_data = {"type": type(entry).__name__, "data": attr.asdict(entry)}
|
||||||
for key, value in entry_data["data"].items():
|
for key, value in entry_data["data"].items():
|
||||||
if hasattr(value, "__dict__"):
|
if hasattr(value, "__dict__"):
|
||||||
entry_data["data"][key] = value.__dict__.copy()
|
entry_data["data"][key] = attr.asdict(value)
|
||||||
return entry_data
|
return entry_data
|
||||||
|
|
||||||
def serialize_repr_traceback(reprtraceback: ReprTraceback):
|
def serialize_repr_traceback(reprtraceback: ReprTraceback):
|
||||||
|
@ -451,7 +451,7 @@ def _report_kwargs_from_json(reportdict):
|
||||||
lines=data["lines"],
|
lines=data["lines"],
|
||||||
reprfuncargs=reprfuncargs,
|
reprfuncargs=reprfuncargs,
|
||||||
reprlocals=reprlocals,
|
reprlocals=reprlocals,
|
||||||
filelocrepr=reprfileloc,
|
reprfileloc=reprfileloc,
|
||||||
style=data["style"],
|
style=data["style"],
|
||||||
) # type: Union[ReprEntry, ReprEntryNative]
|
) # type: Union[ReprEntry, ReprEntryNative]
|
||||||
elif entry_type == "ReprEntryNative":
|
elif entry_type == "ReprEntryNative":
|
||||||
|
|
|
@ -14,8 +14,8 @@ import attr
|
||||||
from .reports import CollectErrorRepr
|
from .reports import CollectErrorRepr
|
||||||
from .reports import CollectReport
|
from .reports import CollectReport
|
||||||
from .reports import TestReport
|
from .reports import TestReport
|
||||||
|
from _pytest._code.code import ExceptionChainRepr
|
||||||
from _pytest._code.code import ExceptionInfo
|
from _pytest._code.code import ExceptionInfo
|
||||||
from _pytest._code.code import ExceptionRepr
|
|
||||||
from _pytest.compat import TYPE_CHECKING
|
from _pytest.compat import TYPE_CHECKING
|
||||||
from _pytest.nodes import Collector
|
from _pytest.nodes import Collector
|
||||||
from _pytest.nodes import Node
|
from _pytest.nodes import Node
|
||||||
|
@ -276,7 +276,7 @@ def pytest_make_collect_report(collector: Collector) -> CollectReport:
|
||||||
if call.excinfo.errisinstance(tuple(skip_exceptions)):
|
if call.excinfo.errisinstance(tuple(skip_exceptions)):
|
||||||
outcome = "skipped"
|
outcome = "skipped"
|
||||||
r_ = collector._repr_failure_py(call.excinfo, "line")
|
r_ = collector._repr_failure_py(call.excinfo, "line")
|
||||||
assert isinstance(r_, ExceptionRepr), r_
|
assert isinstance(r_, ExceptionChainRepr), repr(r_)
|
||||||
r = r_.reprcrash
|
r = r_.reprcrash
|
||||||
assert r
|
assert r
|
||||||
longrepr = (str(r.path), r.lineno, r.message)
|
longrepr = (str(r.path), r.lineno, r.message)
|
||||||
|
|
Loading…
Reference in New Issue