subprocess.check_output(): show output on failure

2019-04-19 09:24发布

The output of subprocess.check_output() looks like this at the moment:

CalledProcessError: Command '['foo', ...]' returned non-zero exit status 1

Is there a way to get a better error message?

I want to see stdout and stderr.

4条回答
时光不老,我们不散
2楼-- · 2019-04-19 09:44

Redirect STDERR to STDOUT.

Example from the interpreter:

>>> try:
...   subprocess.check_output(['ls','-j'], stderr=subprocess.STDOUT)
... except subprocess.CalledProcessError as e:
...   print('error>', e.output, '<')
...

Will throw:

error> b"ls: invalid option -- 'j'\nTry `ls --help' for more information.\n" <

Explantion

From check_output documentation:

To also capture standard error in the result, use stderr=subprocess.STDOUT

查看更多
放我归山
3楼-- · 2019-04-19 09:53

Don't use check_output(), use Popen and Popen.communicate() instead:

>>> proc = subprocess.Popen(['cmd', '--optional-switch'])
>>> output, errors = proc.communicate()

Here output is data from stdout and errors is data from stderr.

查看更多
叼着烟拽天下
4楼-- · 2019-04-19 09:57

In my opinion that a perfect scenario to use sys.excepthook! You just have to filter what you would like to be formatted as you want in the if statement. With this solution, it will cover every exception of your code without having to refract everything!

#!/usr/bin/env python
import sys
import subprocess

# Create the exception handler function
def my_excepthook(type, value, traceback):
    # Check if the exception type name is CalledProcessError
    if type.__name__ == "CalledProcessError":
        # Format the error properly
        sys.stderr.write("Error: " + type.__name__ + "\nCommand: " + value.cmd + "\nOutput: " + value.output.strip())
    # Else we format the exception normally
    else:
        sys.stderr.write(str(value))

# We attach every exceptions to the function my_excepthook
sys.excepthook = my_excepthook

# We duplicate the exception
subprocess.check_output("dir /f",shell=True,stderr=subprocess.STDOUT)

You can modify the output as you wish, here is the actual ouput:

Error: CalledProcessError
Command: dir /f
Output: Invalid switch - "f".
查看更多
老娘就宠你
5楼-- · 2019-04-19 10:00

Since I don't want to write more code, just to get a good error message, I wrote subx

From the docs:

subprocess.check_output() vs subx.call()

Look, compare, think and decide what message helps your more.

subprocess.check_output()::

CalledProcessError: Command '['cat', 'some-file']' returned non-zero exit status 1

sub.call()::

SubprocessError: Command '['cat', 'some-file']' returned non-zero exit status 1:
stdout='' stderr='cat: some-file: No such file or directory'

... especially if the code fails in a production environment where reproducing the error is not easy, subx can call help you to spot the source of the failure.

查看更多
登录 后发表回答