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:
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::
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
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)