By turning blocking off you can only read a character at a time. So, there is no way to get readline() to work in a non-blocking context. I assume you just want to read key presses to control the robot.

I have had no luck using select.select() on Linux and created a way with tweaking termios settings. So, this is Linux specific but works for me:

import atexit, termios
import sys, os
import time


old_settings=None

def init_any_key():
   global old_settings
   old_settings = termios.tcgetattr(sys.stdin)
   new_settings = termios.tcgetattr(sys.stdin)
   new_settings[3] = new_settings[3] & ~(termios.ECHO | termios.ICANON) # lflags
   new_settings[6][termios.VMIN] = 0  # cc
   new_settings[6][termios.VTIME] = 0 # cc
   termios.tcsetattr(sys.stdin, termios.TCSADRAIN, new_settings)


@atexit.register
def term_any_key():
   global old_settings
   if old_settings:
      termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_settings)


def any_key():
   ch_set = []
   ch = os.read(sys.stdin.fileno(), 1)
   while ch is not None and len(ch) > 0:
      ch_set.append( ord(ch[0]) )
      ch = os.read(sys.stdin.fileno(), 1)
   return ch_set


init_any_key()
while True:
   key = any_key()
   if key is not None:
      print(key)
   else:
      time.sleep(0.1)

A better Windows or cross-platform answer is here: Non-blocking console input?

Answer from swdev on Stack Overflow
Top answer
1 of 8
17

By turning blocking off you can only read a character at a time. So, there is no way to get readline() to work in a non-blocking context. I assume you just want to read key presses to control the robot.

I have had no luck using select.select() on Linux and created a way with tweaking termios settings. So, this is Linux specific but works for me:

import atexit, termios
import sys, os
import time


old_settings=None

def init_any_key():
   global old_settings
   old_settings = termios.tcgetattr(sys.stdin)
   new_settings = termios.tcgetattr(sys.stdin)
   new_settings[3] = new_settings[3] & ~(termios.ECHO | termios.ICANON) # lflags
   new_settings[6][termios.VMIN] = 0  # cc
   new_settings[6][termios.VTIME] = 0 # cc
   termios.tcsetattr(sys.stdin, termios.TCSADRAIN, new_settings)


@atexit.register
def term_any_key():
   global old_settings
   if old_settings:
      termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_settings)


def any_key():
   ch_set = []
   ch = os.read(sys.stdin.fileno(), 1)
   while ch is not None and len(ch) > 0:
      ch_set.append( ord(ch[0]) )
      ch = os.read(sys.stdin.fileno(), 1)
   return ch_set


init_any_key()
while True:
   key = any_key()
   if key is not None:
      print(key)
   else:
      time.sleep(0.1)

A better Windows or cross-platform answer is here: Non-blocking console input?

2 of 8
13

You can use selectors for handle I/O multiplexing:

https://docs.python.org/3/library/selectors.html

Try this out:

#! /usr/bin/python3

import sys
import fcntl
import os
import selectors

# set sys.stdin non-blocking
orig_fl = fcntl.fcntl(sys.stdin, fcntl.F_GETFL)
fcntl.fcntl(sys.stdin, fcntl.F_SETFL, orig_fl | os.O_NONBLOCK)

# function to be called when enter is pressed
def got_keyboard_data(stdin):
    print('Keyboard input: {}'.format(stdin.read()))

# register event
m_selector = selectors.DefaultSelector()
m_selector.register(sys.stdin, selectors.EVENT_READ, got_keyboard_data)

while True:
    sys.stdout.write('Type something and hit enter: ')
    sys.stdout.flush()
    for k, mask in m_selector.select():
        callback = k.data
        callback(k.fileobj)

The above code will hold on the line

for k, mask in m_selector.select():

until a registered event occurs, returning a selector_key instance (k) and a mask of monitored events.

In the above example we registered only one event (Enter key press):

m_selector.register(sys.stdin, selectors.EVENT_READ, got_keyboard_data)

The selector key instance is defined as follows:

abstractmethod register(fileobj, events, data=None)

Therefore, the register method sets k.data as our callback function got_keyboard_data, and calls it when the Enter key is pressed:

callback = k.data
callback(k.fileobj)

A more complete example (and hopefully more useful) would be to multiplex stdin data from user with incoming connections from network:

import selectors
import socket
import sys
import os
import fcntl

m_selector = selectors.DefaultSelector()

# set sys.stdin non-blocking
def set_input_nonblocking():
    orig_fl = fcntl.fcntl(sys.stdin, fcntl.F_GETFL)
    fcntl.fcntl(sys.stdin, fcntl.F_SETFL, orig_fl | os.O_NONBLOCK)

