Commit b3f194d1 authored by Serhiy Storchaka's avatar Serhiy Storchaka

Issue #16903: Popen.communicate() on Unix now accepts strings when

universal_newlines is true as on Windows.
parent 0b4591e0
...@@ -538,8 +538,9 @@ Instances of the :class:`Popen` class have the following methods: ...@@ -538,8 +538,9 @@ Instances of the :class:`Popen` class have the following methods:
Interact with process: Send data to stdin. Read data from stdout and stderr, 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 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 *input* argument should be data to be sent to the child process, or
``None``, if no data should be sent to the child. ``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)``. :meth:`communicate` returns a tuple ``(stdoutdata, stderrdata)``.
......
...@@ -1519,6 +1519,8 @@ class Popen(object): ...@@ -1519,6 +1519,8 @@ class Popen(object):
fd2output[self.stderr.fileno()] = stderr = [] fd2output[self.stderr.fileno()] = stderr = []
input_offset = 0 input_offset = 0
if self.universal_newlines and isinstance(input, str):
input = input.encode(self.stdin.encoding)
while fd2file: while fd2file:
try: try:
ready = poller.poll() ready = poller.poll()
...@@ -1571,6 +1573,8 @@ class Popen(object): ...@@ -1571,6 +1573,8 @@ class Popen(object):
stderr = [] stderr = []
input_offset = 0 input_offset = 0
if self.universal_newlines and isinstance(input, str):
input = input.encode(self.stdin.encoding)
while read_set or write_set: while read_set or write_set:
try: try:
rlist, wlist, xlist = select.select(read_set, write_set, []) rlist, wlist, xlist = select.select(read_set, write_set, [])
......
...@@ -608,8 +608,6 @@ class ProcessTestCase(BaseTestCase): ...@@ -608,8 +608,6 @@ class ProcessTestCase(BaseTestCase):
universal_newlines=1) universal_newlines=1)
self.addCleanup(p.stdout.close) self.addCleanup(p.stdout.close)
self.addCleanup(p.stderr.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() (stdout, stderr) = p.communicate()
self.assertEqual(stdout, self.assertEqual(stdout,
"line2\nline4\nline5\nline6\nline7\nline8") "line2\nline4\nline5\nline6\nline7\nline8")
...@@ -640,6 +638,35 @@ class ProcessTestCase(BaseTestCase): ...@@ -640,6 +638,35 @@ class ProcessTestCase(BaseTestCase):
p.communicate() p.communicate()
self.assertEqual(p.returncode, 0) 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): def test_universal_newlines_communicate_encodings(self):
# Check that universal newlines mode works for various encodings, # Check that universal newlines mode works for various encodings,
# in particular for encodings in the UTF-16 and UTF-32 families. # in particular for encodings in the UTF-16 and UTF-32 families.
......
...@@ -212,6 +212,9 @@ Core and Builtins ...@@ -212,6 +212,9 @@ Core and Builtins
Library 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 - Issue #6083: Fix multiple segmentation faults occured when PyArg_ParseTuple
parses nested mutating sequence. parses nested mutating sequence.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment