title: How to create asyncio stream reader/writer for stdin/stdout?
body: <p>I need to write two programs which will be run as a parent process and its child. The parent process spawns the child and then they communicate via pair of pipes connected to child's stdin and stdout. The communication is peer-to-peer, that's why I need asyncio. A simple read/reply loop won't do.</p>
  
  <p>I have written the parent. No problem because <code>asyncio</code> provides everything I needed in <code>create_subprocess_exec()</code>. </p>
  
  <p>However I don't know how to create a similar stream reader/writer in the child. I did not expect any problems. because the pipes are already created and file descriptors 0 and 1 are ready to use when the child process starts. No connection is to be open, no process needs to be spawned.</p>
  
  <p>This is my not working attempt:</p>
  
  <pre><code>import asyncio
  import sys
  
  _DEFAULT_LIMIT = 64 * 1024
  
  async def connect_stdin_stdout(limit=_DEFAULT_LIMIT, loop=None):
      if loop is None:
          loop = asyncio.get_event_loop()
      reader = asyncio.StreamReader(limit=limit, loop=loop)
      protocol = asyncio.StreamReaderProtocol(reader, loop=loop)
      r_transport, _ = await loop.connect_read_pipe(lambda: protocol, sys.stdin)
      w_transport, _ = await loop.connect_write_pipe(lambda: protocol, sys.stdout)
      writer = asyncio.StreamWriter(w_transport, protocol, reader, loop)
      return reader, writer
  </code></pre>
  
  <p>The problem is I have two transports where I should have one. The function fails, because it tries to set the protocol's transport twice:</p>
  
  <pre><code>await loop.connect_read_pipe(lambda: protocol, sys.stdin)
  await loop.connect_write_pipe(lambda: protocol, sys.stdout)
  # !!!! assert self._transport is None, 'Transport already set'
  </code></pre>
  
  <p>I tried to pass a dummy protocol to the first line, but this line is not correct either, because both transports are needed, not just one:</p>
  
  <pre><code>writer = asyncio.StreamWriter(w_transport, protocol, reader, loop)
  </code></pre>
  
  <p>I guess I need to combine two unidirectional transports to one bidirectional somehow. Or is my approach entirely wrong? Could you please give me some advice?</p>
  
  <hr>
  
  <p><strong>UPDATE</strong>: after some test this seems to work (but does not look good to me):</p>
  
  <pre><code>async def connect_stdin_stdout(limit=_DEFAULT_LIMIT, loop=None):
      if loop is None:
          loop = asyncio.get_event_loop()
      reader = asyncio.StreamReader(limit=limit, loop=loop)
      protocol = asyncio.StreamReaderProtocol(reader, loop=loop)
      dummy = asyncio.Protocol()
      await loop.connect_read_pipe(lambda: protocol, sys.stdin) # sets read_transport
      w_transport, _ = await loop.connect_write_pipe(lambda: dummy, sys.stdout)
      writer = asyncio.StreamWriter(w_transport, protocol, reader, loop)
  return reader, writer
  </code></pre>