diff -r 12502327d2c0 Lib/subprocess.py
--- a/Lib/subprocess.py Tue Feb 16 13:27:45 2016 +1100
+++ b/Lib/subprocess.py Wed Feb 17 12:12:07 2016 +0100
@@ -1021,7 +1021,7 @@ class Popen(object):
try:
self.stdin.write(input)
except BrokenPipeError:
- # communicate() must ignore broken pipe error
+ # communicate() must ignore broken pipe error on stdin
pass
except OSError as e:
if e.errno == errno.EINVAL and self.poll() is not None:
@@ -1030,7 +1030,12 @@ class Popen(object):
pass
else:
raise
- self.stdin.close()
+
+ try:
+ self.stdin.close()
+ except BrokenPipeError:
+ # communicate() must ignore broken pipe error on stdin
+ pass
def communicate(self, input=None, timeout=None):
"""Interact with process: Send data to stdin. Read data from
@@ -1666,11 +1671,15 @@ class Popen(object):
def _communicate(self, input, endtime, orig_timeout):
if self.stdin and not self._communication_started:
- # Flush stdio buffer. This might block, if the user has
- # been writing to .stdin in an uncontrolled fashion.
- self.stdin.flush()
- if not input:
- self.stdin.close()
+ try:
+ # Flush stdio buffer. This might block, if the user has
+ # been writing to .stdin in an uncontrolled fashion.
+ self.stdin.flush()
+ if not input:
+ self.stdin.close()
+ except BrokenPipeError:
+ # communicate() must ignore broken pipe error on stdin
+ pass
stdout = None
stderr = None
diff -r 12502327d2c0 Lib/test/test_subprocess.py
--- a/Lib/test/test_subprocess.py Tue Feb 16 13:27:45 2016 +1100
+++ b/Lib/test/test_subprocess.py Wed Feb 17 12:12:07 2016 +0100
@@ -1,4 +1,5 @@
import unittest
+from unittest import mock
from test.support import script_helper
from test import support
import subprocess
@@ -2664,6 +2665,30 @@ class ContextManagerTests(BaseTestCase):
self.assertEqual(proc.returncode, 0)
self.assertTrue(proc.stdin.closed)
+ def test_broken_pipe_stdin_close(self):
+ # Issue #26372: BrokenPipeError must be ignored on stdin.close()
+ # in communicate()
+ proc = subprocess.Popen([sys.executable, '-c', 'pass'],
+ stdin=subprocess.PIPE)
+ with proc, mock.patch.object(proc, 'stdin') as m_stdin:
+ m_stdin.close.side_effect = BrokenPipeError
+
+ # check that BrokenPipeError exception raised by stdin.close()
+ # in _stdin_write() is ignored
+ proc.communicate()
+
+ def test_broken_pipe_stdin_close_timeout(self):
+ # Issue #26372: BrokenPipeError must be ignored on stdin.close()
+ # in communicate()
+ proc = subprocess.Popen([sys.executable, '-c', 'pass'],
+ stdin=subprocess.PIPE)
+ with proc, mock.patch.object(proc, 'stdin') as m_stdin:
+ m_stdin.close.side_effect = BrokenPipeError
+
+ # check that BrokenPipeError exception raised by stdin.close()
+ # in _communicate() is ignored
+ proc.communicate(timeout=1.0)
+
def test_main():
unit_tests = (ProcessTestCase,