Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: readline/input() interacting with output from different threads

I'm writing a multithreaded program with an interactive console:

def console()
    import readline
    while True:
        data = input()
        do_whatever(data.split())

However, a library I'm using runs my callbacks from a different thread. The callback needs to print to the console. Thus I want to clear the command line, re-display the prompt, and re-show the command line.

How do I do that, short of re-implementing readline?

like image 997
Matthias Urlichs Avatar asked Aug 01 '26 18:08

Matthias Urlichs


1 Answers

Starting from this answer that solves the issue for C, I arrived at the following Python code, which works well enough for my purposes:

import os
import readline
import signal
import sys
import time
import threading


print_lock = threading.Lock()

def print_safely(text):
    with print_lock:
        sys.stdout.write(f'\r\x1b[K{text}\n')
        os.kill(os.getpid(), signal.SIGWINCH)

def background_thread():
    while True:
        time.sleep(0.5)
        print_safely('x')

threading.Thread(target=background_thread, daemon=True).start()

while True:
    try:
        inp = input(f'> ')
        with print_lock:
            print(repr(inp))
    except (KeyboardInterrupt, EOFError):
        print('')
        break

print_safely

  • uses \r\x1b[K (CR + CSI code EL) to remove the existing Readline prompt
  • prints its payload line
  • sends SIGWINCH to the thread that runs readline (in my case, readline runs in the main thread so os.getpid() gives the right target PID); this causes readline to re-draw its full prompt.

Possible remaining issues:

  • As mentioned in the other answer, if the readline prompt is longer than one line, the line-clearing will most likely fail.
  • You need to acquire the print_lock whenever printing in the main thread (this is true independent of the readline issue)
  • There might be some racy behaviours when the user presses a key at the exact same moment when the background thread prints.
like image 67
mic_e Avatar answered Aug 04 '26 07:08

mic_e



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!