From 9e9e37bea3267e758a1561b9d14b3c1de21b3791 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= Date: Mon, 24 Feb 2020 23:18:41 +0100 Subject: [PATCH 1/4] 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. --- Doc/library/asyncio-subprocess.rst | 5 +++-- Lib/asyncio/subprocess.py | 11 ++++++----- Lib/test/test_asyncio/test_subprocess.py | 18 ++++++++++++++++++ .../2020-02-25-00-43-22.bpo-39744.hgK689.rst | 1 + 4 files changed, 28 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-02-25-00-43-22.bpo-39744.hgK689.rst diff --git a/Doc/library/asyncio-subprocess.rst b/Doc/library/asyncio-subprocess.rst index 4274638c5e8625..ee2c71efa70ea7 100644 --- a/Doc/library/asyncio-subprocess.rst +++ b/Doc/library/asyncio-subprocess.rst @@ -207,8 +207,9 @@ their completion. Interact with process: 1. send data to *stdin* (if *input* is not ``None``); - 2. read data from *stdout* and *stderr*, until EOF is reached; - 3. wait for process to terminate. + 2. closes *stdin*; + 3. read data from *stdout* and *stderr*, until EOF is reached; + 4. wait for process to terminate. The optional *input* argument is the data (:class:`bytes` object) that will be sent to the child process. diff --git a/Lib/asyncio/subprocess.py b/Lib/asyncio/subprocess.py index cd10231f710f11..50727ca300e63e 100644 --- a/Lib/asyncio/subprocess.py +++ b/Lib/asyncio/subprocess.py @@ -144,10 +144,11 @@ def kill(self): async def _feed_stdin(self, input): debug = self._loop.get_debug() - self.stdin.write(input) - if debug: - logger.debug( - '%r communicate: feed stdin (%s bytes)', self, len(input)) + if input is not None: + self.stdin.write(input) + if debug: + logger.debug( + '%r communicate: feed stdin (%s bytes)', self, len(input)) try: await self.stdin.drain() except (BrokenPipeError, ConnectionResetError) as exc: @@ -180,7 +181,7 @@ async def _read_stream(self, fd): return output async def communicate(self, input=None): - if input is not None: + if self.stdin is not None: stdin = self._feed_stdin(input) else: stdin = self._noop() diff --git a/Lib/test/test_asyncio/test_subprocess.py b/Lib/test/test_asyncio/test_subprocess.py index eba6e2d1f28f3e..eeeca40c15cd28 100644 --- a/Lib/test/test_asyncio/test_subprocess.py +++ b/Lib/test/test_asyncio/test_subprocess.py @@ -151,6 +151,24 @@ async def run(data): self.assertEqual(exitcode, 0) self.assertEqual(stdout, b'some data') + def test_communicate_none_input(self): + args = PROGRAM_CAT + + async def run(): + proc = await asyncio.create_subprocess_exec( + *args, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + ) + stdout, stderr = await proc.communicate() + return proc.returncode, stdout + + task = run() + task = asyncio.wait_for(task, support.LONG_TIMEOUT) + exitcode, stdout = self.loop.run_until_complete(task) + self.assertEqual(exitcode, 0) + self.assertEqual(stdout, b'') + def test_shell(self): proc = self.loop.run_until_complete( asyncio.create_subprocess_shell('exit 7') diff --git a/Misc/NEWS.d/next/Library/2020-02-25-00-43-22.bpo-39744.hgK689.rst b/Misc/NEWS.d/next/Library/2020-02-25-00-43-22.bpo-39744.hgK689.rst new file mode 100644 index 00000000000000..791cf04f8b795d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-02-25-00-43-22.bpo-39744.hgK689.rst @@ -0,0 +1 @@ +Make func:``asyncio.subprocess.Process.communicate`` close subprocess's stdin even when called with input=None From 0ff1c2e2f2577d876313a805ce254550a029c519 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= Date: Thu, 27 Apr 2023 12:51:47 +0200 Subject: [PATCH 2/4] bpo-39744: update docs --- Doc/library/asyncio-subprocess.rst | 4 ++++ .../next/Library/2020-02-25-00-43-22.bpo-39744.hgK689.rst | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Doc/library/asyncio-subprocess.rst b/Doc/library/asyncio-subprocess.rst index ee2c71efa70ea7..b7c83aa04c09f1 100644 --- a/Doc/library/asyncio-subprocess.rst +++ b/Doc/library/asyncio-subprocess.rst @@ -230,6 +230,10 @@ their completion. Note, that the data read is buffered in memory, so do not use this method if the data size is large or unlimited. + .. versionchanged:: 3.12 + + *stdin* gets closed when `input=None` too. + .. method:: send_signal(signal) Sends the signal *signal* to the child process. diff --git a/Misc/NEWS.d/next/Library/2020-02-25-00-43-22.bpo-39744.hgK689.rst b/Misc/NEWS.d/next/Library/2020-02-25-00-43-22.bpo-39744.hgK689.rst index 791cf04f8b795d..21012bc8f620b6 100644 --- a/Misc/NEWS.d/next/Library/2020-02-25-00-43-22.bpo-39744.hgK689.rst +++ b/Misc/NEWS.d/next/Library/2020-02-25-00-43-22.bpo-39744.hgK689.rst @@ -1 +1 @@ -Make func:``asyncio.subprocess.Process.communicate`` close subprocess's stdin even when called with input=None +Make func:``asyncio.subprocess.Process.communicate`` close subprocess's stdin even when called with `input=None` From 4efe16bb08830f3406644f57b3756625865b6b21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= Date: Thu, 27 Apr 2023 12:52:54 +0200 Subject: [PATCH 3/4] bpo-39744: news file update --- .../next/Library/2020-02-25-00-43-22.bpo-39744.hgK689.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2020-02-25-00-43-22.bpo-39744.hgK689.rst b/Misc/NEWS.d/next/Library/2020-02-25-00-43-22.bpo-39744.hgK689.rst index 21012bc8f620b6..6c54bc504fafc8 100644 --- a/Misc/NEWS.d/next/Library/2020-02-25-00-43-22.bpo-39744.hgK689.rst +++ b/Misc/NEWS.d/next/Library/2020-02-25-00-43-22.bpo-39744.hgK689.rst @@ -1 +1 @@ -Make func:``asyncio.subprocess.Process.communicate`` close subprocess's stdin even when called with `input=None` +Make :func:`asyncio.subprocess.Process.communicate` close the subprocess's stdin even when called with `input=None`. From d3223a3659540ade144bca5c77267a1586b6db3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= Date: Thu, 27 Apr 2023 12:58:37 +0200 Subject: [PATCH 4/4] bpo-39744: news file update --- .../next/Library/2020-02-25-00-43-22.bpo-39744.hgK689.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2020-02-25-00-43-22.bpo-39744.hgK689.rst b/Misc/NEWS.d/next/Library/2020-02-25-00-43-22.bpo-39744.hgK689.rst index 6c54bc504fafc8..6e690f996569a4 100644 --- a/Misc/NEWS.d/next/Library/2020-02-25-00-43-22.bpo-39744.hgK689.rst +++ b/Misc/NEWS.d/next/Library/2020-02-25-00-43-22.bpo-39744.hgK689.rst @@ -1 +1 @@ -Make :func:`asyncio.subprocess.Process.communicate` close the subprocess's stdin even when called with `input=None`. +Make :func:`asyncio.subprocess.Process.communicate` close the subprocess's stdin even when called with ``input=None``.