20

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.

1

4 Answers 4

14

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

Sign up to request clarification or add additional context in comments.

2 Comments

Are you capturing STDOUT here or STDERR?
For me this worked - I just needed to print the exception output to get what I wanted (the failure text of the command while still catching the exceptoin).
6

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.

Comments

2

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.

Comments

1

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".

1 Comment

This changes the global stuff which can effect code which gets executed hours after calling the lines of the above question. Yes, your solution works, but I prefer a solution which does no global change. I have a problem with the library. I would like to solve the issue at this level. (for example use an alternative library).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.