...
.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
- 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
# 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.
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)
print_explanations = 0
print_includes = 0
print_objects = 0
+print_stacktrace = 0
print_time = 0
print_tree = 0
memory_stats = None
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:
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":
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:
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
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
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"
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()