Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Doc/library/subprocess.rst
Original file line number Diff line number Diff line change
Expand Up @@ -239,8 +239,8 @@ underlying :class:`Popen` interface can be used directly.

.. attribute:: returncode

Exit status of the child process. If the process exited due to a
signal, this will be the negative signal number.
Exit status of the child process, an integer. If the process
exited due to a signal, this will be the negative signal number.

.. attribute:: cmd

Expand Down
6 changes: 3 additions & 3 deletions Lib/subprocess.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,16 +143,16 @@ def __init__(self, returncode, cmd, output=None, stderr=None):
self.stderr = stderr

def __str__(self):
if self.returncode and self.returncode < 0:
if isinstance(self.returncode, int) 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)
return (f"Command '{self.cmd}' returned non-zero "
f"exit status {self.returncode}.")

@property
def stdout(self):
Expand Down
10 changes: 10 additions & 0 deletions Lib/test/test_subprocess.py
Original file line number Diff line number Diff line change
Expand Up @@ -2414,6 +2414,16 @@ def test_CalledProcessError_str_non_zero(self):
error_string = str(err)
self.assertIn("non-zero exit status 2.", error_string)

# returncode which is not an integer, which happens for example when
# Popen is mocked: str() must not fail
for returncode in (None, "2", 2.5, [2]):
with self.subTest(returncode=returncode):
err = subprocess.CalledProcessError(returncode, "fake cmd")
self.assertEqual(
str(err),
f"Command 'fake cmd' returned non-zero "
f"exit status {returncode}.")

def test_preexec(self):
# DISCLAIMER: Setting environment variables is *not* a good use
# of a preexec_fn. This is merely a test.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Calling :func:`str` on a :exc:`subprocess.CalledProcessError` no longer
raises :exc:`TypeError` when its :attr:`!returncode` is not an integer, such
as ``None``.
Loading