New ExceptionInfo.getrepr 'chain' parameter to be able to suppress chained exceptions
This commit is contained in:
parent
933de16fe4
commit
36dc671843
|
@ -451,13 +451,35 @@ class ExceptionInfo(object):
|
||||||
tbfilter=True,
|
tbfilter=True,
|
||||||
funcargs=False,
|
funcargs=False,
|
||||||
truncate_locals=True,
|
truncate_locals=True,
|
||||||
|
chain=True,
|
||||||
):
|
):
|
||||||
""" return str()able representation of this exception info.
|
"""
|
||||||
showlocals: show locals per traceback entry
|
Return str()able representation of this exception info.
|
||||||
style: long|short|no|native traceback style
|
|
||||||
tbfilter: hide entries (where __tracebackhide__ is true)
|
|
||||||
|
|
||||||
in case of style==native, tbfilter and showlocals is ignored.
|
:param bool showlocals:
|
||||||
|
Show locals per traceback entry.
|
||||||
|
Ignored if ``style=="native"``.
|
||||||
|
|
||||||
|
:param str style: long|short|no|native traceback style
|
||||||
|
|
||||||
|
: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 bool funcargs:
|
||||||
|
Show fixtures ("funcargs" for legacy purposes) per traceback entry.
|
||||||
|
|
||||||
|
:param bool truncate_locals:
|
||||||
|
With ``showlocals==True``, make sure locals can be safely represented as strings.
|
||||||
|
|
||||||
|
:param bool chain: if chained exceptions in Python 3 should be shown.
|
||||||
|
|
||||||
|
.. versionchanged:: 3.9
|
||||||
|
|
||||||
|
Added the ``chain`` parameter.
|
||||||
"""
|
"""
|
||||||
if style == "native":
|
if style == "native":
|
||||||
return ReprExceptionInfo(
|
return ReprExceptionInfo(
|
||||||
|
@ -476,6 +498,7 @@ class ExceptionInfo(object):
|
||||||
tbfilter=tbfilter,
|
tbfilter=tbfilter,
|
||||||
funcargs=funcargs,
|
funcargs=funcargs,
|
||||||
truncate_locals=truncate_locals,
|
truncate_locals=truncate_locals,
|
||||||
|
chain=chain,
|
||||||
)
|
)
|
||||||
return fmt.repr_excinfo(self)
|
return fmt.repr_excinfo(self)
|
||||||
|
|
||||||
|
@ -516,6 +539,7 @@ class FormattedExcinfo(object):
|
||||||
tbfilter = attr.ib(default=True)
|
tbfilter = attr.ib(default=True)
|
||||||
funcargs = attr.ib(default=False)
|
funcargs = attr.ib(default=False)
|
||||||
truncate_locals = attr.ib(default=True)
|
truncate_locals = attr.ib(default=True)
|
||||||
|
chain = attr.ib(default=True)
|
||||||
astcache = attr.ib(default=attr.Factory(dict), init=False, repr=False)
|
astcache = attr.ib(default=attr.Factory(dict), init=False, repr=False)
|
||||||
|
|
||||||
def _getindent(self, source):
|
def _getindent(self, source):
|
||||||
|
@ -735,7 +759,7 @@ class FormattedExcinfo(object):
|
||||||
reprcrash = None
|
reprcrash = None
|
||||||
|
|
||||||
repr_chain += [(reprtraceback, reprcrash, descr)]
|
repr_chain += [(reprtraceback, reprcrash, descr)]
|
||||||
if e.__cause__ is not None:
|
if e.__cause__ is not None and self.chain:
|
||||||
e = e.__cause__
|
e = e.__cause__
|
||||||
excinfo = (
|
excinfo = (
|
||||||
ExceptionInfo((type(e), e, e.__traceback__))
|
ExceptionInfo((type(e), e, e.__traceback__))
|
||||||
|
@ -743,7 +767,11 @@ class FormattedExcinfo(object):
|
||||||
else None
|
else None
|
||||||
)
|
)
|
||||||
descr = "The above exception was the direct cause of the following exception:"
|
descr = "The above exception was the direct cause of the following exception:"
|
||||||
elif e.__context__ is not None and not e.__suppress_context__:
|
elif (
|
||||||
|
e.__context__ is not None
|
||||||
|
and not e.__suppress_context__
|
||||||
|
and self.chain
|
||||||
|
):
|
||||||
e = e.__context__
|
e = e.__context__
|
||||||
excinfo = (
|
excinfo = (
|
||||||
ExceptionInfo((type(e), e, e.__traceback__))
|
ExceptionInfo((type(e), e, e.__traceback__))
|
||||||
|
|
|
@ -1184,20 +1184,28 @@ raise ValueError()
|
||||||
assert tw.lines[47] == ":15: AttributeError"
|
assert tw.lines[47] == ":15: AttributeError"
|
||||||
|
|
||||||
@pytest.mark.skipif("sys.version_info[0] < 3")
|
@pytest.mark.skipif("sys.version_info[0] < 3")
|
||||||
def test_exc_repr_with_raise_from_none_chain_suppression(self, importasmod):
|
@pytest.mark.parametrize("mode", ["from_none", "explicit_suppress"])
|
||||||
|
def test_exc_repr_chain_suppression(self, importasmod, mode):
|
||||||
|
"""Check that exc repr does not show chained exceptions in Python 3.
|
||||||
|
- When the exception is raised with "from None"
|
||||||
|
- Explicitly suppressed with "chain=False" to ExceptionInfo.getrepr().
|
||||||
|
"""
|
||||||
|
raise_suffix = " from None" if mode == "from_none" else ""
|
||||||
mod = importasmod(
|
mod = importasmod(
|
||||||
"""
|
"""
|
||||||
def f():
|
def f():
|
||||||
try:
|
try:
|
||||||
g()
|
g()
|
||||||
except Exception:
|
except Exception:
|
||||||
raise AttributeError() from None
|
raise AttributeError(){raise_suffix}
|
||||||
def g():
|
def g():
|
||||||
raise ValueError()
|
raise ValueError()
|
||||||
"""
|
""".format(
|
||||||
|
raise_suffix=raise_suffix
|
||||||
|
)
|
||||||
)
|
)
|
||||||
excinfo = pytest.raises(AttributeError, mod.f)
|
excinfo = pytest.raises(AttributeError, mod.f)
|
||||||
r = excinfo.getrepr(style="long")
|
r = excinfo.getrepr(style="long", chain=mode != "explicit_suppress")
|
||||||
tw = TWMock()
|
tw = TWMock()
|
||||||
r.toterminal(tw)
|
r.toterminal(tw)
|
||||||
for line in tw.lines:
|
for line in tw.lines:
|
||||||
|
@ -1207,7 +1215,9 @@ raise ValueError()
|
||||||
assert tw.lines[2] == " try:"
|
assert tw.lines[2] == " try:"
|
||||||
assert tw.lines[3] == " g()"
|
assert tw.lines[3] == " g()"
|
||||||
assert tw.lines[4] == " except Exception:"
|
assert tw.lines[4] == " except Exception:"
|
||||||
assert tw.lines[5] == "> raise AttributeError() from None"
|
assert tw.lines[5] == "> raise AttributeError(){}".format(
|
||||||
|
raise_suffix
|
||||||
|
)
|
||||||
assert tw.lines[6] == "E AttributeError"
|
assert tw.lines[6] == "E AttributeError"
|
||||||
assert tw.lines[7] == ""
|
assert tw.lines[7] == ""
|
||||||
line = tw.get_write_msg(8)
|
line = tw.get_write_msg(8)
|
||||||
|
|
Loading…
Reference in New Issue