but the user requested a dry-run"""
def __init__(self,file):
UserError.__init__(self,"Cannot update configure test (%s) within a dry-run." % str(file))
-
-class TaskmasterException(Exception):
- def __init__(self, type, value, traceback, *args):
- self.type = type
- self.value = value
- self.traceback = traceback
- apply(Exception.__init__, (self,) + args)
except SCons.Errors.UserError, e:
assert e.args == ("Cannot update configure test (FileName) within a dry-run.",)
- def test_TaskmasterException(self):
- """Test the TaskmasterException."""
- try:
- raise SCons.Errors.TaskmasterException("one", "two", "three")
- except SCons.Errors.TaskmasterException, e:
- assert e.type == "one", e.type
- assert e.value == "two", e.value
- assert e.traceback == "three", e.traceback
-
if __name__ == "__main__":
suite = unittest.makeSuite(ErrorsTestCase, 'test_')
except KeyboardInterrupt:
raise
except:
+ task.exception_set()
# Let the failed() callback function arrange for the
# build to stop if that's appropriate.
task.failed()
# be explicit here for test/interrupts.py
ok = False
except:
+ task.exception_set()
ok = 0
else:
ok = 1
def postprocess(self):
self.taskmaster.num_postprocessed = self.taskmaster.num_postprocessed + 1
+ def exception_set(self):
+ self.taskmaster.exception_set()
+
class Taskmaster:
"""A dummy taskmaster class for testing the job classes."""
== (i + 1))
return serial
+ def exception_set(self):
+ pass
+
class ParallelTestCase(unittest.TestCase):
def runTest(self):
"test parallel jobs"
if (target.get_state() != SCons.Node.up_to_date and
target.has_builder() and
not hasattr(target.builder, 'status')):
-
+
raise SCons.Errors.ConfigureDryRunError(target)
def failed(self):
- if sys.exc_type == SCons.Errors.ConfigureDryRunError:
- raise
- SConfBuildTask.failed(self)
+ exc_type, exc_value = self.exc_info()[:2]
+ if exc_type == SCons.Errors.ConfigureDryRunError:
+ raise exc_type, exc_value
+ # Should be SConfBuildTask.failed(), really,
+ # but that causes name errors in Python 1.5.2.
+ SCons.Script.BuildTask.failed(self)
if self.logstream != None:
# override stdout / stderr to write in log file
This will show users who have Python errors where the problem is,
without cluttering the output with all of the internal calls leading
up to where we exec the SConscript."""
- stack = traceback.extract_tb(sys.exc_traceback)
+ exc_type, exc_value, exc_tb = sys.exc_info()
+ stack = traceback.extract_tb(exc_tb)
last_text = ""
found = 0
i = 0
# We did not find our exec statement, so this was actually a bug
# in SCons itself. Show the whole stack.
i = 0
- type = str(sys.exc_type)
+ type = str(exc_type)
if type[:11] == "exceptions.":
type = type[11:]
- file.write('%s: %s:\n' % (type, sys.exc_value))
+ file.write('%s: %s:\n' % (type, exc_value))
for fname, line, func, text in stack[i:]:
file.write(' File "%s", line %d:\n' % (fname, line))
file.write(' %s\n' % text)
# is to display the various types of Errors and Exceptions
# appropriately.
status = 2
- e = sys.exc_value
- t = sys.exc_type
+ t, e = self.exc_info()[:2]
tb = None
- if t is SCons.Errors.TaskmasterException:
- # The Taskmaster received an Error or Exception while trying
- # to process or build the Nodes and dependencies, which it
- # wrapped up for us in the object recorded as the value of
- # the Exception, so process the wrapped info instead of the
- # TaskmasterException itself.
- t = e.type
- tb = e.traceback
- e = e.value
+ if t is None:
+ # The Taskmaster didn't record an exception for this Task;
+ # see if the sys module has one.
+ t, e = sys.exc_info()[:2]
if t == SCons.Errors.BuildError:
sys.stderr.write("scons: *** [%s] %s\n" % (e.node, e.errstr))
self.do_failed(status)
+ self.exc_clear()
+
def make_ready(self):
"""Make a task ready for execution"""
SCons.Taskmaster.Task.make_ready(self)
except KeyboardInterrupt:
raise
except SystemExit:
- raise SCons.Errors.ExplicitExit(self.targets[0], sys.exc_value.code)
+ exc_value = sys.exc_info()[1]
+ raise SCons.Errors.ExplicitExit(self.targets[0], exc_value.code)
except SCons.Errors.UserError:
raise
except SCons.Errors.BuildError:
raise
except:
+ exc_type, exc_value, exc_traceback = sys.exc_info()
raise SCons.Errors.BuildError(self.targets[0],
"Exception",
- sys.exc_type,
- sys.exc_value,
- sys.exc_traceback)
+ exc_type,
+ exc_value,
+ exc_traceback)
def get_target(self):
"""Fetch the target being built or updated by this task.
for t in self.targets:
t.postprocess()
+ def exc_info(self):
+ return self.tm.exception
+
+ def exc_clear(self):
+ self.tm.exception_clear()
+
+ def exception_set(self):
+ self.tm.exception_set()
+
def order(dependencies):
self.tasker = tasker
self.ready = None # the next task that is ready to be executed
self.order = order
- self.exception_set(None, None)
+ self.exception_clear()
self.message = None
def _find_next_ready_node(self):
try:
children = node.children()
except SystemExit:
- e = SCons.Errors.ExplicitExit(node, sys.exc_value.code)
- self.exception_set(SCons.Errors.ExplicitExit, e)
+ exc_value = sys.exc_info()[1]
+ e = SCons.Errors.ExplicitExit(node, exc_value.code)
+ self.exception_set((SCons.Errors.ExplicitExit, e))
self.candidates.pop()
self.ready = node
break
# children (like a child couldn't be linked in to a
# BuildDir, or a Scanner threw something). Arrange to
# raise the exception when the Task is "executed."
- x = SCons.Errors.TaskmasterException(sys.exc_type,
- sys.exc_value,
- sys.exc_traceback)
- self.exception_set(x)
+ self.exception_set()
self.candidates.pop()
self.ready = node
break
# the kids are derived (like a child couldn't be linked
# from a repository). Arrange to raise the exception
# when the Task is "executed."
- x = SCons.Errors.TaskmasterException(sys.exc_type,
- sys.exc_value,
- sys.exc_traceback)
- self.exception_set(x)
+ self.exception_set()
self.candidates.pop()
self.ready = node
break
# a child couldn't be linked in to a BuildDir when deciding
# whether this node is current). Arrange to raise the
# exception when the Task is "executed."
- x = SCons.Errors.TaskmasterException(sys.exc_type,
- sys.exc_value,
- sys.exc_traceback)
- self.exception_set(x)
+ self.exception_set()
self.ready = None
return task
self.candidates.extend(self.pending)
self.pending = []
- def exception_set(self, type, value=None):
- """Record an exception type and value to raise later, at an
- appropriate time."""
- self.exc_type = type
- self.exc_value = value
- self.exc_traceback = traceback
+ def exception_set(self, exception=None):
+ if exception is None:
+ exception = sys.exc_info()
+ self.exception = exception
+ self.exception_raise = self._exception_raise
+
+ def exception_clear(self):
+ self.exception = (None, None, None)
+ self.exception_raise = self._no_exception_to_raise
- def exception_raise(self):
- """Raise any pending exception that was recorded while
+ def _no_exception_to_raise(self):
+ pass
+
+ def _exception_raise(self):
+ """Raise a pending exception that was recorded while
getting a Task ready for execution."""
- if self.exc_type:
- try:
- try:
- raise self.exc_type, self.exc_value
- except TypeError:
- # exc_type was probably an instance,
- # so raise it by itself.
- raise self.exc_type
- finally:
- self.exception_set(None, None)
+ exc_type, exc_value = self.exception[:2]
+ raise exc_type, exc_value
n1 = Node("n1")
tm = SCons.Taskmaster.Taskmaster(targets = [n1], tasker = MyTask)
t = tm.next_task()
- assert isinstance(tm.exc_type, SCons.Errors.TaskmasterException), repr(tm.exc_type)
- assert tm.exc_value is None, tm.exc_value
- e = tm.exc_type
- assert e.type == MyException, e.type
- assert str(e.value) == "from make_ready()", str(e.value)
+ exc_type, exc_value, exc_tb = tm.exception
+ assert exc_type == MyException, repr(exc_type)
+ assert str(exc_value) == "from make_ready()", exc_value
def test_make_ready_all(self):
n1 = StopNode("n1")
tm = SCons.Taskmaster.Taskmaster([n1])
t = tm.next_task()
- assert isinstance(tm.exc_type, SCons.Errors.TaskmasterException), repr(tm.exc_type)
- assert tm.exc_value is None, tm.exc_value
- e = tm.exc_type
- assert e.type == SCons.Errors.StopError, e.type
- assert str(e.value) == "stop!", "Unexpected exc_value `%s'" % e.value
+ exc_type, exc_value, exc_tb = tm.exception
+ assert exc_type == SCons.Errors.StopError, repr(exc_type)
+ assert str(exc_value) == "stop!", exc_value
n2 = ExitNode("n2")
tm = SCons.Taskmaster.Taskmaster([n2])
t = tm.next_task()
- assert tm.exc_type == SCons.Errors.ExplicitExit, "Did not record ExplicitExit on node"
- assert tm.exc_value.node == n2, tm.exc_value.node
- assert tm.exc_value.status == 77, tm.exc_value.status
+ exc_type, exc_value = tm.exception
+ assert exc_type == SCons.Errors.ExplicitExit, repr(exc_type)
+ assert exc_value.node == n2, exc_value.node
+ assert exc_value.status == 77, exc_value.status
def test_cycle_detection(self):
"""Test detecting dependency cycles
built_text = None
n5 = Node("n5")
tm = SCons.Taskmaster.Taskmaster([n5])
- tm.exc_type = MyException
- tm.exc_value = "exception value"
+ tm.exception_set((MyException, "exception value"))
t = tm.next_task()
exc_caught = None
try:
assert len(e.args) == 3, `e.args`
assert e.args[0] == OtherError, e.args[0]
assert isinstance(e.args[1], OtherError), type(e.args[1])
- assert type(e.args[2]) == type(sys.exc_traceback), e.args[2]
+ exc_traceback = sys.exc_info()[2]
+ assert type(e.args[2]) == type(exc_traceback), e.args[2]
else:
raise TestFailed, "did not catch expected BuildError"
n1 = Node("n1")
tm = SCons.Taskmaster.Taskmaster([n1])
- tm.exception_set(1, 2)
- assert tm.exc_type == 1, tm.exc_type
- assert tm.exc_value == 2, tm.exc_value
+ tm.exception_set((1, 2))
+ exc_type, exc_value = tm.exception
+ assert exc_type == 1, exc_type
+ assert exc_value == 2, exc_value
tm.exception_set(3)
- assert tm.exc_type == 3, tm.exc_type
- assert tm.exc_value is None, tm.exc_value
-
- tm.exception_set(None, None)
- assert tm.exc_type is None, tm.exc_type
- assert tm.exc_value is None, tm.exc_value
-
- tm.exception_set("exception 1", None)
+ assert tm.exception == 3
+
+ try: 1/0
+ except: pass
+ tm.exception_set(None)
+ exc_type, exc_value, exc_tb = tm.exception
+ assert exc_type is ZeroDivisionError, exc_type
+ exception_values = [
+ "integer division or modulo",
+ "integer division or modulo by zero",
+ ]
+ assert str(exc_value) in exception_values, exc_value
+
+ tm.exception_set(("exception 1", None))
try:
tm.exception_raise()
except:
- assert sys.exc_type == "exception 1", sys.exc_type
- assert sys.exc_value is None, sys.exc_value
+ exc_type, exc_value = sys.exc_info()[:2]
+ assert exc_type == "exception 1", exc_type
+ assert exc_value is None, exc_value
else:
assert 0, "did not catch expected exception"
- tm.exception_set("exception 2", "xyzzy")
+ tm.exception_set(("exception 2", "xyzzy"))
try:
tm.exception_raise()
except:
- assert sys.exc_type == "exception 2", sys.exc_type
- assert sys.exc_value == "xyzzy", sys.exc_value
+ exc_type, exc_value = sys.exc_info()[:2]
+ assert exc_type == "exception 2", exc_type
+ assert exc_value == "xyzzy", exc_value
else:
assert 0, "did not catch expected exception"
test.run(chdir = 'ro-src',
arguments = ".",
status = 2,
- stderr = None)
-test.fail_test(not test.match_re_dotall(test.stderr(), """\
-scons: \\*\\*\\* Cannot duplicate `src.file\\.in' in `build': Permission denied. Stop.
-scons: internal stack trace:
- File .*
-"""))
+ stderr = """\
+scons: *** Cannot duplicate `%s' in `build': Permission denied. Stop.
+""" % (os.path.join('src', 'file.in')))
test.run(chdir = 'ro-src',
arguments = "-k .",
status = 2,
- stderr = None)
-test.fail_test(not test.match_re_dotall(test.stderr(), """\
-scons: \\*\\*\\* Cannot duplicate `src.file\.in' in `build': Permission denied.
-scons: internal stack trace:
- File .*
-"""))
+ stderr = """\
+scons: *** Cannot duplicate `%s' in `build': Permission denied.
+""" % (os.path.join('src', 'file.in')))
f.close()
test.run(chdir = 'duplicate',
arguments = ".",
status = 2,
- stderr = None)
-test.fail_test(test.stderr() != """
+ stderr = """
scons: *** 'build' already has a source directory: 'src1'.
-File \"SConstruct\", line 2, in ?
+File "SConstruct", line 2, in ?
""")
test.pass_test()
test.run(arguments = '.',
status = 2,
- stderr = None)
-test.fail_test(not test.match_re_dotall(test.stderr(), """\
-scons: \\*\\*\\* kfile_scan error: yyy 1
-scons: internal stack trace:
- File .*
-"""))
+ stderr = """\
+scons: *** kfile_scan error: yyy 1
+""")
test.pass_test()