This short Python script shows how to use asyncio to read a single line from standard input (stdin) asynchronously and report what was read to standard error (stderr). It’s a compact example of wiring low-level OS pipes into asyncio’s high-level stream APIs.
-
Creates an asynchronous reader from a file-like object
make_reader(fp)takes a binary file object (likesys.stdin.buffer) and:- Gets the current event loop.
- Builds an
asyncio.StreamReaderand itsStreamReaderProtocol. - Connects the OS read pipe (
fp) to that protocol withloop.connect_read_pipe. - Returns the
StreamReaderso you canawait reader.readline()and similar.
-
Creates an asynchronous writer from a file-like object
make_writer(fp):- Gets the current event loop.
- Uses
loop.connect_write_pipeto attach the OS write pipe (fp) to an asyncio transport usingFlowControlMixin. - Wraps the transport in an
asyncio.StreamWriterso you can callwriter.write(...)andawait writer.drain().
-
Main flow In
main():- It builds
stdinviamake_reader(sys.stdin.buffer). - It builds
stderrviamake_writer(sys.stderr.buffer). (Thestdoutsetup is shown but commented out.) - It awaits one line from stdin:
line = await stdin.readline(). - It writes a debug message like
line=b'hello\n'to stderr, then drains to ensure the bytes are flushed.
- It builds
-
Runs the coroutine
asyncio.run(main())starts the event loop, executesmain(), and closes the loop cleanly.
- Non-blocking I/O: In CLI tools that must remain responsive—maybe they also handle sockets, timers, or subprocesses—you don’t want a blocking
.readline()call. Using asyncio lets your program do other work while waiting for input. - Interfacing with UNIX pipes: The
connect_read_pipe/connect_write_pipefunctions bridge low-level file descriptors (like stdin/stdout/stderr or any pipe) to asyncio streams.
- Binary mode: The code uses
.buffer, so you read and write bytes, not strings. If you need text, decode/encode or wrap withasyncio.StreamReader.readline()followed by.decode(). - Single read: As written, it reads exactly one line and exits. To process multiple lines, loop over
await stdin.readline()until you getb''(EOF). - Flow control: Using
await writer.drain()yields to the event loop if the pipe’s buffer is full, preventing unbounded memory growth.
That would read a line from stdin, print a debug representation to stderr, and echo the raw line to stdout—entirely using asyncio.