I've figured out how to use call() to get my python script to run a command:
import subprocess
mycommandline = ['lumberjack', '-sleep all night', '-work all day']
subprocess.call(mycommandline)
This works but there's a problem, what if users don't have lumberjack in their command path? It would work if lumberjack was put in the same directory as the python script, but how does the script know it should look for lumberjack? I figured if there was a command-not-found error then lumberjack wouldn't be in the command path, the script could try to figure out what its directory is and look for lumberjack there and finally warn the user to copy lumberjack into one of those two places if it wasn't found in either one. How do I find out what the error message is? I read that check_call() can return an error message and something about a returncode attribute. I couldn't find examples on how to use check_call() and returncode, what the message would be or how I could tell if the message is command-not-found.
Am I even going about this the right way?
A simple snippet:
subprocess
will raise an exception,OSError
, when a command is not found.When the command is found, and
subprocess
runs the command for you, the result code is returned from the command. The standard is that code 0 means success, and any failure is some non-zero error code (which varies; check the documentation for the specific command you are running).So, if you catch
OSError
you can handle the non-existent command, and if you check the result code you can find out whether the command succeeded or not.The great thing about
subprocess
is that you can make it collect all the text fromstdout
andstderr
, and you can then discard it or return it or log it or display it as you like. I often use a wrapper that discards all output from a command, unless the command fails in which case the text fromstderr
is output.I agree that you shouldn't be asking users to copy executables around. Programs should be in a directory listed in the
PATH
variable; if a program is missing it should be installed, or if it is installed in a directory not on thePATH
the user should update thePATH
to include that directory.Note that you do have the option of trying
subprocess
multiple times with various hard-coded paths to executables:EDIT: After thinking about it a little bit, I decided to completely rewrite the above. It's much cleaner to just pass a list of locations, and have a loop try the alternative locations until one works. But I didn't want to build the string for the user's home directory if it wasn't needed, so I just made it legal to put a callable into the list of alternatives. If you have any questions about this, just ask.
Wow, that was fast! I combined Theodros Zelleke's simple example and steveha's use of functions with abarnert comment about OSError and Lattyware's comment about moving files:
I tested it on Mac OS-X (6.8/Snow Leopard), Debian (Squeeze) and Windows (7). It seemed to work the way I wanted it to on all three operating systems. I tried using check_call and CalledProcessError but no matter what I did, I seemed to get an error every time and I couldn't get the script to handle the errors. To test the script I changed the name from 'lumberjack' to 'deadparrot', since I had lumberjack in the directory with my script.
Do you see any problems with this script the way it's written?