From b8d5f245b7077d869121835ed72656ac14962ef0 Mon Sep 17 00:00:00 2001 From: Steve Purcell Date: Sat, 6 Dec 2003 13:03:13 +0000 Subject: Variation of Thomas Heller's patch (722638) for improving readability of test failure output. Irrelevant traceback levels are pruned from formatted traceback strings. --- Lib/unittest.py | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/Lib/unittest.py b/Lib/unittest.py index 10108d3..0ec059c 100644 --- a/Lib/unittest.py +++ b/Lib/unittest.py @@ -46,7 +46,7 @@ SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. __author__ = "Steve Purcell" __email__ = "stephen_purcell at yahoo dot com" -__version__ = "#Revision: 1.62 $"[11:-2] +__version__ = "#Revision: 1.63 $"[11:-2] import time import sys @@ -90,6 +90,8 @@ __metaclass__ = type def _strclass(cls): return "%s.%s" % (cls.__module__, cls.__name__) +__unittest = 1 + class TestResult: """Holder for test result information. @@ -119,12 +121,12 @@ class TestResult: """Called when an error has occurred. 'err' is a tuple of values as returned by sys.exc_info(). """ - self.errors.append((test, self._exc_info_to_string(err))) + self.errors.append((test, self._exc_info_to_string(err, test))) def addFailure(self, test, err): """Called when an error has occurred. 'err' is a tuple of values as returned by sys.exc_info().""" - self.failures.append((test, self._exc_info_to_string(err))) + self.failures.append((test, self._exc_info_to_string(err, test))) def addSuccess(self, test): "Called when a test has completed successfully" @@ -138,16 +140,33 @@ class TestResult: "Indicates that the tests should be aborted" self.shouldStop = True - def _exc_info_to_string(self, err): + def _exc_info_to_string(self, err, test): """Converts a sys.exc_info()-style tuple of values into a string.""" - return ''.join(traceback.format_exception(*err)) + 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) + return ''.join(traceback.format_exception(exctype, value, tb, length)) + return ''.join(traceback.format_exception(exctype, value, tb)) + + def _is_relevant_tb_level(self, tb): + return tb.tb_frame.f_globals.has_key('__unittest') + + def _count_relevant_tb_levels(self, tb): + length = 0 + while tb and not self._is_relevant_tb_level(tb): + length += 1 + tb = tb.tb_next + return length def __repr__(self): return "<%s run=%i errors=%i failures=%i>" % \ (_strclass(self.__class__), self.testsRun, len(self.errors), len(self.failures)) - class TestCase: """A class whose instances are single test cases. @@ -274,10 +293,7 @@ class TestCase: exctype, excvalue, tb = sys.exc_info() if sys.platform[:4] == 'java': ## tracebacks look different in Jython return (exctype, excvalue, tb) - newtb = tb.tb_next - if newtb is None: - return (exctype, excvalue, tb) - return (exctype, excvalue, newtb) + return (exctype, excvalue, tb) def fail(self, msg=None): """Fail immediately, with the given message.""" -- cgit v0.12