def create_socket(port, max_conn):
    server_addr = ('localhost', port)
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    server.setblocking(False)
    server.bind(server_addr)
    server.listen(max_conn)
    return server

def read(conn, mask):
    global GO_ON
    client_address = conn.getpeername()
    data = conn.recv(1024)
    print('Got {} from {}'.format(data, client_address))
    if not data:
         GO_ON = False

def accept(sock, mask):
    new_conn, addr = sock.accept()
    new_conn.setblocking(False)
    print('Accepting connection from {}'.format(addr))
    m_selector.register(new_conn, selectors.EVENT_READ, read)

def quit():
    global GO_ON
    print('Exiting...')
    GO_ON = False


def from_keyboard(arg1, arg2):
    line = arg1.read()
    if line == 'quit\n':
        quit()
    else:
        print('User input: {}'.format(line))

GO_ON = True
set_input_nonblocking()

# listen to port 10000, at most 10 connections
server = create_socket(10000, 10)

m_selector.register(server, selectors.EVENT_READ, accept)
m_selector.register(sys.stdin, selectors.EVENT_READ, from_keyboard)

while GO_ON:
    sys.stdout.write('>>> ')
    sys.stdout.flush()
    for k, mask in m_selector.select():
        callback = k.data
        callback(k.fileobj, mask)


# unregister events
m_selector.unregister(sys.stdin)

# close connection
server.shutdown()
server.close()

#  close select
m_selector.close()

You can test using two terminals. first terminal:

$ python3 test.py 
>>> bla

open another terminal and run:

 $ nc localhost 10000
 hey!

back to the first

>>> qwerqwer     

Result (seen on the main terminal):

$ python3 test.py 
>>> bla
User input: bla

>>> Accepting connection from ('127.0.0.1', 39598)
>>> Got b'hey!\n' from ('127.0.0.1', 39598)
>>> qwerqwer     
User input: qwerqwer

>>> 
🌐
Python.org
discuss.python.org › core development
Handling `sys.stdin.read()` in Non-Blocking Mode - Core
July 31, 2024 - Hello Python Community, I’m seeking your input on an issue related to the behavior of sys.stdin.read() when stdin is set to non-blocking mode and no input is available. This discussion is based on issue #109523 in the Python GitHub repository. During the sprint at EuroPython 2024, I created ...
Discussions

