[Python-checkins] cpython (3.2): Issue #16903: Popen.communicate() on Unix now accepts strings when

serhiy.storchaka python-checkins at python.org
Mon Feb 4 15:52:15 CET 2013


http://hg.python.org/cpython/rev/4206f91c974c
changeset:   81997:4206f91c974c
branch:      3.2
parent:      81994:086eb1fe3082
user:        Serhiy Storchaka <storchaka at gmail.com>
date:        Mon Feb 04 16:47:39 2013 +0200
summary:
  Issue #16903: Popen.communicate() on Unix now accepts strings when
universal_newlines is true as on Windows.

files:
  Doc/library/subprocess.rst  |   7 +++--
  Lib/subprocess.py           |   4 +++
  Lib/test/test_subprocess.py |  31 +++++++++++++++++++++++-
  Misc/NEWS                   |   3 ++
  4 files changed, 40 insertions(+), 5 deletions(-)


diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst
--- a/Doc/library/subprocess.rst
+++ b/Doc/library/subprocess.rst
@@ -537,9 +537,10 @@
 .. 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
--- a/Lib/subprocess.py
+++ b/Lib/subprocess.py
@@ -1519,6 +1519,8 @@
                 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 @@
                 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
--- a/Lib/test/test_subprocess.py
+++ b/Lib/test/test_subprocess.py
@@ -608,8 +608,6 @@
                              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 @@
         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
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -212,6 +212,9 @@
 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.
 

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list