bpo-36801: Fix waiting in StreamWriter.drain for closing SSL transport by asvetlov · Pull Request #13098 · python/cpython (original) (raw)

Hi @asvetlov , I ran into a BrokenPipeError error when testing the following code:

#!/usr/bin/env python

import sys
import os
import asyncio


async def main_task():

    print(sys.version)


    xxx = "x" * 196428
    incoming_original_data = xxx.encode()

    print(f"stdin len: {len(incoming_original_data)}")

    proc = await asyncio.create_subprocess_shell(
        f"sleep 2 && xxd -l 1",
        stdin=asyncio.subprocess.PIPE,
        stdout=asyncio.subprocess.PIPE,
        stderr=asyncio.subprocess.PIPE)
    
    await proc.communicate(input = incoming_original_data)

    print("subprocess ended")

def main():

    opts = asyncio.run(main_task())

    print(f"main END")

    return opts


if __name__ == '__main__':

    main()
    

Note the subprocess ends very soon, and it seems _stdin_closed isn't properly handled because I see the following output:

3.11.3 (main, Apr  7 2023, 19:25:52) [Clang 14.0.0 (clang-1400.0.29.202)]
stdin len: 196428
subprocess ended
main END
Future exception was never retrieved
future: <Future finished exception=BrokenPipeError(32, 'Broken pipe')>
Traceback (most recent call last):
  File "/usr/local/Cellar/python@3.11/3.11.3/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/subprocess.py", line 152, in _feed_stdin
    await self.stdin.drain()
  File "/usr/local/Cellar/python@3.11/3.11.3/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/streams.py", line 378, in drain
    await self._protocol._drain_helper()
  File "/usr/local/Cellar/python@3.11/3.11.3/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/streams.py", line 173, in _drain_helper
    await waiter
  File "/usr/local/Cellar/python@3.11/3.11.3/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/unix_events.py", line 709, in _write_ready
    n = os.write(self._fileno, self._buffer)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
BrokenPipeError: [Errno 32] Broken pipe