Skip to content

Commit ace514b

Browse files
fedonmanamericano212
authored andcommitted
[3.13] gh-153970: Fix str() of CalledProcessError when returncode is not an integer (GH-153971)
CalledProcessError.__str__() fell through to a branch that formats the return code with %d, which raises TypeError when returncode is None. (cherry picked from commit 7c653e2) Co-authored-by: Vyron Vasileiadis <hi@fedonman.com>
1 parent b0a181d commit ace514b

4 files changed

Lines changed: 18 additions & 5 deletions

File tree

Doc/library/subprocess.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -239,8 +239,8 @@ underlying :class:`Popen` interface can be used directly.
239239

240240
.. attribute:: returncode
241241

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

245245
.. attribute:: cmd
246246

Lib/subprocess.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,16 +143,16 @@ def __init__(self, returncode, cmd, output=None, stderr=None):
143143
self.stderr = stderr
144144

145145
def __str__(self):
146-
if self.returncode and self.returncode < 0:
146+
if isinstance(self.returncode, int) and self.returncode < 0:
147147
try:
148148
return "Command '%s' died with %r." % (
149149
self.cmd, signal.Signals(-self.returncode))
150150
except ValueError:
151151
return "Command '%s' died with unknown signal %d." % (
152152
self.cmd, -self.returncode)
153153
else:
154-
return "Command '%s' returned non-zero exit status %d." % (
155-
self.cmd, self.returncode)
154+
return (f"Command '{self.cmd}' returned non-zero "
155+
f"exit status {self.returncode}.")
156156

157157
@property
158158
def stdout(self):

Lib/test/test_subprocess.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2414,6 +2414,16 @@ def test_CalledProcessError_str_non_zero(self):
24142414
error_string = str(err)
24152415
self.assertIn("non-zero exit status 2.", error_string)
24162416

2417+
# returncode which is not an integer, which happens for example when
2418+
# Popen is mocked: str() must not fail
2419+
for returncode in (None, "2", 2.5, [2]):
2420+
with self.subTest(returncode=returncode):
2421+
err = subprocess.CalledProcessError(returncode, "fake cmd")
2422+
self.assertEqual(
2423+
str(err),
2424+
f"Command 'fake cmd' returned non-zero "
2425+
f"exit status {returncode}.")
2426+
24172427
def test_preexec(self):
24182428
# DISCLAIMER: Setting environment variables is *not* a good use
24192429
# of a preexec_fn. This is merely a test.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Calling :func:`str` on a :exc:`subprocess.CalledProcessError` no longer
2+
raises :exc:`TypeError` when its :attr:`!returncode` is not an integer, such
3+
as ``None``.

0 commit comments

Comments
 (0)