From 454f76711c14f0a55119601bfe56a1ab5d2c0e04 Mon Sep 17 00:00:00 2001 From: Peter Astrand Date: Sat, 1 Jan 2005 09:36:35 +0000 Subject: [PATCH] New subprocess utility function: check_call. Closes #1071764. --- Doc/lib/libsubprocess.tex | 18 ++++++++++++++++- Lib/subprocess.py | 40 ++++++++++++++++++++++++++++++++++++- Lib/test/test_subprocess.py | 16 +++++++++++++++ 3 files changed, 72 insertions(+), 2 deletions(-) diff --git a/Doc/lib/libsubprocess.tex b/Doc/lib/libsubprocess.tex index 308c1dd40f9..5a2a835f1e6 100644 --- a/Doc/lib/libsubprocess.tex +++ b/Doc/lib/libsubprocess.tex @@ -120,7 +120,7 @@ process. (Windows only) \subsubsection{Convenience Functions} -This module also defines one shortcut function: +This module also defines two shortcut functions: \begin{funcdesc}{call}{*popenargs, **kwargs} Run command with arguments. Wait for command to complete, then @@ -133,6 +133,18 @@ The arguments are the same as for the Popen constructor. Example: \end{verbatim} \end{funcdesc} +\begin{funcdesc}{check_call}{*popenargs, **kwargs} +Run command with arguments. Wait for command to complete. If the exit +code was zero then return, otherwise raise CalledProcessError. The +CalledProcessError object will have the return code in the +\member{errno} attribute. + +The arguments are the same as for the Popen constructor. Example: + +\begin{verbatim} + check_call(["ls", "-l"]) +\end{verbatim} +\end{funcdesc} \subsubsection{Exceptions} @@ -149,6 +161,10 @@ should prepare for \exception{OSError} exceptions. A \exception{ValueError} will be raised if \class{Popen} is called with invalid arguments. +check_call() will raise \exception{CalledProcessError}, which is a +subclass of \exception{OSError}, if the called process returns a +non-zero return code. + \subsubsection{Security} diff --git a/Lib/subprocess.py b/Lib/subprocess.py index 40b04fe39ff..da0c31b6c93 100644 --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -133,6 +133,15 @@ call(*popenargs, **kwargs): retcode = call(["ls", "-l"]) +check_call(*popenargs, **kwargs): + Run command with arguments. Wait for command to complete. If the + exit code was zero then return, otherwise raise + CalledProcessError. The CalledProcessError object will have the + return code in the errno attribute. + + The arguments are the same as for the Popen constructor. Example: + + check_call(["ls", "-l"]) Exceptions ---------- @@ -148,6 +157,9 @@ should prepare for OSErrors. A ValueError will be raised if Popen is called with invalid arguments. +check_call() will raise CalledProcessError, which is a subclass of +OSError, if the called process returns a non-zero return code. + Security -------- @@ -363,6 +375,13 @@ import os import types import traceback +# Exception classes used by this module. +class CalledProcessError(OSError): + """This exception is raised when a process run by check_call() returns + a non-zero exit status. The exit status will be stored in the + errno attribute. This exception is a subclass of + OSError.""" + if mswindows: import threading import msvcrt @@ -393,7 +412,7 @@ else: import fcntl import pickle -__all__ = ["Popen", "PIPE", "STDOUT", "call"] +__all__ = ["Popen", "PIPE", "STDOUT", "call", "check_call", "CalledProcessError"] try: MAXFD = os.sysconf("SC_OPEN_MAX") @@ -428,6 +447,25 @@ def call(*popenargs, **kwargs): return Popen(*popenargs, **kwargs).wait() +def check_call(*popenargs, **kwargs): + """Run command with arguments. Wait for command to complete. If + the exit code was zero then return, otherwise raise + CalledProcessError. The CalledProcessError object will have the + return code in the errno attribute. + + The arguments are the same as for the Popen constructor. Example: + + check_call(["ls", "-l"]) + """ + retcode = call(*popenargs, **kwargs) + cmd = kwargs.get("args") + if cmd is None: + cmd = popenargs[0] + if retcode: + raise CalledProcessError(retcode, "Command %s returned non-zero exit status" % cmd) + return retcode + + def list2cmdline(seq): """ Translate a sequence of arguments into a command line diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index b26d40cb29d..52f4d4711d2 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -44,6 +44,22 @@ class ProcessTestCase(unittest.TestCase): "import sys; sys.exit(47)"]) self.assertEqual(rc, 47) + def test_check_call_zero(self): + # check_call() function with zero return code + rc = subprocess.check_call([sys.executable, "-c", + "import sys; sys.exit(0)"]) + self.assertEqual(rc, 0) + + def test_check_call_nonzero(self): + # check_call() function with non-zero return code + try: + subprocess.check_call([sys.executable, "-c", + "import sys; sys.exit(47)"]) + except subprocess.CalledProcessError, e: + self.assertEqual(e.errno, 47) + else: + self.fail("Expected CalledProcessError") + def test_call_kwargs(self): # call() function with keyword args newenv = os.environ.copy()