[Python] How can I use select with sys.stdin to get non-blocking input?
That's funny. Can you trim it down to a test that selects on just stdin and reads from it? I tried that, and it works for me, so we don't seem to be doing the same thing. Also, I suppose you didn't set stdin to be non-blocking or anything? More on reddit.com
🌐 r/learnprogramming
2
2
January 28, 2014
io - Blocking read from stdin in python - Stack Overflow
How to perform a blocking read operation from stdin in python (2.7) that pauses process until some data appears in the pipe? The problem with read() lies in the fact that after the first time it r... More on stackoverflow.com
🌐 stackoverflow.com
python - Non-blocking read from sys.stdin - Stack Overflow
I am trying to read from sys.stdin while also reading from other network sockets with the following code: import sys import select input = [sys.stdin] inputready, outputready, exceptionready = se... More on stackoverflow.com
🌐 stackoverflow.com
non-blocking terminal input Python
You can use low-level, non cross-platform OS functions e.g. from msvcrt on MS Windows You can use curses library Or use a library with event handler that supports keyboard events e.g. pynput, pygame, tkinter, pyqt5... Summary here: https://stackoverflow.com/questions/292095/polling-the-keyboard-detect-a-keypress-in-python More on reddit.com
🌐 r/learnpython
4
1
March 2, 2020
🌐
Ballingt
ballingt.com › nonblocking-stdin-in-python-3
Nonblocking stdin read works differently in Python 3 - ballingt
I went back to my example above, where the read method kept returning an empty string when it should be erroring on having no bytes to read, and it occurred to me that this must be the new interface: nonblocking files return an empty string on .read(1) if there’s nothing to read! While this feels inconsistent with nonblocking socket behavior, it’s convenient here; there’s no more IOError to catch. I haven’t seen docs that specify this behavior yet, but things seem to be working alright on my platform. with raw(sys.stdin): with nonblocking(sys.stdin): while True: c = sys.stdin.read(1) if c: print(repr(c)) else: print('not ready') time.sleep(.1)
🌐
repolinux
repolinux.wordpress.com › 2012 › 10 › 09 › non-blocking-read-from-stdin-in-python
Non-blocking read from stdin in python | repolinux
May 30, 2022 - Below are two solutions: the first using select(), which is only available on unix, and the second using only threading and queues, which also works on windows. The simpler solution is using select on sys.stdin, reading input when available ...
🌐
Pelicandd
blog.pelicandd.com › article › 191
Non-blocking reading from stdin in Python
A com­mon way all over Stack­Over­flow and the In­ter­net to read from stdin in a non-block­ing way con­sists of us­ing select.select. Let's cre­ate a script, one.py, which uses it: #!/usr/bin/python3 import multiprocessing import select exit_event = multiprocessing.Event() with open(0) as f: while not exit_event.is_set(): rlist, _, _ = select.select([f], [], [], 0.1) if rlist: line = f.readline().strip() if line: print(f"Received {line}.") Un­for­tu­nate­ly, while it looks like it works per­fect­ly well, some­times it doesn't.
🌐
Medium
medium.com › @denismakogon › python-3-fight-for-nonblocking-pipe-68f92429d18e
Python 3: fight for nonblocking pipe | by Denis Makogon | Medium
September 25, 2017 - Comparing Python’s socket to STDIN i found to common things between them: i can do reading/writing. First of all i tried to implement echoing socket server and here’s what i had eventually: import asyncio async def handle_echo(reader, writer): data = await reader.read(100) message = data.decode() writer.write(data) await writer.drain() writer.close() loop = asyncio.get_event_loop() coro = asyncio.start_server( handle_echo, '127.0.0.1', 9000, loop=loop ) server = loop.run_until_complete(coro) try: loop.run_forever() except KeyboardInterrupt: pass finally: server.close() loop.run_until_complete(server.wait_closed()) loop.close()
🌐
GitHub
github.com › orgs › micropython › discussions › 11448
Non blocking read of input from the terminal · micropython · Discussion #11448
May 9, 2023 - Much more complicated version of the example above, that should buffer incomplete utf-8 reads instead of blocking on those, and avoid reads after poll hup/err events: import sys, select, time # NOTE: This code does not work under Thonny because # in Thonny input is sent to program only after [Enter] is clicked. # NOTE: Do not run this via "mpremote run ..." either, as it does not connect stdin class TermReader: def __init__(self, byte_stream, buffer_bytes=100): self.stream, self.poller = byte_stream, select.poll() self.rb, self.rb_n, self.rb_len = bytearray(buffer_bytes), 0, buffer_bytes self.
🌐
Raspberry Pi Forums
forums.raspberrypi.com › board index › programming › python
Non-blocking capture of input from stdin on headless unit - Raspberry Pi Forums
September 12, 2024 - import system, select def barcode(block=True): if block or select.select([sys.stdin], [], [], 0) == ([sys.stdin], [], []): bc = sys.stdin.readline() return bc return None while True: bar = barcode() if bar: with open('/home/pi/result', 'a') as f: f.write(f'barcode = {bar}\n') else: with open('/home/pi/result', 'a') as f: f.write('No code read\n') Just gives me rows and rows of 'No code read' ... If I use my barcode simulator (a pico running circuitpython) that acts as a HID keyboard device, and have a python script reading the "keyboard" it works OK for me on a Pi4 running Bullseye 32-bit, no monitor attached.
Find elsewhere
🌐
PyPI
pypi.org › project › python-nonblock
python-nonblock · PyPI
Methods like readline will block until a newline is printed, etc. You can provide a limit (or default None is anything available) and up to that many bytes, if available, will be returned. When the stream is closed on the other side, and you have already read all the data (i.e. you’ve already been returned all data and it’s impossible that more will ever be there in the future), “None” is returned.
      » pip install python-nonblock
    
