'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 |
