dtmilano / AndroidViewClient

Android ViewServer and ADB client
Apache License 2.0
1.62k stars 345 forks source link

CulebraTester2 backend: error when using findViewWithAttributeThatMatches #319

Closed knyipab closed 1 year ago

knyipab commented 1 year ago

When using CulebraTester2 as backend, findViewWithAttributeThatMatches prompts below error message:

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In[5], line 1
----> 1 vc.findViewWithAttributeThatMatches("text", re.compile("^HA$"))

File [~/.local/lib/python3.10/site-packages/com/dtmilano/android/viewclient.py:4047](https://file+.vscode-resource.vscode-cdn.net/home/knyip/Documents/~/.local/lib/python3.10/site-packages/com/dtmilano/android/viewclient.py:4047), in ViewClient.findViewWithAttributeThatMatches(self, attr, regex, root)
   4041 def findViewWithAttributeThatMatches(self, attr, regex, root="ROOT"):
   4042     """
   4043     Finds the list of Views with the specified attribute matching
   4044     regex
   4045     """
-> 4047     return self.__findViewWithAttributeInTreeThatMatches(attr, regex, root)

File [~/.local/lib/python3.10/site-packages/com/dtmilano/android/viewclient.py:3958](https://file+.vscode-resource.vscode-cdn.net/home/knyip/Documents/~/.local/lib/python3.10/site-packages/com/dtmilano/android/viewclient.py:3958), in ViewClient.__findViewWithAttributeInTreeThatMatches(self, attr, regex, root, rlist)
   3953     root = self.root
   3955 if DEBUG: print("__findViewWithAttributeInTreeThatMatches: checking if root=%s attr=%s matches %s" % (
   3956     root.__smallStr__(), attr, regex), file=sys.stderr)
-> 3958 if root and attr in root.map and regex.match(root.map[attr]):
   3959     if DEBUG: print("__findViewWithAttributeInTreeThatMatches:  FOUND: %s" % root.__smallStr__(),
   3960                     file=sys.stderr)
   3961     return root

AttributeError: 'WindowHierarchy' object has no attribute 'map'

Currently, I use the workaround below:

import sys
import types
DEBUG = False
def findViewWithAttributeThatMatches(self, attr, regex, root="ROOT", rlist=[]):
    if not self.root:
        print("ERROR: no root, did you forget to call dump()?", file=sys.stderr)
        return None

    if root == "ROOT":
        root = self.root

    if DEBUG: print("__findViewWithAttributeInTreeThatMatches: checking if root=%s attr=%s matches %s" % (
        root.__smallStr__(), attr, regex), file=sys.stderr)

    if self.useUiAutomator and root == self.root:
        for ch in self.views:
            v = self._ViewClient__findViewWithAttributeInTreeThatMatches(attr, regex, ch, rlist)
            if v:
                return v
    else: 
        if root and attr in root.map and regex.match(root.map[attr]):
            if DEBUG: print("__findViewWithAttributeInTreeThatMatches:  FOUND: %s" % root.__smallStr__(),
                            file=sys.stderr)
            return root
        else:
            for ch in root.children:
                v = self._ViewClient__findViewWithAttributeInTreeThatMatches(attr, regex, ch, rlist)
                if v:
                    return v

    return None
vc = ViewClient(*ViewClient.connectToDeviceOrExit(), useuiautomatorhelper=True)
vc.findViewWithAttributeThatMatches = types.MethodType(findViewWithAttributeThatMatches, vc)
vc.findViewWithAttributeThatMatches("text", re.compile("^HA$"))
dtmilano commented 1 year ago

Hi @knyipab , Thanks for reporting this. As there are much better ways of finding objects when the backend is CulebraTester2 this may have gone unnoticed. https://github.com/dtmilano/AndroidViewClient/blob/master/examples/helper/find-object-by-regex is a good example and starting point.

dtmilano commented 1 year ago

And for multiple objects: https://github.com/dtmilano/AndroidViewClient/blob/master/examples/helper/find-objects-by-regex

knyipab commented 1 year ago

Thanks a lot for the info! I did not aware of such a useful functionality when I read the ducmentation at https://dtmilano.github.io/AndroidViewClient/. Thanks!

dtmilano commented 1 year ago

You are right, it might not be obvious to infer the functionality of the backend. This is a very good source of the available API: https://mrin9.github.io/OpenAPI-Viewer/#/load/https%3A%2F%2Fraw.githubusercontent.com%2Fdtmilano%2FCulebraTester2-public%2Fmaster%2Fopenapi.yaml