Add support for nosetests multiprocessing plugin.
[sawsim.git] / pysawsim / invoke.py
index d7c10b5c778f9d38118be0cd2093fd9b17a01557..2d8103fab178e6dab14ae1eb298e3e881c89ec23 100644 (file)
@@ -24,17 +24,57 @@ from subprocess import Popen, PIPE
 import sys
 
 
+_multiprocess_can_split_ = True
+"""Allow nosetests to split tests between processes.
+"""
+
+
 class CommandError(Exception):
-    def __init__(self, command, status, stdout, stderr):
-        strerror = ["Command failed (%d):\n  %s\n" % (status, stderr),
-                    "while executing\n  %s" % command]
-        Exception.__init__(self, "\n".join(strerror))
+    """Represent errors in command execution.
+
+    Instances are picklable (for passing through `multiprocessing.Queue`\s).
+
+    >>> import pickle
+    >>> a = CommandError('somefunc', 1, '', 'could not find "somefunc"')
+    >>> x = pickle.dumps(a)
+    >>> b = pickle.loads(x)
+    >>> print b
+    Command failed (1):
+      could not find "somefunc"
+    <BLANKLINE>
+    while executing
+      somefunc
+    >>> print repr(b)  # doctest: +NORMALIZE_WHITESPACE
+    CommandError(command='somefunc', status=1, stdout='',
+                 stderr='could not find "somefunc"')
+    """
+    def __init__(self, command=None, status=None, stdout=None, stderr=None):
         self.command = command
         self.status = status
         self.stdout = stdout
         self.stderr = stderr
+        Exception.__init__(self, self.__str__())
+
+    def __getstate__(self):
+        return self.__dict__
+
+    def __setstate__(self, data):
+        self.__dict__.update(data)
+
+    def __str__(self):
+        return "\n".join([
+                "Command failed (%s):\n  %s\n" % (self.status, self.stderr),
+                "while executing\n  %s" % self.command,
+                ])
+
+    def __repr__(self):
+        return '%s(%s)' % (
+            self.__class__.__name__,
+            ', '.join(['%s=%s' % (attr, repr(getattr(self, attr)))
+                       for attr in ['command', 'status', 'stdout', 'stderr']]))
+
 
-def invoke(cmd_string, stdin=None, expect=(0,), cwd=None, verbose=True):
+def invoke(cmd_string, stdin=None, expect=(0,), cwd=None, verbose=False):
     """
     expect should be a tuple of allowed exit codes.  cwd should be
     the directory from which the command will be executed.
@@ -51,11 +91,11 @@ def invoke(cmd_string, stdin=None, expect=(0,), cwd=None, verbose=True):
             q = Popen(cmd_string, stdin=PIPE, stdout=PIPE, stderr=PIPE,
                       shell=True, cwd=cwd)
     except OSError, e :
-        raise CommandError(args, status=e.args[0], stdout="", stderr=e)
-    output,error = q.communicate(input=stdin)
+        raise CommandError(cmd_string, status=e.args[0], stdout="", stderr=e)
+    stdout,stderr = q.communicate(input=stdin)
     status = q.wait()
     if verbose == True:
-        print >> sys.stderr, "%d\n%s%s" % (status, output, error)
+        print >> sys.stderr, "%d\n%s%s" % (status, stdout, stderr)
     if status not in expect:
-        raise CommandError(args, status, output, error)
-    return status, output, error
+        raise CommandError(cmd_string, status, stdout, stderr)
+    return status, stdout, stderr