From: stevenknight Date: Sat, 18 Sep 2004 12:41:15 +0000 (+0000) Subject: Print tracebacks for errors other than UserError and StopError. (Gary Oberbrunner) X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=bc7d81ae2ee53b15c27e85b827bdbd33918cd241;p=scons.git Print tracebacks for errors other than UserError and StopError. (Gary Oberbrunner) git-svn-id: http://scons.tigris.org/svn/scons/trunk@1081 fdb21ef1-2011-0410-befe-b5e4ea1792b1 --- diff --git a/doc/man/scons.1 b/doc/man/scons.1 index d4f2103e..c63a23a7 100644 --- a/doc/man/scons.1 +++ b/doc/man/scons.1 @@ -561,6 +561,11 @@ Building myprog.o with action(s): ... .EE +.TP +--debug=stacktrace +Prints an internal Python stack trace +when encountering an otherwise unexplained error. + .TP --debug=time Prints various time profiling information: the time spent diff --git a/src/CHANGES.txt b/src/CHANGES.txt index b035acbf..1965c619 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -73,6 +73,9 @@ RELEASE 0.97 - XXX - Add a PRINT_CMD_LINE_FUNC construction variable to allow people to filter (or log) command-line output. + - Print an internal Python stack trace in response to an otherwise + unexplained error when --debug=stacktrace is specified. + From Kevin Quick: - Fix the Builder name returned from ListBuilders and other instances diff --git a/src/engine/SCons/Script/__init__.py b/src/engine/SCons/Script/__init__.py index dfee7677..160fae30 100644 --- a/src/engine/SCons/Script/__init__.py +++ b/src/engine/SCons/Script/__init__.py @@ -141,8 +141,12 @@ class BuildTask(SCons.Taskmaster.Task): # is to display the various types of Errors and Exceptions # appropriately. status = 2 - t, e = self.exc_info()[:2] - tb = None + exc_info = self.exc_info() + try: + t, e, tb = exc_info + except ValueError: + t, e = exc_info + tb = None if t is None: # The Taskmaster didn't record an exception for this Task; # see if the sys module has one. @@ -166,7 +170,7 @@ class BuildTask(SCons.Taskmaster.Task): s = s + ' Stop.' sys.stderr.write("scons: *** %s\n" % s) - if tb: + if tb and print_stacktrace: sys.stderr.write("scons: internal stack trace:\n") traceback.print_tb(tb, file=sys.stderr) @@ -240,6 +244,7 @@ print_dtree = 0 print_explanations = 0 print_includes = 0 print_objects = 0 +print_stacktrace = 0 print_time = 0 print_tree = 0 memory_stats = None @@ -400,7 +405,8 @@ def _set_globals(options): global repositories, keep_going_on_error, ignore_errors global print_count, print_dtree global print_explanations, print_includes - global print_objects, print_time, print_tree + global print_objects, print_stacktrace + global print_time, print_tree global memory_outf, memory_stats if options.repository: @@ -423,6 +429,8 @@ def _set_globals(options): print_objects = 1 elif options.debug == "presub": SCons.Action.print_actions_presub = 1 + elif options.debug == "stacktrace": + print_stacktrace = 1 elif options.debug == "time": print_time = 1 elif options.debug == "tree": @@ -520,7 +528,8 @@ class OptParser(OptionParser): debug_options = ["count", "dtree", "explain", "includes", "memory", "objects", - "pdb", "presub", "time", "tree"] + "pdb", "presub", "stacktrace", + "time", "tree"] def opt_debug(option, opt, value, parser, debug_options=debug_options): if value in debug_options: diff --git a/src/engine/SCons/Taskmaster.py b/src/engine/SCons/Taskmaster.py index dab50264..84eb08dc 100644 --- a/src/engine/SCons/Taskmaster.py +++ b/src/engine/SCons/Taskmaster.py @@ -461,5 +461,10 @@ class Taskmaster: self.pending = [] def exception_raise(self, exception): - exc_type, exc_value = exception[:2] - raise exc_type, exc_value + exc = exception[:] + try: + exc_type, exc_value, exc_traceback = exc + except ValueError: + exc_type, exc_value = exc + exc_traceback = None + raise exc_type, exc_value, exc_traceback diff --git a/src/engine/SCons/TaskmasterTests.py b/src/engine/SCons/TaskmasterTests.py index 8865e09b..a9081928 100644 --- a/src/engine/SCons/TaskmasterTests.py +++ b/src/engine/SCons/TaskmasterTests.py @@ -921,7 +921,25 @@ class TaskmasterTestCase(unittest.TestCase): else: assert 0, "did not catch expected exception" - t.exception_set(("exception 3", "XYZZY")) + try: + 1/0 + except: + tb = sys.exc_info()[2] + t.exception_set(("exception 3", "arg", tb)) + try: + t.exception_raise() + except: + exc_type, exc_value, exc_tb = sys.exc_info() + assert exc_type == 'exception 3', exc_type + assert exc_value == "arg", exc_value + import traceback + x = traceback.extract_tb(tb)[-1] + y = traceback.extract_tb(exc_tb)[-1] + assert x == y, "x = %s, y = %s" % (x, y) + else: + assert 0, "did not catch expected exception" + + t.exception_set(("exception 4", "XYZZY")) def fw_exc(exc): raise 'exception_forwarded', exc tm.exception_raise = fw_exc @@ -930,7 +948,7 @@ class TaskmasterTestCase(unittest.TestCase): except: exc_type, exc_value = sys.exc_info()[:2] assert exc_type == 'exception_forwarded', exc_type - assert exc_value[0] == "exception 3", exc_value[0] + assert exc_value[0] == "exception 4", exc_value[0] assert exc_value[1] == "XYZZY", exc_value[1] else: assert 0, "did not catch expected exception" diff --git a/test/option--debug.py b/test/option--debug.py index 64cc424e..e3d99605 100644 --- a/test/option--debug.py +++ b/test/option--debug.py @@ -384,4 +384,49 @@ test.must_match('file16.out', "file16.in\n") test.must_match('file17.out', "file17.in\n") test.must_match('file18.out', "file18.in\n") +############################ +# test --debug=stacktrace + +test.write('SConstruct', """\ +def kfile_scan(node, env, target): + raise "kfile_scan error" + +kscan = Scanner(name = 'kfile', + function = kfile_scan, + skeys = ['.k']) + +env = Environment() +env.Append(SCANNERS = [kscan]) + +env.Command('foo', 'foo.k', Copy('$TARGET', '$SOURCE')) +""") + +test.write('foo.k', "foo.k\n") + +test.run(status = 2, stderr = "scons: *** kfile_scan error\n") + +test.run(arguments = "--debug=stacktrace", + status = 2, + stderr = None) + +stderr = test.stderr() + +lines = [ + "scons: *** kfile_scan error", + "scons: internal stack trace:", + 'raise "kfile_scan error"', +] + +missing = [] +for line in lines: + if string.find(stderr, line) == -1: + missing.append(line) + +if missing: + print "STDERR is missing the following lines:" + print "\t" + string.join(lines, "\n\t") + print "STDERR =====" + print stderr + test.fail_test(1) + test.pass_test()