"""Functions for obtaining CLI input""" import termios import signal import sys import os from typing import Union from . import color def get_keypress() -> str: """Get a single keypress, the ugly POSIX way""" fileno = sys.stdin.fileno() old = termios.tcgetattr(fileno) new = termios.tcgetattr(fileno) new[3] = new[3] & ~termios.ICANON & ~termios.ECHO new[6][termios.VMIN] = 1 new[6][termios.VTIME] = 0 termios.tcsetattr(fileno, termios.TCSANOW, new) key = None try: key = str(os.read(fileno, 4), 'ascii') finally: termios.tcsetattr(fileno, termios.TCSAFLUSH, old) keylist = { '\t': 'TAB', '\n': 'ENTER', '\x7f': 'BACKSPACE', '\x1b': 'ESC', '\x1b[Z': 'BACKTAB', '\x1bOH': 'HOME', '\x1bOP': 'F1', '\x1bOQ': 'F2', '\x1bOR': 'F3', '\x1bOS': 'F4', '\x1b[15': 'F5', '\x1b[17': 'F6', '\x1b[18': 'F7', '\x1b[19': 'F8', '\x1b[20': 'F9', '\x1b[21': 'F10', '\x1b[23': 'F11', '\x1b[24': 'F12', '\x1b[A': 'ARROW_UP', '\x1b[B': 'ARROW_DN', '\x1b[C': 'ARROW_RT', '\x1b[D': 'ARROW_LT', } return key if key not in keylist else keylist[key] get_keypress.__module__ = 'rads' def _prompt_timeout(signum, _frame): raise TimeoutError("Prompt timed out") def prompt_y_n( question: str, *, timeout: Union[int, None] = 604800, sigint_exit: bool = True, ) -> bool: """Prompt for a yes or no answer Args: question: text to display before [y/n] prompt timeout: time in seconds after which to raise TimeoutError. Defaults to one week sigint_exit: Whether to sys.exit(1) on ctrl+c; Defaults True. Raises: SystemExit: if SIGINT is received KeyboardInterrupt: if sigint_exit=False and a sigint is received TimeoutError: if timeout= is set and no response in that time """ valid = {"yes": True, "y": True, "no": False, "n": False} while True: print(question, '[y/n]') try: if timeout: signal.signal(signal.SIGALRM, _prompt_timeout) signal.alarm(timeout) choice = input().lower() if timeout: signal.alarm(0) # disable the alarm except KeyboardInterrupt: if not sigint_exit: raise print("\nCancelled") sys.exit(1) if choice in valid: return valid[choice] print('Invalid answer. Try again:', color.bold('[y/n]')) prompt_y_n.__module__ = 'rads'