from datetime import datetime def print_header(title: str) -> None: print(f"\n--- {title} ---\n") def print_table(headers: list[str], rows: list[list[str]]) -> None: if not rows: print(" (empty)") return all_rows = [headers] + [[str(c) for c in row] for row in rows] widths = [max(len(r[i]) for r in all_rows) for i in range(len(headers))] fmt = " | ".join(f"{{:<{w}}}" for w in widths) print(fmt.format(*headers)) print("-+-".join("-" * w for w in widths)) for row in all_rows[1:]: print(fmt.format(*row)) def prompt_int( prompt: str, required: bool = True, min_val: int | None = None, max_val: int | None = None, ) -> int | None: while True: val = input(prompt).strip() if not val: if not required: return None print("This field is required.") continue try: n = int(val) except ValueError: print("Please enter a valid integer.") continue if min_val is not None and n < min_val: print(f"Must be at least {min_val}.") continue if max_val is not None and n > max_val: print(f"Must be at most {max_val}.") continue return n def prompt_str(prompt: str, required: bool = True) -> str | None: while True: val = input(prompt).strip() if not val: if not required: return None print("This field is required.") continue return val def prompt_datetime(prompt: str, default_now: bool = True) -> str: while True: default = datetime.now().strftime("%Y-%m-%d %H") val = input(f"{prompt} [{default}]: ").strip() if not val: if default_now: return default else: try: datetime.strptime(val, "%Y-%m-%d %H") return val except ValueError: print("Invalid format. Use YYYY-MM-DD HH.") continue def confirm(prompt: str) -> bool: val = input(f"{prompt} [y/N]: ").strip().lower() return val == "y"