nodes: apply same traceback filtering for chained exceptions as main exception
Fix #1904.
This commit is contained in:
parent
fcada1ea47
commit
dd667336ce
|
@ -0,0 +1 @@
|
|||
Fixed traceback entries hidden with ``__tracebackhide__ = True`` still being shown for chained exceptions (parts after "... the above exception ..." message).
|
|
@ -635,7 +635,9 @@ class ExceptionInfo(Generic[E]):
|
|||
showlocals: bool = False,
|
||||
style: "_TracebackStyle" = "long",
|
||||
abspath: bool = False,
|
||||
tbfilter: bool = True,
|
||||
tbfilter: Union[
|
||||
bool, Callable[["ExceptionInfo[BaseException]"], Traceback]
|
||||
] = True,
|
||||
funcargs: bool = False,
|
||||
truncate_locals: bool = True,
|
||||
chain: bool = True,
|
||||
|
@ -652,9 +654,15 @@ class ExceptionInfo(Generic[E]):
|
|||
:param bool abspath:
|
||||
If paths should be changed to absolute or left unchanged.
|
||||
|
||||
:param bool tbfilter:
|
||||
Hide entries that contain a local variable ``__tracebackhide__==True``.
|
||||
Ignored if ``style=="native"``.
|
||||
:param tbfilter:
|
||||
A filter for traceback entries.
|
||||
|
||||
* If false, don't hide any entries.
|
||||
* If true, hide internal entries and entries that contain a local
|
||||
variable ``__tracebackhide__ = True``.
|
||||
* If a callable, delegates the filtering to the callable.
|
||||
|
||||
Ignored if ``style`` is ``"native"``.
|
||||
|
||||
:param bool funcargs:
|
||||
Show fixtures ("funcargs" for legacy purposes) per traceback entry.
|
||||
|
@ -719,7 +727,7 @@ class FormattedExcinfo:
|
|||
showlocals: bool = False
|
||||
style: "_TracebackStyle" = "long"
|
||||
abspath: bool = True
|
||||
tbfilter: bool = True
|
||||
tbfilter: Union[bool, Callable[[ExceptionInfo[BaseException]], Traceback]] = True
|
||||
funcargs: bool = False
|
||||
truncate_locals: bool = True
|
||||
chain: bool = True
|
||||
|
@ -881,7 +889,9 @@ class FormattedExcinfo:
|
|||
|
||||
def repr_traceback(self, excinfo: ExceptionInfo[BaseException]) -> "ReprTraceback":
|
||||
traceback = excinfo.traceback
|
||||
if self.tbfilter:
|
||||
if callable(self.tbfilter):
|
||||
traceback = self.tbfilter(excinfo)
|
||||
elif self.tbfilter:
|
||||
traceback = traceback.filter(excinfo)
|
||||
|
||||
if isinstance(excinfo.value, RecursionError):
|
||||
|
|
|
@ -450,10 +450,13 @@ class Node(metaclass=NodeMeta):
|
|||
style = "value"
|
||||
if isinstance(excinfo.value, FixtureLookupError):
|
||||
return excinfo.value.formatrepr()
|
||||
|
||||
tbfilter: Union[bool, Callable[[ExceptionInfo[BaseException]], Traceback]]
|
||||
if self.config.getoption("fulltrace", False):
|
||||
style = "long"
|
||||
tbfilter = False
|
||||
else:
|
||||
excinfo.traceback = self._traceback_filter(excinfo)
|
||||
tbfilter = self._traceback_filter
|
||||
if style == "auto":
|
||||
style = "long"
|
||||
# XXX should excinfo.getrepr record all data and toterminal() process it?
|
||||
|
@ -484,7 +487,7 @@ class Node(metaclass=NodeMeta):
|
|||
abspath=abspath,
|
||||
showlocals=self.config.getoption("showlocals", False),
|
||||
style=style,
|
||||
tbfilter=False, # pruned already, or in --fulltrace mode.
|
||||
tbfilter=tbfilter,
|
||||
truncate_locals=truncate_locals,
|
||||
)
|
||||
|
||||
|
|
|
@ -1603,3 +1603,48 @@ def test_all_entries_hidden(pytester: Pytester, tbstyle: str) -> None:
|
|||
result.stdout.fnmatch_lines(["*ZeroDivisionError: division by zero"])
|
||||
if tbstyle not in ("line", "native"):
|
||||
result.stdout.fnmatch_lines(["All traceback entries are hidden.*"])
|
||||
|
||||
|
||||
def test_hidden_entries_of_chained_exceptions_are_not_shown(pytester: Pytester) -> None:
|
||||
"""Hidden entries of chained exceptions are not shown (#1904)."""
|
||||
p = pytester.makepyfile(
|
||||
"""
|
||||
def g1():
|
||||
__tracebackhide__ = True
|
||||
str.does_not_exist
|
||||
|
||||
def f3():
|
||||
__tracebackhide__ = True
|
||||
1 / 0
|
||||
|
||||
def f2():
|
||||
try:
|
||||
f3()
|
||||
except Exception:
|
||||
g1()
|
||||
|
||||
def f1():
|
||||
__tracebackhide__ = True
|
||||
f2()
|
||||
|
||||
def test():
|
||||
f1()
|
||||
"""
|
||||
)
|
||||
result = pytester.runpytest(str(p), "--tb=short")
|
||||
assert result.ret == 1
|
||||
result.stdout.fnmatch_lines(
|
||||
[
|
||||
"*.py:11: in f2",
|
||||
" f3()",
|
||||
"E ZeroDivisionError: division by zero",
|
||||
"",
|
||||
"During handling of the above exception, another exception occurred:",
|
||||
"*.py:20: in test",
|
||||
" f1()",
|
||||
"*.py:13: in f2",
|
||||
" g1()",
|
||||
"E AttributeError:*'does_not_exist'",
|
||||
],
|
||||
consecutive=True,
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue