69 lines
2.1 KiB
Python
69 lines
2.1 KiB
Python
"""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
|