From: Ben Darnell Date: Sat, 18 Apr 2015 18:12:44 +0000 (-0400) Subject: Add raise_error behavior to Subprocess.wait_for_exit. X-Git-Tag: v4.2.0b1~23 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2bd2f0db087c12738ac55aba75fe78fe31987dd0;p=thirdparty%2Ftornado.git Add raise_error behavior to Subprocess.wait_for_exit. Closes #1205. --- diff --git a/tornado/process.py b/tornado/process.py index fb9254fc0..f580e1925 100644 --- a/tornado/process.py +++ b/tornado/process.py @@ -49,6 +49,10 @@ except NameError: long = int # py3 +# Re-export this exception for convenience. +CalledProcessError = subprocess.CalledProcessError + + def cpu_count(): """Returns the number of processors on this machine.""" if multiprocessing is None: @@ -259,7 +263,7 @@ class Subprocess(object): Subprocess._waiting[self.pid] = self Subprocess._try_cleanup_process(self.pid) - def wait_for_exit(self): + def wait_for_exit(self, raise_error=True): """Returns a `.Future` which resolves when the process exits. Usage:: @@ -269,10 +273,21 @@ class Subprocess(object): This is a coroutine-friendly alternative to `set_exit_callback` (and a replacement for the blocking `subprocess.Popen.wait`). + By default, raises `subprocess.CalledProcessError` if the process + has a non-zero exit status. Use ``wait_for_exit(raise_error=False)`` + to suppress this behavior and return the exit status without raising. + .. versionadded:: 4.2 """ future = Future() - self.set_exit_callback(future.set_result) + + def callback(ret): + if ret != 0 and raise_error: + # Unfortunately we don't have the original args any more. + future.set_exception(CalledProcessError(ret, None)) + else: + future.set_result(ret) + self.set_exit_callback(callback) return future @classmethod diff --git a/tornado/test/process_test.py b/tornado/test/process_test.py index 72474167c..58cc410b6 100644 --- a/tornado/test/process_test.py +++ b/tornado/test/process_test.py @@ -222,3 +222,22 @@ class SubprocessTest(AsyncTestCase): ret = self.wait() self.assertEqual(subproc.returncode, ret) self.assertEqual(ret, -signal.SIGTERM) + + @gen_test + def test_wait_for_exit_raise(self): + skip_if_twisted() + Subprocess.initialize() + self.addCleanup(Subprocess.uninitialize) + subproc = Subprocess([sys.executable, '-c', 'import sys; sys.exit(1)']) + with self.assertRaises(subprocess.CalledProcessError) as cm: + yield subproc.wait_for_exit() + self.assertEqual(cm.exception.returncode, 1) + + @gen_test + def test_wait_for_exit_raise_disabled(self): + skip_if_twisted() + Subprocess.initialize() + self.addCleanup(Subprocess.uninitialize) + subproc = Subprocess([sys.executable, '-c', 'import sys; sys.exit(1)']) + ret = yield subproc.wait_for_exit(raise_error=False) + self.assertEqual(ret, 1)