Commit e02891b4 authored by Antoine Pitrou's avatar Antoine Pitrou

Issue #12591: Improve support of "universal newlines" in the subprocess

module: the piped streams can now be properly read from or written to.
parents 664091be ab85ff3d
...@@ -728,7 +728,7 @@ class Popen(object): ...@@ -728,7 +728,7 @@ class Popen(object):
if p2cwrite != -1: if p2cwrite != -1:
self.stdin = io.open(p2cwrite, 'wb', bufsize) self.stdin = io.open(p2cwrite, 'wb', bufsize)
if self.universal_newlines: if self.universal_newlines:
self.stdin = io.TextIOWrapper(self.stdin) self.stdin = io.TextIOWrapper(self.stdin, write_through=True)
if c2pread != -1: if c2pread != -1:
self.stdout = io.open(c2pread, 'rb', bufsize) self.stdout = io.open(c2pread, 'rb', bufsize)
if universal_newlines: if universal_newlines:
......
...@@ -557,44 +557,75 @@ class ProcessTestCase(BaseTestCase): ...@@ -557,44 +557,75 @@ class ProcessTestCase(BaseTestCase):
def test_universal_newlines(self): def test_universal_newlines(self):
p = subprocess.Popen([sys.executable, "-c", p = subprocess.Popen([sys.executable, "-c",
'import sys,os;' + SETBINARY + 'import sys,os;' + SETBINARY +
'sys.stdout.write("line1\\n");' 'sys.stdout.write(sys.stdin.readline());'
'sys.stdout.flush();' 'sys.stdout.flush();'
'sys.stdout.write("line2\\n");' 'sys.stdout.write("line2\\n");'
'sys.stdout.flush();' 'sys.stdout.flush();'
'sys.stdout.write("line3\\r\\n");' 'sys.stdout.write(sys.stdin.read());'
'sys.stdout.flush();' 'sys.stdout.flush();'
'sys.stdout.write("line4\\r");' 'sys.stdout.write("line4\\n");'
'sys.stdout.flush();' 'sys.stdout.flush();'
'sys.stdout.write("\\nline5");' 'sys.stdout.write("line5\\r\\n");'
'sys.stdout.flush();' 'sys.stdout.flush();'
'sys.stdout.write("\\nline6");'], 'sys.stdout.write("line6\\r");'
'sys.stdout.flush();'
'sys.stdout.write("\\nline7");'
'sys.stdout.flush();'
'sys.stdout.write("\\nline8");'],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
universal_newlines=1) universal_newlines=1)
p.stdin.write("line1\n")
self.assertEqual(p.stdout.readline(), "line1\n")
p.stdin.write("line3\n")
p.stdin.close()
self.addCleanup(p.stdout.close) self.addCleanup(p.stdout.close)
stdout = p.stdout.read() self.assertEqual(p.stdout.readline(),
self.assertEqual(stdout, "line1\nline2\nline3\nline4\nline5\nline6") "line2\n")
self.assertEqual(p.stdout.read(6),
"line3\n")
self.assertEqual(p.stdout.read(),
"line4\nline5\nline6\nline7\nline8")
def test_universal_newlines_communicate(self): def test_universal_newlines_communicate(self):
# universal newlines through communicate() # universal newlines through communicate()
p = subprocess.Popen([sys.executable, "-c", p = subprocess.Popen([sys.executable, "-c",
'import sys,os;' + SETBINARY + 'import sys,os;' + SETBINARY +
'sys.stdout.write("line1\\n");'
'sys.stdout.flush();'
'sys.stdout.write("line2\\n");' 'sys.stdout.write("line2\\n");'
'sys.stdout.flush();' 'sys.stdout.flush();'
'sys.stdout.write("line3\\r\\n");' 'sys.stdout.write("line4\\n");'
'sys.stdout.flush();'
'sys.stdout.write("line5\\r\\n");'
'sys.stdout.flush();' 'sys.stdout.flush();'
'sys.stdout.write("line4\\r");' 'sys.stdout.write("line6\\r");'
'sys.stdout.flush();' 'sys.stdout.flush();'
'sys.stdout.write("\\nline5");' 'sys.stdout.write("\\nline7");'
'sys.stdout.flush();' 'sys.stdout.flush();'
'sys.stdout.write("\\nline6");'], 'sys.stdout.write("\\nline8");'],
stdout=subprocess.PIPE, stderr=subprocess.PIPE, stderr=subprocess.PIPE,
stdout=subprocess.PIPE,
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, "line1\nline2\nline3\nline4\nline5\nline6") self.assertEqual(stdout,
"line2\nline4\nline5\nline6\nline7\nline8")
def test_universal_newlines_communicate_stdin(self):
# universal newlines through communicate(), with only stdin
p = subprocess.Popen([sys.executable, "-c",
'import sys,os;' + SETBINARY + '''\nif True:
s = sys.stdin.readline()
assert s == "line1\\n", repr(s)
s = sys.stdin.read()
assert s == "line3\\n", repr(s)
'''],
stdin=subprocess.PIPE,
universal_newlines=1)
(stdout, stderr) = p.communicate("line1\nline3\n")
self.assertEqual(p.returncode, 0)
def test_no_leaking(self): def test_no_leaking(self):
# Make sure we leak no resources # Make sure we leak no resources
...@@ -1658,7 +1689,8 @@ def test_main(): ...@@ -1658,7 +1689,8 @@ def test_main():
ProcessTestCaseNoPoll, ProcessTestCaseNoPoll,
HelperFunctionTests, HelperFunctionTests,
CommandsWithSpaces, CommandsWithSpaces,
ContextManagerTests) ContextManagerTests,
)
support.run_unittest(*unit_tests) support.run_unittest(*unit_tests)
support.reap_children() support.reap_children()
......
...@@ -237,6 +237,9 @@ Core and Builtins ...@@ -237,6 +237,9 @@ Core and Builtins
Library Library
------- -------
- Issue #12591: Improve support of "universal newlines" in the subprocess
module: the piped streams can now be properly read from or written to.
- Issue #12591: Allow io.TextIOWrapper to work with raw IO objects (without - Issue #12591: Allow io.TextIOWrapper to work with raw IO objects (without
a read1() method), and add a *write_through* parameter to mandate a read1() method), and add a *write_through* parameter to mandate
unbuffered writes. unbuffered writes.
......
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