Provide a traceback if a Python-function builder throws an exception (Crain).
authorstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Wed, 23 Jan 2002 22:59:58 +0000 (22:59 +0000)
committerstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Wed, 23 Jan 2002 22:59:58 +0000 (22:59 +0000)
git-svn-id: http://scons.tigris.org/svn/scons/trunk@219 fdb21ef1-2011-0410-befe-b5e4ea1792b1

src/engine/SCons/Node/NodeTests.py
src/engine/SCons/Node/__init__.py
src/engine/SCons/Script/__init__.py
test/build-errors.py
test/exceptions.py

index 37b9f37d70d701950603022400d2d5b885076f83..10507679a86489e5535e6a66dd563be78af0e828 100644 (file)
@@ -60,6 +60,10 @@ class ExceptBuilder:
     def execute(self, **kw):
         raise SCons.Errors.BuildError
 
+class ExceptBuilder2:
+    def execute(self, **kw):
+        raise "foo"
+
 class Environment:
     def Dictionary(self, *args):
        pass
@@ -91,6 +95,22 @@ class NodeTestCase(unittest.TestCase):
         else:
             raise TestFailed, "did not catch expected BuildError"
 
+        node = SCons.Node.Node()
+        node.builder_set(ExceptBuilder2())
+        node.env_set(Environment())
+        try:
+            node.build()
+        except SCons.Errors.BuildError, e:
+            # On a generic (non-BuildError) exception from a Builder,
+            # the Node should throw a BuildError exception with
+            # the args set to the exception value, type, and traceback.
+            assert len(e.args) == 3, `e.args`
+            assert e.args[0] == 'foo', e.args[0]
+            assert e.args[1] is None
+            assert type(e.args[2]) is type(sys.exc_traceback), e.args[2]
+        else:
+            raise TestFailed, "did not catch expected BuildError"
+
     def test_build(self):
        """Test building a node
        """
index f2d379fe39634dd9d729b5ca792db3fdfaa6907e..c6418951d1ed5689731883d03757c757ca07d97c 100644 (file)
@@ -35,6 +35,7 @@ from SCons.Errors import BuildError
 import string
 import types
 import copy
+import sys
 
 # Node states
 #
@@ -77,7 +78,10 @@ class Node:
             stat = self.builder.execute(env = self.env.Dictionary(),
                                         target = self, source = self.sources)
         except:
-            raise BuildError(node = self, errstr = "Exception")
+            raise BuildError(self, "Exception",
+                             sys.exc_type,
+                             sys.exc_value,
+                             sys.exc_traceback)
         if stat:
             raise BuildError(node = self, errstr = "Error %d" % stat)
 
index 1788fab256a02864a2c954aacf3d7163c22c516e..acbd6c0b7af74d53a67554c74806a7594cb3dcf9 100644 (file)
@@ -76,6 +76,9 @@ class BuildTask(SCons.Taskmaster.Task):
                 self.target.build()
             except BuildError, e:
                 sys.stderr.write("scons: *** [%s] %s\n" % (e.node, e.errstr))
+                if e.errstr == 'Exception':
+                    traceback.print_exception(e.args[0], e.args[1],
+                                              e.args[2])
                 raise
 
     def executed(self):
index 85456422898a7720be640f06f1f600a9dde0c017..edd06b1c934d0e9a1aad0ca895791b5bce0b7c11 100644 (file)
@@ -90,7 +90,7 @@ test.description_set("Incorrect STDERR:\n%s\n" % test.stderr())
 if os.name == 'nt':
     errs = [
         bad_command,
-        unrecognized % (no_such_file, 'f2'),
+        unrecognized % (not_executable, 'f2'),
         unspecified % 'f2'
     ]
     test.fail_test(not test.stderr() in errs)
@@ -113,7 +113,7 @@ test.description_set("Incorrect STDERR:\n%s\n" % test.stderr())
 if os.name == 'nt':
     errs = [
         bad_command,
-        unrecognized % (no_such_file, 'f3'),
+        unrecognized % (test.workdir, 'f3'),
         unspecified % 'f3'
     ]
     test.fail_test(not test.stderr() in errs)
index e67cec6dfb837bf0805c54f9277fcdb702b0a063..8fc53483e110f183bcbd4da4a3c2cf6a1249fb1a 100644 (file)
@@ -27,8 +27,9 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 import os
 import sys
 import TestSCons
+import TestCmd
 
-test = TestSCons.TestSCons()
+test = TestSCons.TestSCons(match = TestCmd.match_re)
 
 test.write('SConstruct', """
 def func(source = None, target = None, env = None):
@@ -40,6 +41,16 @@ env.B(target = 'foo.out', source = 'foo.in')
 
 test.write('foo.in', "foo.in\n")
 
-test.run(arguments = "foo.out", stderr = "scons: *** [foo.out] Exception\n")
-
+test.run(arguments = "foo.out", stderr = """scons: \*\*\* \[foo.out\] Exception
+Traceback \((most recent call|innermost) last\):
+  File ".+", line \d+, in .+
+    .+
+  File ".+", line \d+, in .+
+    .+
+  File ".+", line \d+, in .+
+    .+
+  File "SConstruct", line 3, in func
+    raise "func exception"
+func exception
+""")
 test.pass_test()