"""Runtime helpers for console-less Windows launches.""" from __future__ import annotations import sys import traceback from datetime import datetime from pathlib import Path from typing import Callable, TypeVar BASE_DIR = Path(__file__).resolve().parent FATAL_LOG = BASE_DIR / "warehouse_fatal.log" _STDIO_HANDLES = [] T = TypeVar("T") def ensure_stdio(app_name: str) -> None: """Give ``pythonw`` a real stdout/stderr target before loggers are imported.""" stamp = datetime.now().strftime("%Y%m%d") if sys.stdout is None: handle = (BASE_DIR / f"{app_name}_stdout_{stamp}.log").open("a", encoding="utf-8", buffering=1) _STDIO_HANDLES.append(handle) sys.stdout = handle if sys.stderr is None: handle = (BASE_DIR / f"{app_name}_stderr_{stamp}.log").open("a", encoding="utf-8", buffering=1) _STDIO_HANDLES.append(handle) sys.stderr = handle def log_fatal(app_name: str, exc: BaseException) -> None: """Write one startup/runtime crash to a persistent log file.""" with FATAL_LOG.open("a", encoding="utf-8") as handle: handle.write("\n" + "=" * 80 + "\n") handle.write(f"{datetime.now():%Y-%m-%d %H:%M:%S} | {app_name}\n") handle.write("".join(traceback.format_exception(type(exc), exc, exc.__traceback__))) def show_fatal_message(app_name: str, exc: BaseException) -> None: """Show a best-effort message box for console-less launches.""" try: import tkinter as tk from tkinter import messagebox root = tk.Tk() root.withdraw() messagebox.showerror( app_name, f"Avvio non riuscito.\n\nDettaglio salvato in:\n{FATAL_LOG}\n\n{exc}", parent=root, ) root.destroy() except Exception: pass def run_with_fatal_log(app_name: str, func: Callable[[], T]) -> T: """Run an app entry point and persist otherwise invisible ``pythonw`` crashes.""" try: return func() except BaseException as exc: log_fatal(app_name, exc) show_fatal_message(app_name, exc) raise