[Python-Dev] Two patches for the new subprocess module

Nick Craig-Wood nick at craig-wood.com
Tue Nov 23 16:08:46 CET 2004


I have submitted two patches for the subprocess module against cvs
HEAD.  The first notifies the user of a common mistake and the second
adds an IHMO very important utility function.

I'd consider the first to be a bug fix and the second a new feature.
However a rather nice new feature ;-)

------------------------------------------------------------
[ 1071755 ] raise error for common mistake with subprocess
http://python.org/sf/1071755
------------------------------------------------------------

subprocess has a very easy to mistake error in it - forgetting to pass
the command as a list.  Eg

>>> import subprocess
>>> subprocess.call("ls")
BaseHTTPServer.py      dummy_threading.py  pickletools.py   socket.py
Bastion.py             email               pipes.py         sre.py
[...]
dummy_thread.py        pickle.pyc          sndhdr.py        zipfile.py
0
>>> subprocess.call("ls", "-l")
BaseHTTPServer.py      dummy_threading.py  pickletools.py   socket.py
Bastion.py             email               pipes.py         sre.py
[...]
dummy_thread.py        pickle.pyc          sndhdr.py        zipfile.py
0
>>> 

# Note no error, warning or anything, but no "ls -l" either

And with the patch...

>>> subprocess.call("ls", "-l")
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  File "subprocess.py", line 428, in call
    return Popen(*args, **kwargs).wait()
  File "subprocess.py", line 508, in __init__
    raise TypeError("bufsize must be an integer - "
TypeError: bufsize must be an integer - did you forget to pass your arguments in a list?
>>> 

------------------------------------------------------------
[ 1071764 ] a new subprocess.call which raises an error on non-zero rc
http://python.org/sf/1071764
------------------------------------------------------------

The attached patch introduces a 3rd utility function - xcall() to the
subprocess module.  This function acts just like call but raises
errors if the command had a non-zero return code.

This saves writing

if call(...):
    raise OSError(...)

It is most useful for shell script replacement programming.  Checking
the return codes of commands called is often forgotten in shell
programming.

When you've moved up to python because shell is too limiting (usually
about 10 lines of shell in my case ;-) you want to make sure that all
your commands work so you write robust code.

I consider raising an exception to be much more pythonic than checking
a return code (ie "Errors should never pass silently" from Zen of
Python)

Eg

# An easy to miss error

>>> subprocess.call(["mkdir", "a/b"])
mkdir: cannot create directory `a/b': No such file or directory
1
>>> # user forgot to check non-zero return code

# becomes an impossible to miss exception

>>> subprocess.xcall(["mkdir", "a/b"])
mkdir: cannot create directory `a/b': No such file or directory
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  File "subprocess.py", line 462, in xcall
    raise CalledProcessError(rc, "Command %s returned non zero exit status" % args[0])
subprocess.CalledProcessError: [Errno 1] Command ['mkdir', 'a/b'] returned non zero exit status
>>> 

See patch for more!  Its been tested under python 2.3 on windows and
linux.

-- 
Nick Craig-Wood <nick at craig-wood.com> -- http://www.craig-wood.com/nick


More information about the Python-Dev mailing list