"""Keep editable values separate from accessibility hints and visual labels.""" from typing import Any def _boolean(node: dict, *keys: str) -> bool | None: for key in keys: value = node.get(key) if isinstance(value, bool): return value if isinstance(value, str) and value.lower() in {"true", "false"}: return value.lower() == "true" return None def input_state(node: dict[str, Any]) -> dict[str, Any]: """Return value evidence only for an actual editable node, never OCR text. Equality with a hint is ambiguous on older backends: an application can legitimately contain that exact value. Only an explicit showing-hint flag proves that nonempty text is a placeholder. """ editable = _boolean(node, "editable", "isEditable") class_name = str(node.get("class") or node.get("className") or "").lower() if editable is None and "edittext" in class_name: editable = True if editable is not True: return {} hint = str(node.get("hint") or node.get("hintText") or node.get("hint-text") or "") showing = _boolean(node, "showing_hint", "showing-hint-text", "isShowingHintText", "is_hint") raw = node.get("text") value = raw if isinstance(raw, str) else None if showing is True: hint = hint or value or "" value = "" status = "empty" elif value is None: status = "unknown" elif not value: status = "empty" elif hint and value == hint and showing is not False: value = None status = "unknown" else: status = "present" return { "editable": True, "input_value": value, "input_value_state": status, "hint": hint, "showing_hint": showing, "focused": _boolean(node, "focused"), "password": _boolean(node, "password"), } def expected_input_state(text: str, clear_existing: bool) -> str | None: """Empty replacement means clear; empty append has no value postcondition.""" if text: return "present" return "empty" if clear_existing else None def verify_input(elements: list[dict], target: dict | None = None) -> str: """Verify value presence against a fresh tree, without returning its value. Resource identity wins over focus. Unidentifiable, masked, or unsupported inputs remain unknown; visual text elsewhere cannot establish input success. """ candidates = [] target = target or {} resource_id = target.get("target_resource_id") for element in elements: state = input_state(element) if "input_value_state" not in element else element if not state: continue if resource_id: if (element.get("resource_id") or element.get("resource-id")) == resource_id: candidates.append(state) elif state.get("focused") is True: candidates.append(state) if len(candidates) != 1: return "unknown" state = candidates[0] if state.get("password") is True and state.get("input_value_state") != "empty": return "unknown" return str(state["input_value_state"])