Milestone alpha3

This commit is contained in:
2026-05-22 16:05:57 +02:00
parent d2a1f6a068
commit 4dabba8ce7
5 changed files with 561 additions and 52 deletions

83
main.py
View File

@@ -14,7 +14,7 @@ import time
import customtkinter as ctk
from tkinter import messagebox
from async_loop_singleton import get_global_loop
from async_loop_singleton import get_global_loop, stop_global_loop
from async_msssql_query import AsyncMSSQLClient
from audit_log import log_session_event
from db_config import build_dsn_from_config, ensure_db_config
@@ -45,12 +45,6 @@ BYPASS_LOGIN_USER = {
"codice_unita": "U1",
}
if sys.platform.startswith("win"):
try:
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
except Exception:
pass
# Create one global loop and make it the default everywhere.
_loop = get_global_loop()
asyncio.set_event_loop(_loop)
@@ -71,6 +65,51 @@ _APP_MUTEX = None
_APP_MUTEX_NAME = "Local\\WarehousePythonAppSingleton"
def _dispose_db_client() -> None:
"""Best-effort disposal of the shared DB client."""
global db_app
if db_app is None:
return
try:
fut = asyncio.run_coroutine_threadsafe(db_app.dispose(), _loop)
try:
fut.result(timeout=2)
except Exception:
pass
finally:
db_app = None
def _destroy_tk_root(root: tk.Misc | None) -> None:
"""Destroy a hidden bootstrap root without leaking a Tk interpreter."""
if root is None:
return
try:
root.quit()
except Exception:
pass
try:
root.destroy()
except Exception:
pass
def _shutdown_runtime(*, bootstrap: tk.Misc | None = None, dispose_db: bool = True) -> None:
"""Release temporary Tk resources, DB client and background loop."""
try:
_destroy_tk_root(bootstrap)
finally:
if dispose_db:
_dispose_db_client()
try:
stop_global_loop()
except Exception:
pass
def _acquire_single_instance_mutex() -> bool:
"""Return ``True`` only for the first running instance of the application."""
@@ -435,14 +474,19 @@ if __name__ == "__main__":
),
parent=root,
)
_destroy_tk_root(root)
try:
root.destroy()
stop_global_loop()
except Exception:
pass
raise SystemExit(0)
db_cfg = ensure_db_config(_loop)
if db_cfg is None:
try:
stop_global_loop()
except Exception:
pass
raise SystemExit(0)
db_app = AsyncMSSQLClient(build_dsn_from_config(db_cfg))
@@ -466,23 +510,12 @@ if __name__ == "__main__":
session = prompt_login(bootstrap, db_app)
if session is None:
if db_app is not None:
fut = asyncio.run_coroutine_threadsafe(db_app.dispose(), _loop)
try:
fut.result(timeout=2)
except Exception:
pass
try:
if bootstrap is not None:
bootstrap.destroy()
except Exception:
pass
_shutdown_runtime(bootstrap=bootstrap, dispose_db=True)
raise SystemExit(0)
try:
if bootstrap is not None:
bootstrap.destroy()
except Exception:
pass
_destroy_tk_root(bootstrap)
Launcher(session, db_app).mainloop()
try:
Launcher(session, db_app).mainloop()
finally:
_shutdown_runtime(bootstrap=None, dispose_db=True)