Source code for design_research_problems.gui._launcher

"""Core launcher for Tkinter GUI integrations."""

from __future__ import annotations

import argparse
from importlib import import_module
from typing import Any, Final, Literal, Protocol, cast

from design_research_problems._exceptions import MissingOptionalDependencyError

type GUIAppId = Literal["iot", "truss"]


class _TkModule(Protocol):
    """Minimal Tk module protocol required by this launcher."""

    def Tk(self) -> Any:
        """Construct and return the root Tk window."""
        ...


_GUI_APP_SPECS: Final[dict[GUIAppId, tuple[str, str, str]]] = {
    "iot": (
        "design_research_problems.gui.iot_home_cooling_tk",
        "IoTHomeCoolingApp",
        "1250x760",
    ),
    "truss": (
        "design_research_problems.gui.truss_analysis_program_tk",
        "TrussAPApp",
        "1260x760",
    ),
}


[docs] def list_gui_apps() -> tuple[GUIAppId, ...]: """Return supported GUI application identifiers.""" return tuple(_GUI_APP_SPECS)
def _import_tk() -> _TkModule: """Import tkinter or raise a stable optional-dependency error.""" try: import tkinter as tk except ModuleNotFoundError as exc: raise MissingOptionalDependencyError( "Tkinter is not available in this Python environment. " "Install/use a Python build with Tk support to run GUI examples." ) from exc return cast(_TkModule, tk)
[docs] def launch_gui(app: GUIAppId = "iot") -> None: """Launch one packaged Tkinter GUI app by identifier. Args: app: GUI identifier (`"iot"` or `"truss"`). Raises: ValueError: If ``app`` is unknown. MissingOptionalDependencyError: If Tkinter is unavailable. """ if app not in _GUI_APP_SPECS: valid = ", ".join(sorted(_GUI_APP_SPECS)) raise ValueError(f"Unknown GUI app id: {app!r}. Valid ids: {valid}") tk = _import_tk() module_path, class_name, geometry = _GUI_APP_SPECS[app] module = import_module(module_path) app_class = getattr(module, class_name) try: root = tk.Tk() except Exception as exc: raise MissingOptionalDependencyError( "Tkinter is installed but could not initialize a GUI window. " "Ensure Tcl/Tk runtime files are available in this environment." ) from exc root.geometry(geometry) app_class(root) root.mainloop()
[docs] def main() -> None: """Parse CLI arguments and launch one GUI app.""" parser = argparse.ArgumentParser(description="Launch a packaged design-research-problems GUI.") parser.add_argument( "--app", choices=list_gui_apps(), default="iot", help="GUI to launch: 'iot' or 'truss'.", ) args = parser.parse_args() try: launch_gui(app=args.app) except MissingOptionalDependencyError as exc: raise SystemExit(str(exc)) from exc
if __name__ == "__main__": main()