I'm trying to read stdin asynchronously on Windows 7 64-bit and Python 3.4.3
I tried this inspired by an SO answer:
import asyncio
import sys
def reader():
print('Received:', sys.stdin.readline())
loop = asyncio.get_event_loop()
task = loop.add_reader(sys.stdin.fileno(), reader)
loop.run_forever()
loop.close()
However, it raises an OSError: [WInError 100381] An operation was attempted on something that is not a socket.
Could a file-like object like stdin be wrapped in a class to give it the API of a socket? I have asked this question separately, but if the solution is simple please answer here.
Assuming that I cannot wrap a file-like object to make it a socket, I tried using streams as inspired by this gist:
import asyncio
import sys
@asyncio.coroutine
def stdio(loop):
reader = asyncio.StreamReader(loop=loop)
reader_protocol = asyncio.StreamReaderProtocol(reader)
yield from loop.connect_read_pipe(lambda: reader_protocol, sys.stdin)
@asyncio.coroutine
def async_input(loop):
reader = yield from stdio(loop)
line = yield from reader.readline()
return line.decode().replace('\r', '').replace('\n', '')
@asyncio.coroutine
def main(loop):
name = yield from async_input(loop)
print('Hello ', name)
loop = asyncio.get_event_loop()
loop.run_until_complete(main(loop))
loop.close()
And that raises a NotImplementedError in asyncio.base_events._make_read_pipe_transport
Please advise how to read stdin using asyncio on Windows...
The NotImplementedError exception is raised because the connect pipes coroutines are not supported by the SelectorEventLoop, which is the default event loop set on asyncio. You need to use a ProactorEventLoop to support pipes on Windows. However, it would still not work because apparently the connect_read_pipe and connect_write_pipe functions doesn't support stdin/stdout/stderr or files in Windows as Python 3.5.1.
One way to read from stdin with an asynchronous behavior is using a thread with the loop's run_in_executor method. Here is a simple example for reference:
import asyncio
import sys
async def aio_readline(loop):
while True:
line = await loop.run_in_executor(None, sys.stdin.readline)
print('Got line:', line, end='')
loop = asyncio.get_event_loop()
loop.run_until_complete(aio_readline(loop))
loop.close()
In the example the function sys.stdin.readline() is called within another thread by the loop.run_in_executor method. The thread remains blocked until stdin receives a linefeed, in the mean time the loop is free to execute others coroutines if they existed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With