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
<[email protected]> 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.
>