summaryrefslogtreecommitdiffstats
path: root/Lib/unittest/result.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/unittest/result.py')
-rw-r--r--Lib/unittest/result.py53
1 files changed, 39 insertions, 14 deletions
diff --git a/Lib/unittest/result.py b/Lib/unittest/result.py
index ce7468e..3da7005 100644
--- a/Lib/unittest/result.py
+++ b/Lib/unittest/result.py
@@ -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>" %