简体   繁体   中英

How do I catch a subprocess.call error with Python?

I'm trying to download a specific Docker image, where the user will input a version. However, if the version doesn't exist, Docker will throw an error.

I'm using subprocess.call to pipe to the Terminal from Python 3.

Sample code:

from subprocess import call
containerName = input("Enter Docker container name: ")
swVersion = input("Enter software version: ")

call(["docker", "run", "--name", "{}".format(containerName), 
      "--detach", "--publish", "8080:8080", "user/software:{}".format(swVersion)])

If the version isn't found, docker will output in the Terminal:

docker: Error response from daemon: manifest for user/software:8712378 not found.

How do I catch this error within the Python script?

Something along the lines of:

try:
    call(["docker", "run", "--name", "{}".format(containerName), "--detach", "--publish", "8080:8080", "user/software:{}".format(swVersion)])
except:
    # How do I catch the piped response code here?`

If you are fine with the program writing its output to stderr and you not directly interacting with it, the easiest way to do what you are asking is to use check_call instead of call . check_call will raise an exception if the command it's running exits with anything other than 0 as its status.

try:
    check_call(["docker", "run", "--name", "{}".format(containerName), "--detach", "--publish", "8080:8080", "user/software:{}".format(swVersion)])
except CalledProcessError:
    print("That command didn't work, try again")

You can use the Popen function of subprocess to grab the stderr and print in python console, as Documentation says for subprocess.call

Note Do not use stdout=PIPE or stderr=PIPE with this function as that can deadlock based on the child process output volume. Use Popen with the communicate() method when you need pipes.

proc = subprocess.Popen(["docker", "run", "--name", "{}".format(containerName), "--detach", "--publish", "8080:8080", "user/software:{}".format(swVersion)],stdout=subprocess.PIPE, stderr=subprocess.PIPE, creationflags=subprocess_flags)
proc.wait()
(stdout, stderr) = proc.communicate()

if proc.returncode != 0:
    print(stderr)
else:
    print("success")

The answer above with checking the return code works but the more pythonic way would be to catch an exception like:

try:
    proc = subprocess.Popen(["docker", "run", "--name", "{}".format(containerName), "--detach", "--publish", "8080:8080", "user/software:{}".format(swVersion)],stdout=subprocess.PIPE, stderr=subprocess.PIPE, creationflags=subprocess_flags)
    proc.wait()
    (stdout, stderr) = proc.communicate()

except calledProcessError as err:
    print("Error ocurred: " + err.stderr)

calledProcessError is the error caught by the Popen class.

If you want to catch the frequent errors on OS or system level (eg file/directory doesn't exist), add the following exceptions:

except OSError as e:
    print ("OSError > ",e.errno)
    print ("OSError > ",e.strerror)
    print ("OSError > ",e.filename)

except:
    print ("Error > ",sys.exc_info()[0])

If you want to return a return code, you should do that explicitly instead of print()ing it. Write after the last except statement and on the same indentation as the try statement:

return True

If you want to return a message, you can use the Response object:

return Response ("Success Message")

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM