'Python subprocess check_call, native way to print STDERR if it fails?

I often wish to perform the action of subprocess.check_output, i.e. print STDOUT live, and check the return code is 0 on exit. However if there is an error, I would like the STDERR to be printed. When looking at log files and just seeing the return code is often not very beneficial.

E.g.:

subprocess.check_call(['ping', '-c', '1', 'github.com2'])

Will generate this error:

subprocess.CalledProcessError: Command '['ping', '-c', '1', 'github.com2']' returned non-zero exit status 2.

Here we are left wondering why it failed, on real world examples it becomes critical to be able to see what the actual error is. So I find I always have to wrap such calls in something like this to be able to see STDERR:

import subprocess
cmds = ['ping', '-c', '1', 'github.com2']
result = subprocess.run(cmds, stderr=subprocess.PIPE)
if result.returncode != 0:
    msg = result.stderr.decode().strip()
    raise subprocess.CalledProcessError(f"CALLED SUBPROCESS ERROR: Command: {' '.join(cmds)}\nReturn code {result.returncode}\nSTDERR: {msg}\n")

With the above one gets to see that STDERR is:

ping: github.com2: Temporary failure in name resolution

I feel there must be a built in way using subprocess, but can't figure it out.

Im guessing it's not possible because CalledSubprocessError does not use STDERR is the string version of the exception:

class CalledProcessError(SubprocessError):
    """Raised when run() is called with check=True and the process
    returns a non-zero exit status.

    Attributes:
      cmd, returncode, stdout, stderr, output
    """
    def __init__(self, returncode, cmd, output=None, stderr=None):
        self.returncode = returncode
        self.cmd = cmd
        self.output = output
        self.stderr = stderr

    def __str__(self):
        if self.returncode and self.returncode < 0:
            try:
                return "Command '%s' died with %r." % (
                        self.cmd, signal.Signals(-self.returncode))
            except ValueError:
                return "Command '%s' died with unknown signal %d." % (
                        self.cmd, -self.returncode)
        else:
            return "Command '%s' returned non-zero exit status %d." % (
                    self.cmd, self.returncode)

    @property
    def stdout(self):
        """Alias for output attribute, to match stderr"""
        return self.output

    @stdout.setter
    def stdout(self, value):
        # There's no obvious reason to set this, but allow it anyway so
        # .stdout is a transparent alias for .output
        self.output = value


Solution 1:[1]

Calling subprocess.run(..., check=True) should provide all the needed info. From the manual: "If check is true, and the process exits with a non-zero exit code, a CalledProcessError exception will be raised. Attributes of that exception hold the arguments, the exit code, and stdout and stderr if they were captured."

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Tzane