Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 30 additions & 3 deletions inspect.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from contextlib import suppress
from reprlib import Repr

from talon import Context, Module, actions, ctrl, ui
Expand Down Expand Up @@ -108,11 +109,37 @@ def element_print(element, all_attributes, complex_attributes):


def element_context(element, pos=None, display=None):
while True:
if hasattr(element, "AXWindow"):
try:
app = element.window.app
except ui.UIErr:
pass
else:
break
match element.AXRole:
case "AXWindow":
with suppress(AttributeError):
app = element.app
break
case "AXApplication":
apps = ui.apps(name=element.AXTitle)
if len(apps) == 1:
app = apps[0]
break
if hasattr(element, "AXParent"):
element = element.parent
continue
app = None
break

Comment on lines +112 to +135
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think splitting it out into its own function can improve the readability a bit -- what do you think about this?

def extract_app(element) -> Optional[ui.App]:
    # Works around a macOS issue where elements lose their window property
    # https://github.com/talonvoice/talon/issues/XX
    while element:
        try:
            return element.window.app
        except (ui.UIErr, AttributeError):
            pass

        match element.AXRole:
            case "AXWindow":
                with suppress(AttributeError):
                    return element.app
            case "AXApplication":
                apps = ui.apps(name=element.AXTitle)
                if len(apps) == 1:
                    return apps[0]

        if not hasattr(element, "AXParent"):
            break

        element = element.parent
    return None

I normally would check for the property rather than catch the AttributeError, but since we're already doing this for ui.UIErr, I think it's cleaner and saves a level of indentation.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, hadn't filed an issue but have now (talonvoice/talon#689).

Your refactor looks good to me. Unfortunately sometimes checking for properties doesn't always work right with UI elements (see the ticket above), so I've defaulted to catching/suppressing exceptions.

return f"""Element{
f' {display}' if display else ""
f" {display}" if display else ""
}{
f' at {tuple(map(round, pos))}' if pos else ""
} in app bundle={element.window.app.bundle!r}:"""
f" at {tuple(map(round, pos))}" if pos else ""
} in app bundle={
f"{app.bundle!r}" if app else "<unknown>"
}:"""


def format_attributes(d, prefix=""):
Expand Down