Published   Jul 23, 2019
Version   4.0.1
🌐
Python
mail.python.org › pipermail › python-list › 2001-September › 108492.html
read stdin NON-BLOCKING
September 19, 2013 - "Olivier Deme" <olivier.deme at airtel-atn.com> writes: > How can I read the standard input in a non-blocking way? > I have tried the following, but it is still blocking: > > fcntl.fcntl(sys.stdin.fileno(), FCNTL.F_SETFD, FCNTL.O_NONBLOCK) > os.read(sys.stdin.fileno(), bufsize) When you say 'blocking', do you mean 'line-buffered'?
🌐
GitHub
gist.github.com › ali1234 › 7a6899ecc77a67a643de65a919457020
Unbuffered, non-blocking stdin in Python · GitHub
def __exit__(self, *args): # restore terminal to previous state termios.tcsetattr(sys.stdin, termios.TCSADRAIN, self.old) # set for blocking io orig_fl = fcntl.fcntl(sys.stdin, fcntl.F_GETFL) fcntl.fcntl(sys.stdin, fcntl.F_SETFL, orig_fl | ~ os.O_NONBLOCK)
🌐
Python.org
discuss.python.org › core development
Handling `sys.stdin.read()` in Non-Blocking Mode
August 9, 2024 - Overall I agree. Including the use of BlockingIOError for this. That actually makes sense as opposed to the “this case was never considered” smell of the existing TypeError. Next steps: We need a PR implementing this. The existing Draft PR can be changed to raise rather than return None, or a new draft PR can be opened and the old one closed.
🌐
Reddit
reddit.com › r/learnprogramming › [python] how can i use select with sys.stdin to get non-blocking input?
r/learnprogramming on Reddit: [Python] How can I use select with sys.stdin to get non-blocking input?
January 28, 2014 -

I'm writing a basic chat client for a networking class in Python and I'm trying to use standard input and a socket in the same select loop to process broadcasts and responses from the server as well as input from the user. When I read from sys.stdin, the input doesn't get flushed and the loop keeps sending the same message. Here's my code:

while True:
    readables, writeables, exceptions = select([sockobj, sys.stdin], [], [])
    for sock in readables:
        if sock == sockobj:
      
            data = sockobj.recv(240)
            print ("Server responded with", data.decode())
        
        elif sock == sys.stdin:
            message = sys.stdin.readline() 
            sockobj.send(message.encode())

sockobj is the socket connected to the server.

Edit:

Figured it out. I had a line of code in there that I didn't copy to Reddit. It was sending "message" to the server whenever it got a response and each message sent generated another response.

🌐
Tomecek
blog.tomecek.net › post › non-blocking-stdin-in-python
Non-blocking stdin with python using epoll · Blog | Tomáš Tomeček
October 20, 2016 - import os import sys import fcntl import select fd = sys.stdin.fileno() fl = fcntl.fcntl(fd, fcntl.F_GETFL) fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK) epoll = select.epoll() epoll.register(fd, select.EPOLLIN) try: while True: events = epoll.poll(1) for fileno, event in events: data = "" while True: l = sys.stdin.read(64) if not l: break data += l print(data.upper(), end="") finally: epoll.unregister(fd) epoll.close() ... $ python3 cat.py asdqwe ASDQWE zxcasd ZXCASD ^CTraceback (most recent call last): File "cat.py", line 15, in <module> events = epoll.poll(1) KeyboardInterrupt
🌐
Shallow Thoughts
shallowsky.com › blog › programming › python-read-characters.html
Reading keypresses in Python (Shallow Thoughts)
Blocking is whether the read() waits for input or returns immediately. If I read a character with c = sys.stdin.read(1) but there's been no character typed yet, a non-blocking read will throw an IOError exception, while a blocking read will wait, not returning until the user types a character.
🌐
Python
bugs.python.org › issue36293
Issue 36293: Nonblocking read sys.stdin raises error - Python tracker
March 14, 2019 - This issue tracker has been migrated to GitHub, and is currently read-only. For more information, see the GitHub FAQs in the Python's Developer Guide · This issue has been migrated to GitHub: https://github.com/python/cpython/issues/80474
🌐
Narkive
comp.lang.python.narkive.com › uuZS6VxZ › help-non-blocking-reads-from-sys-stdin-in-windows
HELP Non-Blocking reads from sys.stdin in Windows.
------------------------------- from Queue import Queue, Empty from sys import stdin from threading import Thread # Reading from empty stdin error class EmptyError(Exception): pass # Input queue _queue = Queue() def produce(): '''Read one char at a time from stdin and place in _queue''' try: while 1: c = stdin.read(1) # Read one char if not c: # EOF _queue.put(EOFError, 1) break _queue.put(c, 1) except EOFError, e: _queue.put(EOFError) # Start the thread t = Thread(target=produce) t.setDaemon(1) # Don't inhibit interperter exit t.start() # Start thread def get(): '''Get one item from queue.
🌐
Stack Overflow
stackoverflow.com › questions › 31341432 › non-blocking-read-from-sys-stdin
python - Non-blocking read from sys.stdin - Stack Overflow
import sys import select input = [sys.stdin] inputready, outputready, exceptionready = select.select(input, [],[]) for s in inputready: if inputready == sys.stdin: data = sys.stdin.readline() print(data)