From: Andrew Svetlov Date: Tue, 14 Aug 2012 15:40:21 +0000 (+0300) Subject: Issue #15592. Fix regression: subprocess.communicate() breaks on no input with univer... X-Git-Tag: v3.3.0rc1~115 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=aa0dbdc2ddb4cfe1669ac83a24673a8ef4ee1fc4;p=python Issue #15592. Fix regression: subprocess.communicate() breaks on no input with universal newlines true. Patch by Chris Jerdonek. --- aa0dbdc2ddb4cfe1669ac83a24673a8ef4ee1fc4 diff --cc Lib/subprocess.py index 7885ba37af,179f41a85f..35f6f965c5 --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@@ -1536,12 -1455,12 +1536,23 @@@ class Popen(object) return (stdout, stderr) - def _communicate_with_poll(self, input): ++ def _save_input(self, input): ++ # This method is called from the _communicate_with_*() methods ++ # so that if we time out while communicating, we can continue ++ # sending input if we retry. ++ if self.stdin and self._input is None: ++ self._input_offset = 0 ++ self._input = input ++ if self.universal_newlines and input is not None: ++ self._input = self._input.encode(self.stdin.encoding) ++ ++ + def _communicate_with_poll(self, input, endtime, orig_timeout): stdout = None # Return stderr = None # Return - fd2file = {} - fd2output = {} + + if not self._communication_started: + self._fd2file = {} poller = select.poll() def register_and_append(file_obj, eventmask): @@@ -1567,25 -1478,15 +1578,19 @@@ select_POLLIN_POLLPRI = select.POLLIN | select.POLLPRI if self.stdout: register_and_append(self.stdout, select_POLLIN_POLLPRI) - fd2output[self.stdout.fileno()] = stdout = [] + stdout = self._fd2output[self.stdout.fileno()] if self.stderr: register_and_append(self.stderr, select_POLLIN_POLLPRI) - fd2output[self.stderr.fileno()] = stderr = [] + stderr = self._fd2output[self.stderr.fileno()] - # Save the input here so that if we time out while communicating, - # we can continue sending input if we retry. - if self.stdin and self._input is None: - self._input_offset = 0 - self._input = input - if self.universal_newlines: - self._input = self._input.encode(self.stdin.encoding) - input_offset = 0 - while fd2file: ++ self._save_input(input) + + while self._fd2file: + timeout = self._remaining_time(endtime) + if timeout is not None and timeout < 0: + raise TimeoutExpired(self.args, orig_timeout) try: - ready = poller.poll() + ready = poller.poll(timeout) except select.error as e: if e.args[0] == errno.EINTR: continue @@@ -1621,23 -1520,9 +1626,19 @@@ return (stdout, stderr) - def _communicate_with_select(self, input): - read_set = [] - write_set = [] + def _communicate_with_select(self, input, endtime, orig_timeout): + if not self._communication_started: + self._read_set = [] + self._write_set = [] + if self.stdin and input: + self._write_set.append(self.stdin) + if self.stdout: + self._read_set.append(self.stdout) + if self.stderr: + self._read_set.append(self.stderr) + - if self.stdin and self._input is None: - self._input_offset = 0 - self._input = input - if self.universal_newlines: - self._input = self._input.encode(self.stdin.encoding) ++ self._save_input(input) + stdout = None # Return stderr = None # Return diff --cc Lib/test/test_subprocess.py index 552b13ebd9,9e92a96227..e591d2fd56 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@@ -615,8 -528,8 +615,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")