non-blocking stdin using selectors

Viewed 505

Playing around with non-blocking console input, using Python's selectors in combination with sys.stdin, there is something I do not understand:

Suppose I want to exit a loop when a user presses Enter, possibly after entering some other characters first.

If I do a blocking read, as follows, the process always finishes after the first linefeed \n it encounters, as expected, regardless of any preceding characters:

import sys

character = ''
while character != '\n':
    character = sys.stdin.read(1)

Now consider the following minimized example of a non-blocking read:

import sys
import selectors

selector = selectors.DefaultSelector()
selector.register(fileobj=sys.stdin, events=selectors.EVENT_READ)

character = ''
while character != '\n':
    for key, __ in selector.select(timeout=0):
        character = key.fileobj.read(1)

If I hit Enter as the first input, that generates a linefeed character, and the process finishes, as expected.

However, if I input some other characters first, followed by Enter, the process does not finish: I need to hit Enter again before it does.

Apparently this implementation only works if the linefeed is the first input.

There's probably a good reason for this, but I do not see it at the moment, and could not find any related questions.

Does this have to do with my non-blocking implementation, or is it a stdin buffer thing, or perhaps something to do with the console or terminal implementation?

(I am running this from a python 3.8 shell on ubuntu.)

0 Answers
Related