summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAntoine Pitrou <solipsis@pitrou.net>2011-07-23 20:04:41 (GMT)
committerAntoine Pitrou <solipsis@pitrou.net>2011-07-23 20:04:41 (GMT)
commite02891b459b6a903b71dce1dfb1399419eaefaaf (patch)
tree2cc4bec3fa7b826cc952c256b0e8f0f12c0e5d67
parent664091be72c8b1620cea239bf8ae0be19570709d (diff)
parentab85ff3d1a35011d09fc2e6a25a02d65f798bde4 (diff)
downloadcpython-e02891b459b6a903b71dce1dfb1399419eaefaaf.zip
cpython-e02891b459b6a903b71dce1dfb1399419eaefaaf.tar.gz
cpython-e02891b459b6a903b71dce1dfb1399419eaefaaf.tar.bz2
Issue #12591: Improve support of "universal newlines" in the subprocess
module: the piped streams can now be properly read from or written to.
-rw-r--r--Lib/subprocess.py2
-rw-r--r--Lib/test/test_subprocess.py64
-rw-r--r--Misc/NEWS3
3 files changed, 52 insertions, 17 deletions
diff --git a/Lib/subprocess.py b/Lib/subprocess.py
index 83e6c40..ec417c2 100644
--- a/Lib/subprocess.py
+++ b/Lib/subprocess.py
@@ -728,7 +728,7 @@ class Popen(object):
if p2cwrite != -1:
self.stdin = io.open(p2cwrite, 'wb', bufsize)
if self.universal_newlines:
- self.stdin = io.TextIOWrapper(self.stdin)
+ self.stdin = io.TextIOWrapper(self.stdin, write_through=True)
if c2pread != -1:
self.stdout = io.open(c2pread, 'rb', bufsize)
if universal_newlines:
diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py
index 2bf49f2..3921436 100644
--- a/Lib/test/test_subprocess.py
+++ b/Lib/test/test_subprocess.py
@@ -557,44 +557,75 @@ class ProcessTestCase(BaseTestCase):
def test_universal_newlines(self):
p = subprocess.Popen([sys.executable, "-c",
'import sys,os;' + SETBINARY +
- 'sys.stdout.write("line1\\n");'
+ 'sys.stdout.write(sys.stdin.readline());'
'sys.stdout.flush();'
'sys.stdout.write("line2\\n");'
'sys.stdout.flush();'
- 'sys.stdout.write("line3\\r\\n");'
+ 'sys.stdout.write(sys.stdin.read());'
'sys.stdout.flush();'
- 'sys.stdout.write("line4\\r");'
+ 'sys.stdout.write("line4\\n");'
'sys.stdout.flush();'
- 'sys.stdout.write("\\nline5");'
+ 'sys.stdout.write("line5\\r\\n");'
'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,
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)
- stdout = p.stdout.read()
- self.assertEqual(stdout, "line1\nline2\nline3\nline4\nline5\nline6")
+ self.assertEqual(p.stdout.readline(),
+ "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):
# universal newlines through communicate()
p = subprocess.Popen([sys.executable, "-c",
'import sys,os;' + SETBINARY +
- 'sys.stdout.write("line1\\n");'
- 'sys.stdout.flush();'
'sys.stdout.write("line2\\n");'
'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.write("line4\\r");'
+ 'sys.stdout.write("line6\\r");'
'sys.stdout.flush();'
- 'sys.stdout.write("\\nline5");'
+ 'sys.stdout.write("\\nline7");'
'sys.stdout.flush();'
- 'sys.stdout.write("\\nline6");'],
- stdout=subprocess.PIPE, stderr=subprocess.PIPE,
+ 'sys.stdout.write("\\nline8");'],
+ stderr=subprocess.PIPE,
+ stdout=subprocess.PIPE,
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, "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):
# Make sure we leak no resources
@@ -1658,7 +1689,8 @@ def test_main():
ProcessTestCaseNoPoll,
HelperFunctionTests,
CommandsWithSpaces,
- ContextManagerTests)
+ ContextManagerTests,
+ )
support.run_unittest(*unit_tests)
support.reap_children()
diff --git a/Misc/NEWS b/Misc/NEWS
index 089b07a..74da530 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -237,6 +237,9 @@ Core and Builtins
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
a read1() method), and add a *write_through* parameter to mandate
unbuffered writes.