Wrap startup in try/except with file log + Tk messagebox
--noconsole exes silently exit on import-time errors, so when v0.3.2 crashed during startup the user just saw nothing happen. This wrapper: - Catches BaseException at module-import and main() level - Writes traceback to %LOCALAPPDATA%/sephiria_inv/startup.log - Pops a Tk messagebox-equivalent window with the traceback - Falls back gracefully if Tk itself is unavailable Also build with --console (no --noconsole) so prints/tracebacks are visible in real time. Once we know what is failing we can re-enable windowed mode.
This commit is contained in:
78
run.py
78
run.py
@@ -1,6 +1,80 @@
|
|||||||
"""PyInstaller entry shim."""
|
"""PyInstaller entry shim.
|
||||||
|
|
||||||
|
Wrapped in a top-level try/except so any startup failure is written to
|
||||||
|
%LOCALAPPDATA%\\sephiria_inv\\startup.log and surfaced to the user via a
|
||||||
|
Tk messagebox when possible. Without this wrapper, --noconsole builds
|
||||||
|
exit silently on import-time errors and the user sees "nothing happens".
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import traceback
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
|
||||||
|
def _log_path() -> str:
|
||||||
|
base = os.environ.get("LOCALAPPDATA") or os.path.expanduser("~")
|
||||||
|
folder = os.path.join(base, "sephiria_inv")
|
||||||
|
try:
|
||||||
|
os.makedirs(folder, exist_ok=True)
|
||||||
|
except OSError:
|
||||||
|
folder = os.path.dirname(os.path.abspath(sys.argv[0])) or "."
|
||||||
|
return os.path.join(folder, "startup.log")
|
||||||
|
|
||||||
|
|
||||||
|
def _write_log(msg: str) -> str:
|
||||||
|
path = _log_path()
|
||||||
|
try:
|
||||||
|
with open(path, "a", encoding="utf-8") as fh:
|
||||||
|
fh.write(f"\n=== {datetime.now().isoformat()} ===\n{msg}\n")
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
return path
|
||||||
|
|
||||||
|
|
||||||
|
def _show_error(title: str, body: str) -> None:
|
||||||
|
try:
|
||||||
|
import tkinter as tk
|
||||||
|
from tkinter import scrolledtext
|
||||||
|
root = tk.Tk()
|
||||||
|
root.title(title)
|
||||||
|
root.geometry("760x420")
|
||||||
|
txt = scrolledtext.ScrolledText(root, wrap="word")
|
||||||
|
txt.pack(fill="both", expand=True)
|
||||||
|
txt.insert("1.0", body)
|
||||||
|
tk.Button(root, text="Close", command=root.destroy).pack(pady=4)
|
||||||
|
root.mainloop()
|
||||||
|
except Exception:
|
||||||
|
# Tk itself is broken; nothing we can show.
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def _main() -> int:
|
||||||
|
try:
|
||||||
from sephiria_inv.__main__ import main
|
from sephiria_inv.__main__ import main
|
||||||
|
except BaseException:
|
||||||
|
tb = traceback.format_exc()
|
||||||
|
log = _write_log("IMPORT FAIL\n" + tb)
|
||||||
|
_show_error(
|
||||||
|
"sephiria_inv: import failed",
|
||||||
|
f"Failed to import sephiria_inv.__main__\n\nLog: {log}\n\n{tb}",
|
||||||
|
)
|
||||||
|
return 11
|
||||||
|
try:
|
||||||
|
return int(main() or 0)
|
||||||
|
except SystemExit:
|
||||||
|
raise
|
||||||
|
except BaseException:
|
||||||
|
tb = traceback.format_exc()
|
||||||
|
log = _write_log("RUNTIME FAIL\n" + tb)
|
||||||
|
_show_error(
|
||||||
|
"sephiria_inv: runtime error",
|
||||||
|
f"Crashed during main()\n\nLog: {log}\n\n{tb}",
|
||||||
|
)
|
||||||
|
return 12
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
raise SystemExit(main())
|
raise SystemExit(_main())
|
||||||
|
|||||||
Reference in New Issue
Block a user