]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-42388: Fix subprocess.check_output input=None when text=True (GH-23467)
authorGregory P. Smith <greg@krypto.org>
Fri, 25 Dec 2020 04:57:21 +0000 (20:57 -0800)
committerGitHub <noreply@github.com>
Fri, 25 Dec 2020 04:57:21 +0000 (20:57 -0800)
When the modern text= spelling of the universal_newlines= parameter was added
for Python 3.7, check_output's special case around input=None was overlooked.
So it behaved differently with universal_newlines=True vs text=True.  This
reconciles the behavior to be consistent and adds a test to guarantee it.

Also clarifies the existing check_output documentation.

Co-authored-by: Alexey Izbyshev <izbyshev@ispras.ru>
Doc/library/subprocess.rst
Lib/subprocess.py
Lib/test/test_subprocess.py
Misc/NEWS.d/next/Library/2020-11-22-11-22-28.bpo-42388.LMgM6B.rst [new file with mode: 0644]

index 4ac3f80a319f80a51265111ea4769dea6d4d2e78..07b8ad77655dbeb4d403c81d682c083d560b1051 100644 (file)
@@ -1187,8 +1187,9 @@ calls these functions.
    The arguments shown above are merely some common ones.
    The full function signature is largely the same as that of :func:`run` -
    most arguments are passed directly through to that interface.
-   However, explicitly passing ``input=None`` to inherit the parent's
-   standard input file handle is not supported.
+   One API deviation from :func:`run` behavior exists: passing ``input=None``
+   will behave the same as ``input=b''`` (or ``input=''``, depending on other
+   arguments) rather than using the parent's standard input file handle.
 
    By default, this function will return the data as encoded bytes. The actual
    encoding of the output data may depend on the command being invoked, so the
index e259dc3a8e538af49a5a4dd4d62426f596c6a759..aa107cb60e461f2d836d21260856654ea3c84c7a 100644 (file)
@@ -420,7 +420,11 @@ def check_output(*popenargs, timeout=None, **kwargs):
     if 'input' in kwargs and kwargs['input'] is None:
         # Explicitly passing input=None was previously equivalent to passing an
         # empty string. That is maintained here for backwards compatibility.
-        kwargs['input'] = '' if kwargs.get('universal_newlines', False) else b''
+        if kwargs.get('universal_newlines') or kwargs.get('text'):
+            empty = ''
+        else:
+            empty = b''
+        kwargs['input'] = empty
 
     return run(*popenargs, stdout=PIPE, timeout=timeout, check=True,
                **kwargs).stdout
index 2a4c47530e6a1bd3c29f83f3c21364e704254f71..70b54f4155a9a5c06dc5c3558eaffa39ce535b46 100644 (file)
@@ -204,6 +204,28 @@ class ProcessTestCase(BaseTestCase):
                 input=b'pear')
         self.assertIn(b'PEAR', output)
 
+    def test_check_output_input_none(self):
+        """input=None has a legacy meaning of input='' on check_output."""
+        output = subprocess.check_output(
+                [sys.executable, "-c",
+                 "import sys; print('XX' if sys.stdin.read() else '')"],
+                input=None)
+        self.assertNotIn(b'XX', output)
+
+    def test_check_output_input_none_text(self):
+        output = subprocess.check_output(
+                [sys.executable, "-c",
+                 "import sys; print('XX' if sys.stdin.read() else '')"],
+                input=None, text=True)
+        self.assertNotIn('XX', output)
+
+    def test_check_output_input_none_universal_newlines(self):
+        output = subprocess.check_output(
+                [sys.executable, "-c",
+                 "import sys; print('XX' if sys.stdin.read() else '')"],
+                input=None, universal_newlines=True)
+        self.assertNotIn('XX', output)
+
     def test_check_output_stdout_arg(self):
         # check_output() refuses to accept 'stdout' argument
         with self.assertRaises(ValueError) as c:
diff --git a/Misc/NEWS.d/next/Library/2020-11-22-11-22-28.bpo-42388.LMgM6B.rst b/Misc/NEWS.d/next/Library/2020-11-22-11-22-28.bpo-42388.LMgM6B.rst
new file mode 100644 (file)
index 0000000..1b19247
--- /dev/null
@@ -0,0 +1,2 @@
+Fix subprocess.check_output(..., input=None) behavior when text=True to be
+consistent with that of the documentation and universal_newlines=True.