Short answer
No and maybe yes.
Long answer
You can't just wrap a file-like object as a socket, or vice-versa, and expect it to work. asyncio
is using system calls under the hood to do its async magic and stdin
is stdin
from the system's point of view no mater how much you wrap it. When using the default SelectorEventLoop
it uses one of the select-like system calls. On Windows it uses the select
system call, which does not support anything but sockets.
So, select
sucks on windows. Is there another option? Yes. On Windows, and only Windows, there is another API for doing async operations called IOCP (I/O Completion Ports)
. It's a "notify-on-completion"
type multiplexer as opposed to the select
based "notify-when-ready"
type multiplexers. The API is much more complicated than doing a simple select
call on a file, but fortunately asyncio
has some support for it already.
The ProactorEventLoop
uses IOCP on Windows and it should theoretically supports reading from stdin
. I don't have access to a Windows machine so I can't test this, but give this a go:
# vim: filetype=python3 tabstop=2 expandtab
import asyncio as aio
import os
import sys
if os.name == "nt":
proactor_loop = aio.ProactorEventLoop()
aio.set_event_loop(proactor_loop)
@aio.coroutine
def main(loop):
stdin_reader = aio.StreamReader()
stdin_transport, stdin_protocol = yield from loop.connect_read_pipe(
lambda: aio.StreamReaderProtocol(stdin_reader),
sys.stdin
)
line = yield from stdin_reader.read()
print(line.strip().decode("utf-8"))
stdin_transport.close()
loop = aio.get_event_loop()
loop.run_until_complete(main(loop))
loop.close()
And run the equivalent of this on Windows:
$ echo blha blha blha | python test.py
blha blha blha
If this works, then at least you can do async stdin
on Windows. And then you could try something similar for stdout/stderr
or perhaps even serial ports.
If all else fails, you could always simulate async behaviour by wrapping blocking calls in threads using the loop.run_in_executor
coroutine:
yield from loop.run_in_executor(None, sys.stdin.readline)