mirror of
https://github.com/python/cpython.git
synced 2025-08-22 09:45:06 +00:00
bpo-24959: fix unittest.assertRaises bug where traceback entries are dropped from chained exceptions (GH-23688)
(cherry picked from commit 88b7d86a73
)
Co-authored-by: Irit Katriel <1055913+iritkatriel@users.noreply.github.com>
This commit is contained in:
parent
8de434b332
commit
26fa25a9a7
3 changed files with 95 additions and 14 deletions
|
@ -173,18 +173,10 @@ class TestResult(object):
|
|||
def _exc_info_to_string(self, err, test):
|
||||
"""Converts a sys.exc_info()-style tuple of values into a string."""
|
||||
exctype, value, tb = err
|
||||
# Skip test runner traceback levels
|
||||
while tb and self._is_relevant_tb_level(tb):
|
||||
tb = tb.tb_next
|
||||
|
||||
if exctype is test.failureException:
|
||||
# Skip assert*() traceback levels
|
||||
length = self._count_relevant_tb_levels(tb)
|
||||
else:
|
||||
length = None
|
||||
tb = self._clean_tracebacks(exctype, value, tb, test)
|
||||
tb_e = traceback.TracebackException(
|
||||
exctype, value, tb,
|
||||
limit=length, capture_locals=self.tb_locals, compact=True)
|
||||
capture_locals=self.tb_locals, compact=True)
|
||||
msgLines = list(tb_e.format())
|
||||
|
||||
if self.buffer:
|
||||
|
@ -200,16 +192,49 @@ class TestResult(object):
|
|||
msgLines.append(STDERR_LINE % error)
|
||||
return ''.join(msgLines)
|
||||
|
||||
def _clean_tracebacks(self, exctype, value, tb, test):
|
||||
ret = None
|
||||
first = True
|
||||
excs = [(exctype, value, tb)]
|
||||
while excs:
|
||||
(exctype, value, tb) = excs.pop()
|
||||
# Skip test runner traceback levels
|
||||
while tb and self._is_relevant_tb_level(tb):
|
||||
tb = tb.tb_next
|
||||
|
||||
# Skip assert*() traceback levels
|
||||
if exctype is test.failureException:
|
||||
self._remove_unittest_tb_frames(tb)
|
||||
|
||||
if first:
|
||||
ret = tb
|
||||
first = False
|
||||
else:
|
||||
value.__traceback__ = tb
|
||||
|
||||
if value is not None:
|
||||
for c in (value.__cause__, value.__context__):
|
||||
if c is not None:
|
||||
excs.append((type(c), c, c.__traceback__))
|
||||
return ret
|
||||
|
||||
def _is_relevant_tb_level(self, tb):
|
||||
return '__unittest' in tb.tb_frame.f_globals
|
||||
|
||||
def _count_relevant_tb_levels(self, tb):
|
||||
length = 0
|
||||
def _remove_unittest_tb_frames(self, tb):
|
||||
'''Truncates usercode tb at the first unittest frame.
|
||||
|
||||
If the first frame of the traceback is in user code,
|
||||
the prefix up to the first unittest frame is returned.
|
||||
If the first frame is already in the unittest module,
|
||||
the traceback is not modified.
|
||||
'''
|
||||
prev = None
|
||||
while tb and not self._is_relevant_tb_level(tb):
|
||||
length += 1
|
||||
prev = tb
|
||||
tb = tb.tb_next
|
||||
return length
|
||||
if prev is not None:
|
||||
prev.tb_next = None
|
||||
|
||||
def __repr__(self):
|
||||
return ("<%s run=%i errors=%i failures=%i>" %
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue