diff -r 760f222103c7 Doc/library/subprocess.rst --- a/Doc/library/subprocess.rst Mon Mar 02 09:36:48 2015 -0500 +++ b/Doc/library/subprocess.rst Tue Mar 03 13:05:19 2015 +0100 @@ -533,9 +533,17 @@ functions. with Popen(["ifconfig"], stdout=PIPE) as proc: log.write(proc.stdout.read()) + The context manager ignores broken pipe errors when closing the process's + stdin: call explicitly ``proc.stdin.flush()`` and ``proc.stdin.close()`` to + get broken pipe errors. + .. versionchanged:: 3.2 Added context manager support. + .. versionchanged:: 3.5 + The context manager support now ignores broken pipe errors as + the :meth:`~Popen.communicate` method. + Exceptions ^^^^^^^^^^ @@ -642,6 +650,11 @@ Instances of the :class:`Popen` class ha ``None`` in the result tuple, you need to give ``stdout=PIPE`` and/or ``stderr=PIPE`` too. + Broken pipe errors are ignored when sending data to the process's stdin. If + the process exits before reading all input data or closes its stdin, the + parent gets a broken pipe error. The method ignore this error and so may not + send all *input* data. + If the process does not terminate after *timeout* seconds, a :exc:`TimeoutExpired` exception will be raised. Catching this exception and retrying communication will not lose any output. diff -r 760f222103c7 Lib/subprocess.py --- a/Lib/subprocess.py Mon Mar 02 09:36:48 2015 -0500 +++ b/Lib/subprocess.py Tue Mar 03 13:05:19 2015 +0100 @@ -489,6 +489,20 @@ STDOUT = -2 DEVNULL = -3 +def _ignore_epipe(func, *args): + try: + func(*args) + except BrokenPipeError: + pass + except OSError as e: + if e.errno == errno.EINVAL and self.poll() is not None: + # Issue #19612: On Windows, writing into stdin pipe fails with + # EINVAL if the process already exited before the write + pass + else: + raise + + # XXX This function is only used by multiprocessing and the test suite, # but it's here so that it can be imported when Python is compiled without # threads. @@ -892,12 +906,12 @@ class Popen(object): self.stdout.close() if self.stderr: self.stderr.close() - try: # Flushing a BufferedWriter may raise an error - if self.stdin: - self.stdin.close() - finally: - # Wait for the process to terminate, to avoid zombies. - self.wait() + if self.stdin: + # Ignore broken pipe error when closing stdin. stdin is buffered: + # close() can flush buffered data and so write data. + _ignore_epipe(self.stdin.close) + # Wait for the process to terminate, to avoid zombies. + self.wait() def __del__(self, _maxsize=sys.maxsize): if not self._child_created: @@ -916,19 +930,12 @@ class Popen(object): def _stdin_write(self, input): if input: - try: - self.stdin.write(input) - except BrokenPipeError: - # communicate() must ignore broken pipe error - pass - except OSError as e: - if e.errno == errno.EINVAL and self.poll() is not None: - # Issue #19612: On Windows, stdin.write() fails with EINVAL - # if the process already exited before the write - pass - else: - raise - self.stdin.close() + # communicate() must ignore broken pipe error + _ignore_epipe(self.stdin.write, input) + + # stdin is buffered: close() can flush buffered data and so write + # data. We also want to catch errors on close() + _ignore_epipe(self.stdin.close) def communicate(self, input=None, timeout=None): """Interact with process: Send data to stdin. Read data from