]> granicus.if.org Git - python/commitdiff
Issue #27167: Clarify the subprocess.CalledProcessError error message text
authorGregory P. Smith ext:(%20%5BGoogle%20Inc.%5D) <greg@krypto.org>
Fri, 3 Jun 2016 06:14:06 +0000 (06:14 +0000)
committerGregory P. Smith ext:(%20%5BGoogle%20Inc.%5D) <greg@krypto.org>
Fri, 3 Jun 2016 06:14:06 +0000 (06:14 +0000)
when the child process died due to a signal.

Lib/subprocess.py
Lib/test/test_subprocess.py
Misc/NEWS

index b853f4d59323e042bfe428f4cfe4a67d2086a04b..716f7fff534322fcb3a8d92e73f342e98da500cf 100644 (file)
@@ -372,9 +372,11 @@ class SubprocessError(Exception): pass
 
 
 class CalledProcessError(SubprocessError):
-    """This exception is raised when a process run by check_call() or
-    check_output() returns a non-zero exit status.
-    The exit status will be stored in the returncode attribute;
+    """Raised when a check_call() or check_output() process returns non-zero.
+
+    The exit status will be stored in the returncode attribute, negative
+    if it represents a signal number.
+
     check_output() will also store the output in the output attribute.
     """
     def __init__(self, returncode, cmd, output=None, stderr=None):
@@ -384,7 +386,16 @@ class CalledProcessError(SubprocessError):
         self.stderr = stderr
 
     def __str__(self):
-        return "Command '%s' returned non-zero exit status %d" % (self.cmd, self.returncode)
+        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):
index a8f0a64e96e0d10620599affa347daccf544c380..8a2352bf9549b9376a38510d9463353a20dbd03a 100644 (file)
@@ -1427,6 +1427,25 @@ class POSIXProcessTestCase(BaseTestCase):
             p.wait()
         self.assertEqual(-p.returncode, signal.SIGABRT)
 
+    def test_CalledProcessError_str_signal(self):
+        err = subprocess.CalledProcessError(-int(signal.SIGABRT), "fake cmd")
+        error_string = str(err)
+        # We're relying on the repr() of the signal.Signals intenum to provide
+        # the word signal, the signal name and the numeric value.
+        self.assertIn("signal", error_string.lower())
+        self.assertIn("SIGABRT", error_string)
+        self.assertIn(str(signal.SIGABRT), error_string)
+
+    def test_CalledProcessError_str_unknown_signal(self):
+        err = subprocess.CalledProcessError(-9876543, "fake cmd")
+        error_string = str(err)
+        self.assertIn("unknown signal 9876543.", error_string)
+
+    def test_CalledProcessError_str_non_zero(self):
+        err = subprocess.CalledProcessError(2, "fake cmd")
+        error_string = str(err)
+        self.assertIn("non-zero exit status 2.", error_string)
+
     def test_preexec(self):
         # DISCLAIMER: Setting environment variables is *not* a good use
         # of a preexec_fn.  This is merely a test.
index 4220062837394ee734e27022ec0ca3287934f234..57edb4963059858a5b601ac10c26af8607be0486 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -22,6 +22,9 @@ Core and Builtins
 Library
 -------
 
+- Issue #27167: Clarify the subprocess.CalledProcessError error message text
+  when the child process died due to a signal.
+
 - Issue #25931: Don't define socketserver.Forking* names on platforms such
   as Windows that do not support os.fork().