Hello Jonathan,

The snippet you've sent through has worked perfectly for me, thank
you. I found the os.fdopen(0, 'wb') call was important, as was the
order - connecting the read pipe before the write pipe resulted in
silence.

Thank you for the explanation on stdin/stdout in a pseudo terminal -
that helped make more sense of it all to me.

What follows is a rough example of asynchronous stdin/stdout,
implemented as an async version of input(). Hopefully this will be of
use to someone in the future.

As a bonus, the os.fdopen() call means that regular print() calls will
still work.

import os
import asyncio
import sys

from asyncio.streams import StreamWriter, FlowControlMixin

reader, writer = None, None

@asyncio.coroutine
def stdio(loop=None):
    if loop is None:
        loop = asyncio.get_event_loop()

    reader = asyncio.StreamReader()
    reader_protocol = asyncio.StreamReaderProtocol(reader)

    writer_transport, writer_protocol = yield from
loop.connect_write_pipe(FlowControlMixin, os.fdopen(0, 'wb'))
    writer = StreamWriter(writer_transport, writer_protocol, None, loop)

    yield from loop.connect_read_pipe(lambda: reader_protocol, sys.stdin)

    return reader, writer

@asyncio.coroutine
def async_input(message):
    if isinstance(message, str):
        message = message.encode('utf8')

    global reader, writer
    if (reader, writer) == (None, None):
        reader, writer = yield from stdio()

    writer.write(message)
    line = yield from reader.readline()
    return line.decode('utf8').strip()

@asyncio.coroutine
def main():
    name = yield from async_input("What's your name? ")

    print("Hello, {}!".format(name))

asyncio.get_event_loop().run_until_complete(main())

Thank you,

Nathan.


On Thu, Feb 13, 2014 at 12:02 AM, Jonathan Slenders
<jonathan.slend...@gmail.com> wrote:
> One thing that could be also confusing is that (as far as I understand)
> stdin and stdout are actually the same file if your process is attached to a
> pseudo terminal. In that case, stdin is opened as read, while stdout is
> opened as write. (Internally, often os.dup2 is used by the parent process to
> copy the file descriptor from '0' to '1' and '2' before running exec, making
> them identical. See pexpect for instance.) But if you open a subprocess,
> it's possible to use pipes, and I think in that case, they are really
> different file descriptors.
>
> Further.
> StreamReader and StreamWriter are often used in pairs. In Python2.7.3, you
> can do create a bidirectional pipe on stdin/out as follows:
>
>>>> import os
>>>> fd = os.fdopen(0, 'r+')
>>>>
>
> Now 'fd' supports both read and write operations.
> However, in Python 3.3, you can't create such an object:
>
>>>> import os
>>>> os.fdopen(0, 'r+')
>
>
> Traceback (most recent call last):
>   File "<stdin>", line 1, in <module>
>   File "/usr/lib/python3.3/os.py", line 1032, in fdopen
>     return io.open(fd, *args, **kwargs)
> io.UnsupportedOperation: File or stream is not seekable.
>>>>
>
>
> I think that could be a bug in Python 3, but I'm not sure.
>

Reply via email to