Matthias Urlichs
Matthias Urlichs

Reputation: 2544

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?

Upvotes: 3

Views: 880

Answers (1)

mic_e
mic_e

Reputation: 5840

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.

Upvotes: 2

Related Questions