Skip to content

Commit 0272411

Browse files
committed
bpo-39744: make asyncio.subprocess communicate similar to non-asyncio one
subprocess's communicate(None) closes stdin of the child process, after sending no (extra) data. Make asyncio variant do the same. This fixes issues with processes that waits for EOF on stdin before continuing.
1 parent 9169a56 commit 0272411

File tree

3 files changed

+25
-5
lines changed

3 files changed

+25
-5
lines changed

Lib/asyncio/subprocess.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -144,10 +144,11 @@ def kill(self):
144144

145145
async def _feed_stdin(self, input):
146146
debug = self._loop.get_debug()
147-
self.stdin.write(input)
148-
if debug:
149-
logger.debug(
150-
'%r communicate: feed stdin (%s bytes)', self, len(input))
147+
if input is not None:
148+
self.stdin.write(input)
149+
if debug:
150+
logger.debug(
151+
'%r communicate: feed stdin (%s bytes)', self, len(input))
151152
try:
152153
await self.stdin.drain()
153154
except (BrokenPipeError, ConnectionResetError) as exc:
@@ -180,7 +181,7 @@ async def _read_stream(self, fd):
180181
return output
181182

182183
async def communicate(self, input=None):
183-
if input is not None:
184+
if self.stdin is not None:
184185
stdin = self._feed_stdin(input)
185186
else:
186187
stdin = self._noop()

Lib/test/test_asyncio/test_subprocess.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,24 @@ async def run(data):
151151
self.assertEqual(exitcode, 0)
152152
self.assertEqual(stdout, b'some data')
153153

154+
def test_communicate_none_input(self):
155+
args = PROGRAM_CAT
156+
157+
async def run():
158+
proc = await asyncio.create_subprocess_exec(
159+
*args,
160+
stdin=subprocess.PIPE,
161+
stdout=subprocess.PIPE,
162+
)
163+
stdout, stderr = await proc.communicate()
164+
return proc.returncode, stdout
165+
166+
task = run()
167+
task = asyncio.wait_for(task, support.LONG_TIMEOUT)
168+
exitcode, stdout = self.loop.run_until_complete(task)
169+
self.assertEqual(exitcode, 0)
170+
self.assertEqual(stdout, b'')
171+
154172
def test_shell(self):
155173
proc = self.loop.run_until_complete(
156174
asyncio.create_subprocess_shell('exit 7')
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Make func:``asyncio.subprocess.Process.communicate`` close subprocess's stdin even when called with input=None

0 commit comments

Comments
 (0)