gh-153970: Fix str() of CalledProcessError when returncode is not an integer (#153971)
vstinner <[email protected]> Fri, 07 Aug 2026 08:19:22 -0400 (EDT)
| Newsgroups | gmane.comp.python.cvs |
|---|---|
| Message-ID | <[email protected]> |
https://github.com/python/cpython/commit/7c653e2540cbe4180efb3bd83b63865a1f675650 commit: 7c653e2540cbe4180efb3bd83b63865a1f675650 branch: main author: Vyron Vasileiadis <[email protected]> committer: vstinner <[email protected]> date: 2026-08-07T14:19:07+02:00 summary: gh-153970: Fix str() of CalledProcessError when returncode is not an integer (#153971) CalledProcessError.__str__() fell through to a branch that formats the return code with %d, which raises TypeError when returncode is None. files: A Misc/NEWS.d/next/Library/2026-07-22-12-00-00.gh-issue-153970.Kq7Wn3.rst M Doc/library/subprocess.rst M Lib/subprocess.py M Lib/test/test_subprocess.py diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst index fe64daa3291d67..2a31213560c92d 100644 --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -236,8 +236,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 diff --git a/Lib/subprocess.py b/Lib/subprocess.py index 054860a19c74b6..a14fede00c391c 100644 --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -143,7 +143,7 @@ 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 %r died with %r." % ( self.cmd, signal.Signals(-self.returncode)) @@ -151,8 +151,8 @@ def __str__(self): return "Command %r died with unknown signal %d." % ( self.cmd, -self.returncode) else: - return "Command %r returned non-zero exit status %d." % ( - self.cmd, self.returncode) + return (f"Command {self.cmd!r} returned non-zero " + f"exit status {self.returncode}.") @property def stdout(self): diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index 4fd14d98b0324c..d1840e97d0f2f7 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -2449,6 +2449,16 @@ def test_CalledProcessError_str(self): err = subprocess.CalledProcessError(-9876543, "fake cmd") self.assertEqual(str(err), "Command 'fake cmd' died with unknown signal 9876543.") + # 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. diff --git a/Misc/NEWS.d/next/Library/2026-07-22-12-00-00.gh-issue-153970.Kq7Wn3.rst b/Misc/NEWS.d/next/Library/2026-07-22-12-00-00.gh-issue-153970.Kq7Wn3.rst new file mode 100644 index 00000000000000..def943b46b5942 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-22-12-00-00.gh-issue-153970.Kq7Wn3.rst @@ -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``. _______________________________________________ Python-checkins mailing list -- [email protected] To unsubscribe send an email to [email protected] https://mail.python.org/mailman3//lists/python-checkins.python.org Member address: [email protected]