Files
HighCostDrugsDemo/app_desktop.py
T
Andrew Charlwood 7e63e6ea45 feat: add desktop packaging (pywebview + PyInstaller)
- resource_path.py: frozen/dev path resolution for bundled data files
- app_desktop.py: pywebview entry point (Dash in daemon thread)
- app.spec: PyInstaller onedir config with data files and hidden imports
- Updated queries.py, card_browser.py, app.py to use get_resource_path()
- Added pywebview + pyinstaller to project dependencies
- Fixed unresolved merge conflict in .gitignore
- Removed stale 01_nhs_classic.html and AdditionalAnalytics.md
2026-02-09 14:53:22 +00:00

63 lines
1.7 KiB
Python

"""Desktop entry point: Dash app inside a pywebview native window."""
import sys
import socket
import threading
import time
from pathlib import Path
# Ensure src/ is on sys.path so that core/, data_processing/, etc. are importable
_src_dir = str(Path(__file__).resolve().parent / "src")
if _src_dir not in sys.path:
sys.path.insert(0, _src_dir)
import webview
from dash_app.app import app
def find_free_port(start: int = 8050) -> int:
"""Find the first available port starting from *start*."""
for port in range(start, start + 100):
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
try:
s.bind(("127.0.0.1", port))
return port
except OSError:
continue
raise RuntimeError("No free port found")
def wait_for_server(port: int, timeout: float = 30.0) -> None:
"""Block until the Dash server accepts connections."""
deadline = time.monotonic() + timeout
while time.monotonic() < deadline:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
if s.connect_ex(("127.0.0.1", port)) == 0:
return
time.sleep(0.1)
raise TimeoutError(f"Server did not start within {timeout}s")
def main() -> None:
port = find_free_port()
server_thread = threading.Thread(
target=app.run,
kwargs={"debug": False, "port": port, "use_reloader": False},
daemon=True,
)
server_thread.start()
wait_for_server(port)
webview.create_window(
"NHS Pathway Analysis",
f"http://127.0.0.1:{port}",
width=1400,
height=900,
)
webview.start()
if __name__ == "__main__":
main()