bpo-42388: Fix subprocess.check_output input=None when text=True (GH-23467)
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>
diff --git a/Lib/subprocess.py b/Lib/subprocess.py
index e259dc3..aa107cb 100644
--- a/Lib/subprocess.py
+++ b/Lib/subprocess.py
@@ -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
diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py
index 2a4c475..70b54f4 100644
--- a/Lib/test/test_subprocess.py
+++ b/Lib/test/test_subprocess.py
@@ -204,6 +204,28 @@ def test_check_output_input_arg(self):
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: