"""Inspektera Windows-fönster för att hitta rätt selectors till desktop_*-stegen (motsvarigheten till rpa/discover.py fast för skrivbordsappar). python -m rpa.desktop_inspect # listar synliga toppfönster python -m rpa.desktop_inspect "Anteckningar" # dumpar kontroll-identifierare Kör på Windows-maskinen med målappen igång. Använd 'name'/'auto_id'/ 'control_type' från utskriften i webui:ts desktop-steg (webui:t har samma funktion under ⚙ → Inspektera fönster). """ from __future__ import annotations import sys class InspectUnavailable(RuntimeError): """pywinauto kunde inte laddas (icke-Windows?).""" def _desktop(): try: from pywinauto import Desktop except Exception as exc: # noqa: BLE001 raise InspectUnavailable( f"pywinauto kunde inte laddas (Windows-only): {exc}" ) from exc return Desktop(backend="uia") def list_windows() -> list[str]: """Titlarna på alla synliga toppfönster.""" out: list[str] = [] for w in _desktop().windows(): try: if w.is_visible() and w.window_text(): out.append(w.window_text()) except Exception: # noqa: BLE001 continue # unika, i ordning seen: set[str] = set() return [t for t in out if not (t in seen or seen.add(t))] def inspect_window(title: str, max_depth: int = 6, limit: int = 800) -> list[dict]: """Plattad lista över kontrollerna i första fönstret vars titel matchar `title` (regex). Varje rad: {depth, control_type, name, auto_id, class_name}.""" desktop = _desktop() matches = desktop.windows(title_re=title, visible_only=True) if not matches: raise ValueError(f"Hittade inget synligt fönster med titel som matchar {title!r}") win = desktop.window(handle=matches[0].handle) win.wait("exists", timeout=10) rows: list[dict] = [] def walk(ctrl, depth: int) -> None: if len(rows) >= limit or depth > max_depth: return try: info = ctrl.element_info rows.append({ "depth": depth, "control_type": getattr(info, "control_type", "") or "", "name": (ctrl.window_text() or "").strip(), "auto_id": getattr(info, "automation_id", "") or "", "class_name": getattr(info, "class_name", "") or "", }) except Exception: # noqa: BLE001 return try: for child in ctrl.children(): walk(child, depth + 1) except Exception: # noqa: BLE001 pass walk(win, 0) return rows def main() -> None: try: if len(sys.argv) < 2: wins = list_windows() print("Synliga toppfönster:\n") for t in wins: print(f" {t!r}") print('\nKör igen med en titel (regex), t.ex.:\n python -m rpa.desktop_inspect "Anteckningar"') return for row in inspect_window(sys.argv[1]): indent = " " * row["depth"] bits = [f'{indent}{row["control_type"] or "?"}'] if row["name"]: bits.append(f'name={row["name"]!r}') if row["auto_id"]: bits.append(f'auto_id={row["auto_id"]!r}') if row["class_name"]: bits.append(f'class={row["class_name"]!r}') print(" ".join(bits)) except (InspectUnavailable, ValueError) as exc: sys.exit(str(exc)) if __name__ == "__main__": main()