summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2013-02-04 14:47:39 (GMT)
committerSerhiy Storchaka <storchaka@gmail.com>2013-02-04 14:47:39 (GMT)
commitb3f194d10951d5c23af885c6d55c45dfb0db0666 (patch)
treeaa40c095d34ff160840f755604fb389f88487940
parent0b4591e0eb80b78b4c6a4aa6a4071c74c253bde7 (diff)
downloadcpython-b3f194d10951d5c23af885c6d55c45dfb0db0666.zip
cpython-b3f194d10951d5c23af885c6d55c45dfb0db0666.tar.gz
cpython-b3f194d10951d5c23af885c6d55c45dfb0db0666.tar.bz2
Issue #16903: Popen.communicate() on Unix now accepts strings when
universal_newlines is true as on Windows.
-rw-r--r--Doc/library/subprocess.rst7
-rw-r--r--Lib/subprocess.py4
-rw-r--r--Lib/test/test_subprocess.py31
-rw-r--r--Misc/NEWS3
4 files changed, 40 insertions, 5 deletions
diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst
index fc456a1..b4adc02 100644
--- a/Doc/library/subprocess.rst
+++ b/Doc/library/subprocess.rst
@@ -537,9 +537,10 @@ Instances of the :class:`Popen` class have the following methods:
.. method:: Popen.communicate(input=None)
Interact with process: Send data to stdin. Read data from stdout and stderr,
- until end-of-file is reached. Wait for process to terminate. The optional
- *input* argument should be a byte string to be sent to the child process, or
- ``None``, if no data should be sent to the child.
+ until end-of-file is reached. Wait for process to terminate. The optional
+ *input* argument should be data to be sent to the child process, or
+ ``None``, if no data should be sent to the child. The type of *input*
+ must be bytes or, if *universal_newlines* was ``True``, a string.
:meth:`communicate` returns a tuple ``(stdoutdata, stderrdata)``.
diff --git a/Lib/subprocess.py b/Lib/subprocess.py
index f32f081e..1a21455 100644
--- a/Lib/subprocess.py
+++ b/Lib/subprocess.py
@@ -1519,6 +1519,8 @@ class Popen(object):
fd2output[self.stderr.fileno()] = stderr = []
input_offset = 0
+ if self.universal_newlines and isinstance(input, str):
+ input = input.encode(self.stdin.encoding)
while fd2file:
try:
ready = poller.poll()
@@ -1571,6 +1573,8 @@ class Popen(object):
stderr = []
input_offset = 0
+ if self.universal_newlines and isinstance(input, str):
+ input = input.encode(self.stdin.encoding)
while read_set or write_set:
try:
rlist, wlist, xlist = select.select(read_set, write_set, [])
diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py
index 921328f..45ba373 100644
--- a/Lib/test/test_subprocess.py
+++ b/Lib/test/test_subprocess.py
@@ -608,8 +608,6 @@ class ProcessTestCase(BaseTestCase):
universal_newlines=1)
self.addCleanup(p.stdout.close)
self.addCleanup(p.stderr.close)
- # BUG: can't give a non-empty stdin because it breaks both the
- # select- and poll-based communicate() implementations.
(stdout, stderr) = p.communicate()
self.assertEqual(stdout,
"line2\nline4\nline5\nline6\nline7\nline8")
@@ -640,6 +638,35 @@ class ProcessTestCase(BaseTestCase):
p.communicate()
self.assertEqual(p.returncode, 0)
+ def test_universal_newlines_communicate_stdin_stdout_stderr(self):
+ # universal newlines through communicate(), with stdin, stdout, stderr
+ p = subprocess.Popen([sys.executable, "-c",
+ 'import sys,os;' + SETBINARY + '''\nif True:
+ s = sys.stdin.buffer.readline()
+ sys.stdout.buffer.write(s)
+ sys.stdout.buffer.write(b"line2\\r")
+ sys.stderr.buffer.write(b"eline2\\n")
+ s = sys.stdin.buffer.read()
+ sys.stdout.buffer.write(s)
+ sys.stdout.buffer.write(b"line4\\n")
+ sys.stdout.buffer.write(b"line5\\r\\n")
+ sys.stderr.buffer.write(b"eline6\\r")
+ sys.stderr.buffer.write(b"eline7\\r\\nz")
+ '''],
+ stdin=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ universal_newlines=True)
+ self.addCleanup(p.stdout.close)
+ self.addCleanup(p.stderr.close)
+ (stdout, stderr) = p.communicate("line1\nline3\n")
+ self.assertEqual(p.returncode, 0)
+ self.assertEqual("line1\nline2\nline3\nline4\nline5\n", stdout)
+ # Python debug build push something like "[42442 refs]\n"
+ # to stderr at exit of subprocess.
+ # Don't use assertStderrEqual because it strips CR and LF from output.
+ self.assertTrue(stderr.startswith("eline2\neline6\neline7\n"))
+
def test_universal_newlines_communicate_encodings(self):
# Check that universal newlines mode works for various encodings,
# in particular for encodings in the UTF-16 and UTF-32 families.
diff --git a/Misc/NEWS b/Misc/NEWS
index c5a64c2..7a04599 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -212,6 +212,9 @@ Core and Builtins
Library
-------
+- Issue #16903: Popen.communicate() on Unix now accepts strings when
+ universal_newlines is true as on Windows.
+
- Issue #6083: Fix multiple segmentation faults occured when PyArg_ParseTuple
parses nested mutating sequence.