# [DEF:superset_tool.utils.whiptail_fallback:Module] # # @SEMANTICS: ui, fallback, console, utility, interactive # @PURPOSE: Предоставляет плотный консольный UI-fallback для интерактивных диалогов, имитируя `whiptail` для систем, где он недоступен. # @LAYER: UI # @PUBLIC_API: menu, checklist, yesno, msgbox, inputbox, gauge # [SECTION: IMPORTS] import sys from typing import List, Tuple, Optional, Any # [/SECTION] # [DEF:menu:Function] # @PURPOSE: Отображает меню выбора и возвращает выбранный элемент. # @PARAM: title (str) - Заголовок меню. # @PARAM: prompt (str) - Приглашение к вводу. # @PARAM: choices (List[str]) - Список вариантов для выбора. # @RETURN: Tuple[int, Optional[str]] - Кортеж (код возврата, выбранный элемент). rc=0 - успех. def menu(title: str, prompt: str, choices: List[str], **kwargs) -> Tuple[int, Optional[str]]: print(f"\n=== {title} ===\n{prompt}") for idx, item in enumerate(choices, 1): print(f"{idx}) {item}") try: raw = input("\nВведите номер (0 – отмена): ").strip() sel = int(raw) return (0, choices[sel - 1]) if 0 < sel <= len(choices) else (1, None) except (ValueError, IndexError): return 1, None # [/DEF:menu] # [DEF:checklist:Function] # @PURPOSE: Отображает список с возможностью множественного выбора. # @PARAM: title (str) - Заголовок. # @PARAM: prompt (str) - Приглашение к вводу. # @PARAM: options (List[Tuple[str, str]]) - Список кортежей (значение, метка). # @RETURN: Tuple[int, List[str]] - Кортеж (код возврата, список выбранных значений). def checklist(title: str, prompt: str, options: List[Tuple[str, str]], **kwargs) -> Tuple[int, List[str]]: print(f"\n=== {title} ===\n{prompt}") for idx, (val, label) in enumerate(options, 1): print(f"{idx}) [{val}] {label}") raw = input("\nВведите номера через запятую (пустой ввод → отказ): ").strip() if not raw: return 1, [] try: indices = {int(x.strip()) for x in raw.split(",") if x.strip()} selected_values = [options[i - 1][0] for i in indices if 0 < i <= len(options)] return 0, selected_values except (ValueError, IndexError): return 1, [] # [/DEF:checklist] # [DEF:yesno:Function] # @PURPOSE: Задает вопрос с ответом да/нет. # @PARAM: title (str) - Заголовок. # @PARAM: question (str) - Вопрос для пользователя. # @RETURN: bool - `True`, если пользователь ответил "да". def yesno(title: str, question: str, **kwargs) -> bool: ans = input(f"\n=== {title} ===\n{question} (y/n): ").strip().lower() return ans in ("y", "yes", "да", "д") # [/DEF:yesno] # [DEF:msgbox:Function] # @PURPOSE: Отображает информационное сообщение. # @PARAM: title (str) - Заголовок. # @PARAM: msg (str) - Текст сообщения. def msgbox(title: str, msg: str, **kwargs) -> None: print(f"\n=== {title} ===\n{msg}\n") # [/DEF:msgbox] # [DEF:inputbox:Function] # @PURPOSE: Запрашивает у пользователя текстовый ввод. # @PARAM: title (str) - Заголовок. # @PARAM: prompt (str) - Приглашение к вводу. # @RETURN: Tuple[int, Optional[str]] - Кортеж (код возврата, введенная строка). def inputbox(title: str, prompt: str, **kwargs) -> Tuple[int, Optional[str]]: print(f"\n=== {title} ===") val = input(f"{prompt}\n") return (0, val) if val else (1, None) # [/DEF:inputbox] # [DEF:_ConsoleGauge:Class] # @PURPOSE: Контекстный менеджер для имитации `whiptail gauge` в консоли. class _ConsoleGauge: def __init__(self, title: str, **kwargs): self.title = title def __enter__(self): print(f"\n=== {self.title} ===") return self def __exit__(self, exc_type, exc_val, exc_tb): sys.stdout.write("\n"); sys.stdout.flush() def set_text(self, txt: str) -> None: sys.stdout.write(f"\r{txt} "); sys.stdout.flush() def set_percent(self, percent: int) -> None: sys.stdout.write(f"{percent}%"); sys.stdout.flush() # [/DEF:_ConsoleGauge] # [DEF:gauge:Function] # @PURPOSE: Создает и возвращает экземпляр `_ConsoleGauge`. # @PARAM: title (str) - Заголовок для индикатора прогресса. # @RETURN: _ConsoleGauge - Экземпляр контекстного менеджера. def gauge(title: str, **kwargs) -> _ConsoleGauge: return _ConsoleGauge(title, **kwargs) # [/DEF:gauge] # [/DEF:superset_tool.utils.whiptail_fallback]