liveBook · Manning

StreamReader.read

As explained in Python Concurrency with asyncio

StreamReader.read is a coroutine method that waits for and returns a specified amount of data from a stream.

StreamReader.read is an awaitable method that waits for a specified number of bytes to arrive, then returns them. Unlike readline, it does not wait for a line ending. section 8.3

Use the method according to the shape of the input:

  • Call read(1) when an application must process input one character at a time. section 8.4.1
  • Use readline when input is naturally line-oriented and waiting for a complete line is appropriate. section 8.3
  • Remember that the result is bytes, so decode it before treating it as text. section 8.4.1

Reading an interactive line

A cbreak-mode terminal can repeatedly await stdin_reader.read(1), append each byte to a buffer, echo it, and stop when the returned byte is b'\n'. This enables application-controlled editing and output placement. section 8.4.1

Listing 8.8 Reading input one character at a time
import sys
from asyncio import StreamReader
from collections import deque
from chapter_08.listing_8_7 import move_back_one_char, clear_line
 
 
async def read_line(stdin_reader: StreamReader) -> str:
    def erase_last_char():                                     #1
        move_back_one_char()
        sys.stdout.write(' ')
        move_back_one_char()
 
    delete_char = b'\x7f'
    input_buffer = deque()
    while (input_char := await stdin_reader.read(1)) != b'\n':
        if input_char == delete_char:                          #2
            if len(input_buffer) > 0:
                input_buffer.pop()
                erase_last_char()
                sys.stdout.flush()
        else:
            input_buffer.append(input_char)                    #3
            sys.stdout.write(input_char.decode())
            sys.stdout.flush()
    clear_line()
    return b''.join(input_buffer).decode()

Inspect the complete read_line coroutine, including read(1), delete-key handling, buffering, decoding, and terminal echo. section 8.4.1

How Python Concurrency with asyncio covers it

How deep it goes
Explains coroutine waiting, byte counts, and character-by-character use, but defers lower-level transport and protocol internals.
Examples
Uses a cbreak terminal, a one-character input loop, a byte buffer, and an HTTP response reader.
What you can do after
Apply via asyncio StreamReader to consume exact byte counts, decode input, and build incremental input handlers.
How it connects
Connects StreamReader.read with readline, StreamReader, StreamWriter, streams, and transports and protocols.

This explainer was generated by Manning's knowledge graph from the text of Python Concurrency with asyncio. The section links point to the parts of the book it draws on.