Source code for magboltz_gui.util.platform

# --- Put this at the very top of main.py (before creating QApplication) ---

import sys, platform, re
from pathlib import Path
from typing import Tuple, Optional


def _detect_linux_distro() -> str:
    """
    Returns a short distro key: 'debian', 'ubuntu', 'fedora', 'arch', 'opensuse', or 'linux'.
    """
    try:
        data = Path("/etc/os-release").read_text(errors="ignore")
    except Exception:
        return "linux"

    def get(k: str) -> str:
        m = re.search(rf'^{k}=(?:"([^"]+)"|([^\n]+))', data, flags=re.M)
        return (m.group(1) or m.group(2) or "").lower() if m else ""

    id_ = get("ID")
    like = get("ID_LIKE")
    # normalize some families
    if id_ in {"ubuntu"} or "ubuntu" in like:
        return "ubuntu"
    if id_ in {"debian"} or "debian" in like:
        return "debian"
    if id_ in {"fedora"} or "fedora" in like or "rhel" in like or "centos" in like:
        return "fedora"
    if id_ in {"arch", "manjaro", "endeavouros"} or "arch" in like:
        return "arch"
    if id_ in {"opensuse-leap", "opensuse-tumbleweed", "opensuse"} or "suse" in like:
        return "opensuse"
    return "linux"


def _print_install_help_for_missing_pyqt6() -> None:
    system = platform.system()
    if system == "Linux":
        d = _detect_linux_distro()
        print("\nPyQt6 (bindings) is not available.\n", file=sys.stderr)
        if d in {"debian", "ubuntu"}:
            print("Install system packages:", file=sys.stderr)
            print("  sudo apt install python3-pyqt6", file=sys.stderr)
            print("  ", file=sys.stderr)
            print("and be sure to recreate the .venv directory using:", file=sys.stderr)
            print("  uv venv --system-site-packages", file=sys.stderr)
        elif d == "fedora":
            print("Install system packages:", file=sys.stderr)
            print("  sudo dnf install python3-qt6", file=sys.stderr)
            print("  ", file=sys.stderr)
            print("and be sure to recreate the .venv directory using:", file=sys.stderr)
            print("  uv venv --system-site-packages", file=sys.stderr)
        elif d == "arch":
            print("Install system packages:", file=sys.stderr)
            print("  sudo pacman -S python-pyqt6", file=sys.stderr)
            print("  ", file=sys.stderr)
            print("and be sure to recreate the .venv directory using:", file=sys.stderr)
            print("  uv venv --system-site-packages", file=sys.stderr)
        elif d == "opensuse":
            print("Install system packages (adjust python version if needed):", file=sys.stderr)
            print("  sudo zypper install python311-qt6", file=sys.stderr)
            print("  ", file=sys.stderr)
            print("and be sure to recreate the .venv directory using:", file=sys.stderr)
            print("  uv venv --system-site-packages", file=sys.stderr)
        else:
            print("Install your distro’s PyQt6 package.", file=sys.stderr)
            print("Examples:", file=sys.stderr)
            print("  Debian/Ubuntu: sudo apt install python3-pyqt6", file=sys.stderr)
            print("  Fedora:        sudo dnf install python3-qt6", file=sys.stderr)
            print("  ", file=sys.stderr)
            print("and be sure to recreate the .venv directory using:", file=sys.stderr)
            print("  uv venv --system-site-packages", file=sys.stderr)
    elif system == "Darwin":  # macOS
        print("\nPyQt6 is not available on macOS.", file=sys.stderr)
        print("  python3 -m pip install PyQt6 PyQt6-Qt6 PyQt6-Qt6-Data", file=sys.stderr)
        print("Install using Homebrew Qt6:", file=sys.stderr)
        print("  brew install qt@6", file=sys.stderr)
        print("  ", file=sys.stderr)
        print("and be sure to recreate the .venv directory using:", file=sys.stderr)
        print("  uv venv --system-site-packages", file=sys.stderr)
        print("", file=sys.stderr)

    else:  # Windows / other
        print("\nPyQt6 is not available.\nInstall via PyPI:", file=sys.stderr)
        print("  py -m pip install  a\n", file=sys.stderr)
        print("", file=sys.stderr)
        print("  and be sure to recreate the .venv directory using:", file=sys.stderr)
        print("  uv venv --system-site-packages", file=sys.stderr)


def _platform_plugins_ok() -> Tuple[bool, Optional[str]]:
    """
    On Linux: check that at least one platform plugin we can use is present (wayland/xcb).
    On macOS: cocoa is baked in; if import works, we're fine.
    Returns (ok: bool, hint: str|None)
    """
    try:
        from PyQt6.QtCore import QLibraryInfo as LI

        plug_dir = Path(LI.path(LI.LibraryPath.PluginsPath)) / "platforms"
        # plugin filenames vary by OS
        files = [p.name.lower() for p in plug_dir.glob("*")]
        system = platform.system()
        if system == "Linux":
            has_wayland = any("wayland" in f for f in files)

            has_xcb = any("xcb" in f for f in files)
            if has_wayland or has_xcb:
                return True, None
            return False, f"Qt platform plugins not found in: {plug_dir}"
        elif system == "Darwin":
            # Cocoa comes with the Qt framework; if PyQt6 imported, it's generally fine.
            return True, None
        else:
            return True, None
    except Exception as e:
        return False, f"Failed to inspect Qt plugins: {e}"


[docs] def ensure_qt_runtime_or_explain() -> None: # Prefer Wayland if present, let Qt fall back automatically. # os.environ.setdefault("QT_QPA_PLATFORM", "wayland") # 1) PyQt6 available? try: import PyQt6 # noqa: F401 except Exception as e: _print_install_help_for_missing_pyqt6() print(f"Details: {e}\n", file=sys.stderr) sys.exit(1) ok, hint = _platform_plugins_ok() if not ok: print("\nQt platform plugins are missing or unusable.", file=sys.stderr) if hint: print(f"Details: {hint}", file=sys.stderr) print("Install a Qt platform plugin (wayland or xcb) and ensure it is discoverable.", file=sys.stderr) sys.exit(1)