Best Python code snippet using fMBT_python
fmbtgti.py
Source:fmbtgti.py  
...91_g_ocrEngines = []92_g_oirEngines = []93def _fmbtLog(msg):94    fmbt.fmbtlog("fmbtgti: %s" % (msg,))95def _filenameTimestamp(t=None):96    if t == None:97        t = datetime.datetime.now()98    return t.strftime("%Y%m%d-%H%M%S-%f")99def _takeDragArgs(d):100    return _takeArgs(("startPos", "delayBeforeMoves", "delayBetweenMoves",101                      "delayAfterMoves", "movePoints"), d)102def _takeTapArgs(d):103    return _takeArgs(("tapPos", "long", "hold", "count", "delayBetweenTaps", "button"), d)104def _takeWaitArgs(d):105    return _takeArgs(("waitTime", "pollDelay"), d)106def _takeOirArgs(screenshotOrOirEngine, d, thatsAll=False):107    if isinstance(screenshotOrOirEngine, Screenshot):108        oirEngine = screenshotOrOirEngine.oirEngine()109    else:110        oirEngine = screenshotOrOirEngine111    return _takeArgs(oirEngine._findBitmapArgNames(), d, thatsAll)112def _takeOcrArgs(screenshotOrOcrEngine, d, thatsAll=False):113    if isinstance(screenshotOrOcrEngine, Screenshot):114        ocrEngine = screenshotOrOcrEngine.ocrEngine()115    else:116        ocrEngine = screenshotOrOcrEngine117    return _takeArgs(ocrEngine._findTextArgNames(), d, thatsAll)118def _takeArgs(argNames, d, thatsAll=False):119    """120    Returns pair:121        (dict of items where key in argNames,122         dict of items that were left in d)123    If thatsAll is True, require that all arguments have been124    consumed.125    """126    retval = {}127    for a in argNames:128        if a in d:129            retval[a] = d.pop(a, None)130    if thatsAll and len(d) > 0:131        raise TypeError('Unknown argument(s): "%s"' %132                        ('", "'.join(sorted(d.keys()))))133    return retval, d134def _intCoords((x, y), (width, height)):135    if 0 <= x <= 1 and type(x) == float: x = x * width136    if 0 <= y <= 1 and type(y) == float: y = y * height137    return (int(round(x)), int(round(y)))138def _edgeDistanceInDirection((x, y), (width, height), direction):139    x, y = _intCoords((x, y), (width, height))140    direction = direction % 360 # -90 => 270, 765 => 45141    dirRad = math.radians(direction)142    if 0 < direction < 180:143        distTopBottom = y / math.sin(dirRad)144    elif 180 < direction < 360:145        distTopBottom = -(height - y) / math.sin(dirRad)146    else:147        distTopBottom = float('inf')148    if 90 < direction < 270:149        distLeftRight = -x / math.cos(dirRad)150    elif 270 < direction <= 360 or 0 <= direction < 90:151        distLeftRight = (width - x) / math.cos(dirRad)152    else:153        distLeftRight = float('inf')154    return min(distTopBottom, distLeftRight)155### Binding to eye4graphics.so156_libpath = ["", ".", distutils.sysconfig.get_python_lib(plat_specific=1)]157_suffix = ".so"158if sys.platform == "win32":159    _suffix = ".dll"160for _dirname in _libpath:161    try:162        eye4graphics = ctypes.CDLL(os.path.join(_dirname , "eye4graphics"+_suffix))163        break164    except: pass165else:166    raise ImportError("%s cannot load eye4graphics.so" % (__file__,))167class _Bbox(ctypes.Structure):168    _fields_ = [("left", ctypes.c_int32),169                ("top", ctypes.c_int32),170                ("right", ctypes.c_int32),171                ("bottom", ctypes.c_int32),172                ("error", ctypes.c_int32)]173### end of binding to eye4graphics.so174def _e4gImageDimensions(e4gImage):175    struct_bbox = _Bbox(0, 0, 0, 0, 0)176    eye4graphics.openedImageDimensions(ctypes.byref(struct_bbox), e4gImage)177    return (struct_bbox.right, struct_bbox.bottom)178def _e4gImageIsBlank(filename):179    e4gImage = eye4graphics.openImage(filename)180    rv = (eye4graphics.openedImageIsBlank(e4gImage) == 1)181    eye4graphics.closeImage(e4gImage)182    return rv183class GUITestConnection(object):184    """185    Implements GUI testing primitives needed by GUITestInterface.186    All send* and recv* methods return187    - True on success188    - False on user error (unknown keyName, coordinates out of range)189    - raise Exception on framework error (connection lost, missing190      dependencies).191    """192    def sendPress(self, keyName):193        raise NotImplementedError('sendPress("%s") needed but not implemented.' % (keyName,))194    def sendKeyDown(self, keyName):195        raise NotImplementedError('sendKeyDown("%s") needed but not implemented.' % (keyName,))196    def sendKeyUp(self, keyName):197        raise NotImplementedError('sendKeyUp("%s") needed but not implemented.' % (keyName,))198    def sendTap(self, x, y):199        raise NotImplementedError('sendTap(%d, %d) needed but not implemented.' % (x, y))200    def sendTouchDown(self, x, y):201        raise NotImplementedError('sendTouchDown(%d, %d) needed but not implemented.' % (x, y))202    def sendTouchMove(self, x, y):203        raise NotImplementedError('sendTouchMove(%d, %d) needed but not implemented.' % (x, y))204    def sendTouchUp(self, x, y):205        raise NotImplementedError('sendTouchUp(%d, %d) needed but not implemented.' % (x, y))206    def sendType(self, text):207        raise NotImplementedError('sendType("%s") needed but not implemented.' % (text,))208    def recvScreenshot(self, filename):209        """210        Saves screenshot from the GUI under test to given filename.211        """212        raise NotImplementedError('recvScreenshot("%s") needed but not implemented.' % (filename,))213    def target(self):214        """215        Returns a string that is unique to each test target. For216        instance, Android device serial number.217        """218        return "GUITestConnectionTarget"219class OrEngine(object):220    """221    Optical recognition engine. Base class for OCR and OIR engines,222    enables registering engine instances.223    """224    def __init__(self, *args, **kwargs):225        pass226    def register(self, defaultOcr=False, defaultOir=False):227        """228        Register this engine instance to the list of OCR and/or OIR229        engines.230        Parameters:231          defaultOcr (optional, boolean):232                  if True, use this OCR engine by default in all new233                  GUITestInterface instances. The default is False.234          defaultOir (optional, boolean):235                  if True, use this OIR engine by default in all new236                  GUITestInterface instances. The default is False.237        Returns the index with which the engine was registered to the238        list of OCR or OIR engines. If this instance implements both239        OCR and OIR engines, returns pair (OCR index, OIR index).240        """241        # Allow a single engine implement both OCR and OIR engine242        # interfaces. Therefore, it must be possible to call243        # e.register(defaultOcr=True, defaultOir=True).244        #245        global _g_defaultOcrEngine, _g_defaultOirEngine246        global _g_ocrEngines, _g_oirEngines247        engineIndexes = []248        if isinstance(self, OcrEngine):249            if not self in _g_ocrEngines:250                _g_ocrEngines.append(self)251            engineIndexes.append(_g_ocrEngines.index(self))252            if defaultOcr:253                _g_defaultOcrEngine = self254        if isinstance(self, OirEngine):255            if not self in _g_oirEngines:256                _g_oirEngines.append(self)257            engineIndexes.append(_g_oirEngines.index(self))258            if defaultOir:259                _g_defaultOirEngine = self260        if len(engineIndexes) == 1:261            return engineIndexes[0]262        else:263            return engineIndexes264class OcrEngine(OrEngine):265    """266    This is an abstract interface for OCR engines that can be plugged267    into fmbtgti.GUITestInterface instances and Screenshots.268    To implement an OCR engine, you need to override _findText() at269    minimum. See _findText documentation in this class for270    requirements.271    If possible in your OCR engine, you can provide _dumpOcr() to272    reveal what is recognized in screenshots.273    For efficient caching of results and freeing cached results, you274    can override _addScreenshot() and _removeScreenshot(). Every275    screenshot is added before findText() or dumpOcr().276    A typical usage of OcrEngine instance:277    - oe.addScreenshot(ss)278    - oe.findText(ss, text1, <engine/screenshot/find-specific-args>)279    - oe.findText(ss, text2, <engine/screenshot/find-specific-args>)280    - oe.removeScreenshot(ss)281    Note that there may be several screenshots added before they are282    removed.283    """284    def __init__(self, *args, **kwargs):285        super(OcrEngine, self).__init__(*args, **kwargs)286        self._ssFindTextDefaults = {}287        self._findTextDefaults = {}288        ocrFindArgs, _ = _takeOcrArgs(self, kwargs)289        self._setFindTextDefaults(ocrFindArgs)290    def dumpOcr(self, screenshot, **kwargs):291        """292        Returns what is recognized in the screenshot. For debugging293        purposes.294        """295        ocrArgs = self.__ocrArgs(screenshot, **kwargs)296        return self._dumpOcr(screenshot, **ocrArgs)297    def _dumpOcr(self, screenshot, **kwargs):298        return None299    def addScreenshot(self, screenshot, **findTextDefaults):300        """301        Prepare for finding text from the screenshot.302        Parameters:303          screenshot (fmbtgti.Screenshot)304                  screenshot object to be searched from.305          other parameters (optional)306                  findText defaults for this screenshot.307        Notice that there may be many screenshots simultaneously.308        Do not keep reference to the screenshot object.309        """310        self.setScreenshotFindTextDefaults(screenshot, **findTextDefaults)311        return self._addScreenshot(screenshot, **findTextDefaults)312    def _addScreenshot(self, screenshot, **findTextDefaults):313        pass314    def removeScreenshot(self, screenshot):315        """316        OCR queries on the screenshot will not be made anymore.317        """318        self._removeScreenshot(screenshot)319        try:320            del self._ssFindTextDefaults[id(screenshot)]321        except KeyError:322            raise KeyError('screenshot "%s" does not have findTextDefaults. '323                           'If OcrEngine.addScreenshot() is overridden, it '324                           '*must* call parent\'s addScreenshot.' % (screenshot.filename(),))325    def _removeScreenshot(self, screenshot):326        pass327    def setFindTextDefaults(self, **findTextDefaults):328        return self._setFindTextDefaults(findTextDefaults, screenshot=None)329    def setScreenshotFindTextDefaults(self, screenshot, **findTextDefaults):330        return self._setFindTextDefaults(findTextDefaults, screenshot=screenshot)331    def _setFindTextDefaults(self, defaults, screenshot=None):332        """333        Set default values for optional arguments for findText().334        Parameters:335          defaults (dictionary)336                  Default keyword arguments and their values.337          screenshot (optional, fmbtgti.Screenshot instance)338                  Use the defaults for findText on this screenshot. If339                  the defaults are None, make them default for all340                  screenshots. Screenshot-specific defaults override341                  engine default.342        """343        if screenshot == None:344            self._findTextDefaults.update(defaults)345        else:346            ssid = id(screenshot)347            if not ssid in self._ssFindTextDefaults:348                self._ssFindTextDefaults[ssid] = self._findTextDefaults.copy()349            self._ssFindTextDefaults[ssid].update(defaults)350    def findTextDefaults(self, screenshot=None):351        if screenshot == None:352            return self._findTextDefaults353        elif id(screenshot) in self._ssFindTextDefaults:354            return self._ssFindTextDefaults[id(screenshot)]355        else:356            return None357    def _findTextArgNames(self):358        """359        Returns names of optional findText arguments.360        """361        return inspect.getargspec(self._findText).args[3:]362    def __ocrArgs(self, screenshot, **priorityArgs):363        ocrArgs = {}364        ocrArgs.update(self._findTextDefaults)365        ssId = id(screenshot)366        if ssId in self._ssFindTextDefaults:367            ocrArgs.update(self._ssFindTextDefaults[ssId])368        ocrArgs.update(priorityArgs)369        return ocrArgs370    def findText(self, screenshot, text, **kwargs):371        """372        Return list of fmbtgti.GUIItems that match to text.373        """374        ocrArgs = self.__ocrArgs(screenshot, **kwargs)375        return self._findText(screenshot, text, **ocrArgs)376    def _findText(self, screenshot, text, **kwargs):377        """378        Find appearances of text from the screenshot.379        Parameters:380          screenshot (fmbtgti.Screenshot)381                  Screenshot from which text is to be searched382                  for. Use Screenshot.filename() to get the filename.383          text (string)384                  text to be searched for.385          other arguments (engine specific)386                  kwargs contain keyword arguments given to387                  findText(screenshot, text, ...), already extended388                  first with screenshot-specific findTextDefaults, then389                  with engine-specific findTextDefaults.390                  _findText *must* define all engine parameters as391                  explicit keyword arguments:392                  def _findText(self, screenshot, text, engArg1=42):393                      ...394        Return list of fmbtgti.GUIItems.395        """396        raise NotImplementedError("_findText needed but not implemented.")397class _EyenfingerOcrEngine(OcrEngine):398    """399    OCR engine parameters that can be used in all400    ...OcrText() methods (swipeOcrText, tapOcrText, findItemsByOcrText, ...):401      match (float, optional):402              minimum match score in range [0.0, 1.0].  The default is403              1.0 (exact match).404      area ((left, top, right, bottom), optional):405              search from the given area only. Left, top, right and406              bottom are either absolute coordinates (integers) or407              floats in range [0.0, 1.0]. In the latter case they are408              scaled to screenshot dimensions. The default is (0.0,409              0.0, 1.0, 1.0), that is, search everywhere in the410              screenshot.411      pagesegmodes (list of integers, optional):412              try all integers as tesseract -pagesegmode413              arguments. The default is [3], another good option could414              be [3, 6].415      preprocess (string, optional):416              preprocess filter to be used in OCR for better417              result. Refer to eyenfinger.autoconfigure to search for418              a good one.419    """420    class _OcrResults(object):421        __slots__ = ("filename", "screenSize", "pagesegmodes", "preprocess", "area", "words")422        def __init__(self, filename, screenSize):423            self.filename = filename424            self.screenSize = screenSize425            self.pagesegmodes = None426            self.preprocess = None427            self.area = None428            self.words = None429    def __init__(self, *args, **engineDefaults):430        engineDefaults["area"] = engineDefaults.get("area", (0.0, 0.0, 1.0, 1.0))431        engineDefaults["match"] = engineDefaults.get("match", 1.0)432        engineDefaults["pagesegmodes"] = engineDefaults.get("pagesegmodes", _OCRPAGESEGMODES)433        engineDefaults["preprocess"] = engineDefaults.get("preprocess", _OCRPREPROCESS)434        super(_EyenfingerOcrEngine, self).__init__(*args, **engineDefaults)435        self._ss = {} # OCR results for screenshots436    def _addScreenshot(self, screenshot, **findTextDefaults):437        ssId = id(screenshot)438        self._ss[ssId] = _EyenfingerOcrEngine._OcrResults(screenshot.filename(), screenshot.size())439    def _removeScreenshot(self, screenshot):440        ssId = id(screenshot)441        if ssId in self._ss:442            del self._ss[ssId]443    def _findText(self, screenshot, text, match=None, preprocess=None, area=None, pagesegmodes=None):444        ssId = id(screenshot)445        self._assumeOcrResults(screenshot, preprocess, area, pagesegmodes)446        for ppfilter in self._ss[ssId].words.keys():447            try:448                score_text_bbox_list = eyenfinger.findText(449                    text, self._ss[ssId].words[ppfilter], match=match)450                if not score_text_bbox_list:451                    continue452                else:453                    break454            except eyenfinger.BadMatch:455                continue456        else:457            return []458        retval = [GUIItem("OCR text (match %.2f)" % (score,),459                          bbox, self._ss[ssId].filename,460                          ocrFind=text, ocrFound=matching_text)461                  for score, matching_text, bbox in score_text_bbox_list]462        return retval463    def _dumpOcr(self, screenshot, match=None, preprocess=None, area=None, pagesegmodes=None):464        ssId = id(screenshot)465        if self._ss[ssId].words == None:466            self._assumeOcrResults(screenshot, preprocess, area, pagesegmodes)467        w = []468        for ppfilter in self._ss[ssId].preprocess:469            for word in self._ss[ssId].words[ppfilter]:470                for appearance, (wid, middle, bbox) in enumerate(self._ss[ssId].words[ppfilter][word]):471                    (x1, y1, x2, y2) = bbox472                    w.append((word, (x1, y1, x2, y2)))473        return sorted(set(w), key=lambda i:(i[1][1]/8, i[1][0]))474    def _assumeOcrResults(self, screenshot, preprocess, area, pagesegmodes):475        ssId = id(screenshot)476        if not type(preprocess) in (list, tuple):477            preprocess = [preprocess]478        if self._ss[ssId].words == None or self._ss[ssId].preprocess != preprocess or self._ss[ssId].area != area:479            self._ss[ssId].words = {}480            self._ss[ssId].preprocess = preprocess481            self._ss[ssId].area = area482            for ppfilter in preprocess:483                pp = ppfilter % { "zoom": "-resize %sx" % (self._ss[ssId].screenSize[0] * 2) }484                eyenfinger.iRead(source=self._ss[ssId].filename, ocr=True, preprocess=pp, ocrArea=area, ocrPageSegModes=pagesegmodes)485                self._ss[ssId].words[ppfilter] = eyenfinger._g_words486def _defaultOcrEngine():487    if _g_defaultOcrEngine:488        return _g_defaultOcrEngine489    else:490        _EyenfingerOcrEngine().register(defaultOcr=True)491        return _g_defaultOcrEngine492class OirEngine(OrEngine):493    """494    This is an abstract interface for OIR (optical image recognition)495    engines that can be plugged into fmbtgti.GUITestInterface496    instances and Screenshots.497    To implement an OIR engine, you need to override _findBitmap() at498    minimum. See _findBitmap documentation in this class for499    requirements.500    This base class provides full set of OIR parameters to501    _findBitmap. The parameters are combined from502    - OirEngine find defaults, specified when OirEngine is503      instantiated.504    - Screenshot instance find defaults.505    - bitmap / bitmap directory find defaults (read from the506      .fmbtoirrc that is in the same directory as the bitmap).507    - ...Bitmap() method parameters.508    The latter in the list override the former.509    For efficient caching of results and freeing cached results, you510    can override _addScreenshot() and _removeScreenshot(). Every511    screenshot is added before findBitmap().512    A typical usage of OirEngine instance:513    - oe.addScreenshot(ss)514    - oe.findBitmap(ss, bmpFilename1, <engine/screenshot/find-specific-args>)515    - oe.findBitmap(ss, bmpFilename2, <engine/screenshot/find-specific-args>)516    - oe.removeScreenshot(ss)517    Note that there may be several screenshots added before they are518    removed. ss is a Screenshot instance. Do not keep references to519    Screenshot intances, otherwise garbage collector will not remove520    them.521    """522    def __init__(self, *args, **kwargs):523        super(OirEngine, self).__init__(*args, **kwargs)524        self._ssFindBitmapDefaults = {}525        self._findBitmapDefaults = {}526        oirArgs, _ = _takeOirArgs(self, kwargs)527        self._setFindBitmapDefaults(oirArgs)528    def addScreenshot(self, screenshot, **findBitmapDefaults):529        """530        Prepare for finding bitmap from the screenshot.531        Parameters:532          screenshot (fmbtgti.Screenshot)533                  screenshot object to be searched from.534          other parameters (optional)535                  findBitmap defaults for this screenshot.536        Notice that there may be many screenshots simultaneously.537        Do not keep reference to the screenshot object.538        """539        self.setScreenshotFindBitmapDefaults(screenshot, **findBitmapDefaults)540        return self._addScreenshot(screenshot, **findBitmapDefaults)541    def _addScreenshot(self, screenshot, **findBitmapDefaults):542        pass543    def removeScreenshot(self, screenshot):544        """545        OIR queries on the screenshot will not be made anymore.546        """547        self._removeScreenshot(screenshot)548        try:549            del self._ssFindBitmapDefaults[id(screenshot)]550        except KeyError:551            raise KeyError('screenshot "%s" does not have findBitmapDefaults. '552                           'If OirEngine.addScreenshot() is overridden, it '553                           '*must* call parent\'s addScreenshot.' % (screenshot.filename(),))554    def _removeScreenshot(self, screenshot):555        pass556    def setFindBitmapDefaults(self, **findBitmapDefaults):557        return self._setFindBitmapDefaults(findBitmapDefaults, screenshot=None)558    def setScreenshotFindBitmapDefaults(self, screenshot, **findBitmapDefaults):559        return self._setFindBitmapDefaults(findBitmapDefaults, screenshot=screenshot)560    def _setFindBitmapDefaults(self, defaults, screenshot=None):561        """562        Set default values for optional arguments for findBitmap().563        Parameters:564          defaults (dictionary)565                  Default keyword arguments and their values.566          screenshot (optional, fmbtgti.Screenshot instance)567                  Use the defaults for findBitmap on this screenshot. If568                  the defaults are None, make them default for all569                  screenshots. Screenshot-specific defaults override570                  engine default.571        """572        if screenshot == None:573            self._findBitmapDefaults.update(defaults)574        else:575            ssid = id(screenshot)576            if not ssid in self._ssFindBitmapDefaults:577                self._ssFindBitmapDefaults[ssid] = self._findBitmapDefaults.copy()578            self._ssFindBitmapDefaults[ssid].update(defaults)579    def findBitmapDefaults(self, screenshot=None):580        if screenshot == None:581            return self._findBitmapDefaults582        elif id(screenshot) in self._ssFindBitmapDefaults:583            return self._ssFindBitmapDefaults[id(screenshot)]584        else:585            return None586    def _findBitmapArgNames(self):587        """588        Returns names of optional findBitmap arguments.589        """590        return inspect.getargspec(self._findBitmap).args[3:]591    def __oirArgs(self, screenshot, bitmap, **priorityArgs):592        oirArgs = {}593        oirArgs.update(self._findBitmapDefaults)594        ssId = id(screenshot)595        if ssId in self._ssFindBitmapDefaults:596            oirArgs.update(self._ssFindBitmapDefaults[ssId])597        oirArgs.update(priorityArgs)598        return oirArgs599    def findBitmap(self, screenshot, bitmap, **kwargs):600        """601        Return list of fmbtgti.GUIItems that match to bitmap.602        """603        oirArgs = self.__oirArgs(screenshot, bitmap, **kwargs)604        return self._findBitmap(screenshot, bitmap, **oirArgs)605    def _findBitmap(self, screenshot, bitmap, **kwargs):606        """607        Find appearances of bitmap from the screenshot.608        Parameters:609          screenshot (fmbtgti.Screenshot)610                  Screenshot from which bitmap is to be searched611                  for. Use Screenshot.filename() to get the filename.612          bitmap (string)613                  bitmap to be searched for.614          other arguments (engine specific)615                  kwargs contain keyword arguments given to616                  findBitmap(screenshot, bitmap, ...), already extended617                  first with screenshot-specific findBitmapDefaults, then618                  with engine-specific findBitmapDefaults.619                  _findBitmap *must* define all engine parameters as620                  explicit keyword arguments:621                  def _findBitmap(self, screenshot, bitmap, engArg1=42):622                      ...623        Returns list of fmbtgti.GUIItems.624        """625        raise NotImplementedError("_findBitmap needed but not implemented.")626class _Eye4GraphicsOirEngine(OirEngine):627    """OIR engine parameters that can be used in all628    ...Bitmap() methods (swipeBitmap, tapBitmap, findItemsByBitmap, ...):629      colorMatch (float, optional):630              required color matching accuracy. The default is 1.0631              (exact match). For instance, 0.75 requires that every632              pixel's every RGB component value on the bitmap is at633              least 75 % match with the value of corresponding pixel's634              RGB component in the screenshot.635      opacityLimit (float, optional):636              threshold for comparing pixels with non-zero alpha637              channel. Pixels less opaque than the given threshold are638              skipped in match comparison. The default is 0, that is,639              alpha channel is ignored.640      area ((left, top, right, bottom), optional):641              search bitmap from the given area only. Left, top right642              and bottom are either absolute coordinates (integers) or643              floats in range [0.0, 1.0]. In the latter case they are644              scaled to screenshot dimensions. The default is (0.0,645              0.0, 1.0, 1.0), that is, search everywhere in the646              screenshot.647      limit (integer, optional):648              number of returned matches is limited to the limit. The649              default is -1: all matches are returned. Applicable in650              findItemsByBitmap.651      allowOverlap (boolean, optional):652              allow returned icons to overlap. If False, returned list653              contains only non-overlapping bounding boxes. The654              default is False.655      scale (float or pair of floats, optional):656              scale to be applied to the bitmap before657              matching. Single float is a factor for both X and Y658              axis, pair of floats is (xScale, yScale). The default is659              1.0.660      bitmapPixelSize (integer, optional):661              size of pixel rectangle on bitmap for which there must662              be same color on corresponding screenshot rectangle.  If663              scale is 1.0, default is 1 (rectangle is 1x1). If scale664              != 1.0, the default is 2 (rectangle is 2x2).665      screenshotPixelSize (integer, optional):666              size of pixel rectangle on screenshot in which there667              must be a same color pixel as in the corresponding668              rectangle on bitmap. The default is scale *669              bitmapPixelSize.670    If unsure about parameters, but you have a bitmap that should be671    detected in a screenshot, try obj.oirEngine().adjustParameters().672    Example:673    d.enableVisualLog("params.html")674    screenshot = d.refreshScreenshot()675    results = d.oirEngine().adjustParameters(screenshot, "mybitmap.png")676    if results:677        item, params = results[0]678        print "found %s with parameters:" % (item,)679        print "\n".join(sorted(["  %s = %s" % (k, params[k]) for k in params]))680        print "verify:", d.verifyBitmap("mybitmap.png", **params)681    Notice, that you can force refreshScreenshot to load old screenshot:682    d.refreshScreenshot("old.png")683    """684    def __init__(self, *args, **engineDefaults):685        engineDefaults["colorMatch"] = engineDefaults.get("colorMatch", 1.0)686        engineDefaults["opacityLimit"] = engineDefaults.get("opacityLimit", 0.0)687        engineDefaults["area"] = engineDefaults.get("area", (0.0, 0.0, 1.0, 1.0))688        engineDefaults["limit"] = engineDefaults.get("limit", -1)689        engineDefaults["allowOverlap"] = engineDefaults.get("allowOverlap", False)690        engineDefaults["scale"] = engineDefaults.get("scale", 1.0)691        engineDefaults["bitmapPixelSize"] = engineDefaults.get("bitmapPixelSize", 0)692        engineDefaults["screenshotPixelSize"] = engineDefaults.get("screenshotPixelSize", 0)693        OirEngine.__init__(self, *args, **engineDefaults)694        self._openedImages = {}695        self._findBitmapCache = {}696    def _addScreenshot(self, screenshot, **findBitmapDefaults):697        filename = screenshot.filename()698        self._openedImages[filename] = eye4graphics.openImage(filename)699        # make sure size() is available, this can save an extra700        # opening of the screenshot file.701        if screenshot.size(allowReadingFile=False) == None:702            screenshot.setSize(_e4gImageDimensions(self._openedImages[filename]))703        self._findBitmapCache[filename] = {}704    def _removeScreenshot(self, screenshot):705        filename = screenshot.filename()706        eye4graphics.closeImage(self._openedImages[filename])707        del self._openedImages[filename]708        del self._findBitmapCache[filename]709    def adjustParameters(self, screenshot, bitmap,710                         scaleRange = [p/100.0 for p in range(110,210,10)],711                         colorMatchRange = [p/100.0 for p in range(100,60,-10)],712                         pixelSizeRange = range(2,5),713                         resultCount = 1,714                         **oirArgs):715        """716        Search for scale, colorMatch, bitmapPixelSize and717        screenshotPixelSize parameters that find the bitmap in the718        screenshot.719        Parameters:720          screenshot (Screenshot instance):721                  screenshot that contains the bitmap.722          bitmap (string):723                  bitmap filename.724          scaleRange (list of floats, optional):725                  scales to go through.726                  The default is: 1.1, 1.2, ... 2.0.727          colorMatchRange (list of floats, optional):728                  colorMatches to try out.729                  The default is: 1.0, 0.9, ... 0.7.730          pixelSizeRange (list of integers, optional):731                  values for bitmapPixelSize and screenshotPixelSize.732                  The default is: [2, 3]733          resultCount (integer, optional):734                  number of parameter combinations to be found.735                  The default is 1. 0 is unlimited.736          other OIR parameters: as usual, refer to engine documentation.737        Returns list of pairs: (GUIItem, findParams), where738        GUIItem is the detected item (GUIItem.bbox() is the box around it),739        and findParams is a dictionary containing the parameters.740        """741        if not screenshot.filename() in self._findBitmapCache:742            self.addScreenshot(screenshot)743            ssAdded = True744        else:745            ssAdded = False746        retval = []747        for colorMatch in colorMatchRange:748            for pixelSize in pixelSizeRange:749                for scale in scaleRange:750                    findParams = oirArgs.copy()751                    findParams.update({"colorMatch": colorMatch,752                                       "limit": 1,753                                       "scale": scale,754                                       "bitmapPixelSize": pixelSize,755                                       "screenshotPixelSize": pixelSize})756                    results = self.findBitmap(screenshot, bitmap,757                                               **findParams)758                    if results:759                        retval.append((results[0], findParams))760                        if len(retval) == resultCount:761                            return retval762        if ssAdded:763            self.removeScreenshot(screenshot)764        return retval765    def _findBitmap(self, screenshot, bitmap, colorMatch=None,766                    opacityLimit=None, area=None, limit=None,767                    allowOverlap=None, scale=None,768                    bitmapPixelSize=None, screenshotPixelSize=None):769        """770        Find items on the screenshot that match to bitmap.771        """772        ssFilename = screenshot.filename()773        ssSize = screenshot.size()774        cacheKey = (bitmap, colorMatch, opacityLimit, area, limit,775                    scale, bitmapPixelSize, screenshotPixelSize)776        if cacheKey in self._findBitmapCache[ssFilename]:777            return self._findBitmapCache[ssFilename][cacheKey]778        self._findBitmapCache[ssFilename][cacheKey] = []779        e4gIcon = eye4graphics.openImage(bitmap)780        if e4gIcon == 0:781            raise IOError('Cannot open bitmap "%s".' % (bitmap,))782        matchCount = 0783        leftTopRightBottomZero = (_intCoords((area[0], area[1]), ssSize) +784                                  _intCoords((area[2], area[3]), ssSize) +785                                  (0,))786        struct_area_bbox = _Bbox(*leftTopRightBottomZero)787        struct_bbox = _Bbox(0, 0, 0, 0, 0)788        contOpts = 0 # search for the first hit789        try:790            xscale, yscale = scale791        except TypeError:792            xscale = yscale = float(scale)793        while True:794            if matchCount == limit: break795            result = eye4graphics.findNextIcon(796                ctypes.byref(struct_bbox),797                ctypes.c_void_p(self._openedImages[ssFilename]),798                ctypes.c_void_p(e4gIcon),799                0, # no fuzzy matching800                ctypes.c_double(colorMatch),801                ctypes.c_double(opacityLimit),802                ctypes.byref(struct_area_bbox),803                ctypes.c_int(contOpts),804                ctypes.c_float(xscale),805                ctypes.c_float(yscale),806                ctypes.c_int(bitmapPixelSize),807                ctypes.c_int(screenshotPixelSize))808            contOpts = 1 # search for the next hit809            if result < 0: break810            bbox = (int(struct_bbox.left), int(struct_bbox.top),811                    int(struct_bbox.right), int(struct_bbox.bottom))812            addToFoundItems = True813            if allowOverlap == False:814                for guiItem in self._findBitmapCache[ssFilename][cacheKey]:815                    itemLeft, itemTop, itemRight, itemBottom = guiItem.bbox()816                    if ((itemLeft <= bbox[0] <= itemRight or itemLeft <= bbox[2] <= itemRight) and817                        (itemTop <= bbox[1] <= itemBottom or itemTop <= bbox[3] <= itemBottom)):818                        if ((itemLeft < bbox[0] < itemRight or itemLeft < bbox[2] < itemRight) or819                            (itemTop < bbox[1] < itemBottom or itemTop < bbox[3] < itemBottom)):820                            addToFoundItems = False821                            break822            if addToFoundItems:823                self._findBitmapCache[ssFilename][cacheKey].append(824                    GUIItem("bitmap", bbox, ssFilename, bitmap=bitmap))825                matchCount += 1826        eye4graphics.closeImage(e4gIcon)827        return self._findBitmapCache[ssFilename][cacheKey]828def _defaultOirEngine():829    if _g_defaultOirEngine:830        return _g_defaultOirEngine831    else:832        _Eye4GraphicsOirEngine().register(defaultOir=True)833        return _g_defaultOirEngine834class _OirRc(object):835    """Optical image recognition settings for a directory.836    Currently loaded from file .fmbtoirc in the directory.837    There is once _OirRc instance per directory.838    """839    _filename = ".fmbtoirrc"840    _cache = {}841    @classmethod842    def load(cls, directory):843        if directory in cls._cache:844            pass845        elif os.access(os.path.join(directory, cls._filename), os.R_OK):846            cls._cache[directory] = cls(directory)847        else:848            cls._cache[directory] = None849        return cls._cache[directory]850    def __init__(self, directory):851        self._key2value = {}852        curdir = "."853        self._dir2oirArgsList = {curdir: [{}]}854        for line in file(os.path.join(directory, _OirRc._filename)):855            line = line.strip()856            if line == "" or line[0] in "#;":857                continue858            elif line == "alternative":859                self._dir2oirArgsList[curdir].append({}) # new set of args860                self._key2value = {}861            elif "=" in line:862                key, value_str = line.split("=", 1)863                value_str = value_str.strip()864                if key.strip().lower() == "includedir":865                    curdir = value_str866                    self._dir2oirArgsList[curdir] = [{}]867                else:868                    try: value = int(value_str)869                    except ValueError:870                        try: value = float(value_str)871                        except ValueError:872                            if value_str[0] in "([\"'": # tuple, list, string873                                value = eval(value_str)874                            else:875                                value = value_str876                    self._dir2oirArgsList[curdir][-1][key.strip()] = value877    def searchDirs(self):878        return self._dir2oirArgsList.keys()879    def oirArgsList(self, searchDir):880        return self._dir2oirArgsList[searchDir]881class _Paths(object):882    def __init__(self, bitmapPath, relativeRoot):883        self.bitmapPath = bitmapPath884        self.relativeRoot = relativeRoot885        self._oirAL = {} # OIR parameters for bitmaps886        self._abspath = {} # bitmap to abspath887    def abspath(self, bitmap, checkReadable=True):888        if bitmap in self._abspath:889            return self._abspath[bitmap]890        if bitmap.startswith("/"):891            path = [os.path.dirname(bitmap)]892            bitmap = os.path.basename(bitmap)893        else:894            path = []895            for singleDir in self.bitmapPath.split(":"):896                if not singleDir.startswith("/"):897                    path.append(os.path.join(self.relativeRoot, singleDir))898                else:899                    path.append(singleDir)900        for singleDir in path:901            retval = os.path.join(singleDir, bitmap)902            if not checkReadable or os.access(retval, os.R_OK):903                oirRc = _OirRc.load(singleDir)904                if oirRc:905                    self._oirAL[retval] = oirRc.oirArgsList(".")906                else:907                    self._oirAL[retval] = [{}]908                self._oirAL[bitmap] = self._oirAL[retval]909                break910            else:911                # bitmap is not in singleDir, but there might be .fmbtoirrc912                oirRc = _OirRc.load(singleDir)913                if oirRc:914                    for d in oirRc.searchDirs():915                        if d.startswith("/"):916                            candidate = os.path.join(d, bitmap)917                        else:918                            candidate = os.path.join(singleDir, d, bitmap)919                        if os.access(candidate, os.R_OK):920                            self._oirAL[candidate] = oirRc.oirArgsList(d)921                            self._oirAL[bitmap] = self._oirAL[candidate]922                            retval = candidate923                            break924        if checkReadable and not os.access(retval, os.R_OK):925            raise ValueError('Bitmap "%s" not readable in bitmapPath %s' % (bitmap, ':'.join(path)))926        self._abspath[bitmap] = retval927        return retval928    def oirArgsList(self, bitmap):929        """Returns list of alternative OIR parameters associated to the bitmap930        by appropriate .fmbtoirrc file931        """932        if bitmap in self._oirAL:933            return self._oirAL[bitmap]934        else:935            absBitmap = self.abspath(bitmap)936            if absBitmap in self._oirAL:937                return self._oirAL[absBitmap]938            else:939                return None940class GUITestInterface(object):941    def __init__(self, ocrEngine=None, oirEngine=None, rotateScreenshot=None):942        self._paths = _Paths("", "")943        self._conn = None944        self._lastScreenshot = None945        self._longPressHoldTime = 2.0946        self._longTapHoldTime = 2.0947        self._ocrEngine = None948        self._oirEngine = None949        self._rotateScreenshot = rotateScreenshot950        self._screenshotLimit = None951        self._screenshotRefCount = {} # filename -> Screenshot object ref count952        self._screenshotArchiveMethod = "resize"953        if ocrEngine == None:954            self.setOcrEngine(_defaultOcrEngine())955        else:956            if type(ocrEngine) == int:957                self.setOcrEngine(_g_ocrEngines[ocrEngine])958            else:959                self.setOcrEngine(ocrEngine)960        if oirEngine == None:961            self.setOirEngine(_defaultOirEngine())962        else:963            if type(oirEngine) == int:964                self.setOirEngine(_g_oirEngines[oirEngine])965            else:966                self.setOirEngine(oirEngine)967        self._screenshotDir = None968        self._screenshotDirDefault = "screenshots"969        self._screenshotSubdir = None970        self._screenshotSubdirDefault = ""971        self._screenSize = None972        self._visualLog = None973        self._visualLogFileObj = None974        self._visualLogFilenames = set()975    def bitmapPath(self):976        """977        Returns bitmapPath from which bitmaps are searched for.978        """979        return self._paths.bitmapPath980    def bitmapPathRoot(self):981        """982        Returns the path that prefixes all relative directories in983        bitmapPath.984        """985        return self._paths.relativeRoot986    def close(self):987        self._lastScreenshot = None988        if self._visualLog:989            if hasattr(self._visualLog._outFileObj, "name"):990                self._visualLogFilenames.remove(self._visualLog._outFileObj.name)991            self._visualLog.close()992            if self._visualLogFileObj:993                self._visualLogFileObj.close()994            self._visualLog = None995    def connection(self):996        """997        Returns GUITestConnection instance.998        """999        return self._conn1000    def drag(self, (x1, y1), (x2, y2), delayBetweenMoves=0.01, delayBeforeMoves=0, delayAfterMoves=0, movePoints=20):1001        """1002        Touch the screen on coordinates (x1, y1), drag along straight1003        line to coordinates (x2, y2), and raise fingertip.1004        coordinates (floats in range [0.0, 1.0] or integers):1005                floating point coordinates in range [0.0, 1.0] are1006                scaled to full screen width and height, others are1007                handled as absolute coordinate values.1008        delayBeforeMoves (float, optional):1009                seconds to wait after touching and before dragging.1010                If negative, starting touch event is not sent.1011        delayBetweenMoves (float, optional):1012                seconds to wait when moving between points when1013                dragging.1014        delayAfterMoves (float, optional):1015                seconds to wait after dragging, before raising1016                fingertip.1017                If negative, fingertip is not raised.1018        movePoints (integer, optional):1019                the number of intermediate move points between end1020                points of the line.1021        Returns True on success, False if sending input failed.1022        """1023        x1, y1 = self.intCoords((x1, y1))1024        x2, y2 = self.intCoords((x2, y2))1025        if delayBeforeMoves >= 0:1026            if not self._conn.sendTouchDown(x1, y1):1027                return False1028        if delayBeforeMoves > 0:1029            time.sleep(delayBeforeMoves)1030        else:1031            time.sleep(delayBetweenMoves)1032        for i in xrange(0, movePoints):1033            nx = x1 + int(round(((x2 - x1) / float(movePoints+1)) * (i+1)))1034            ny = y1 + int(round(((y2 - y1) / float(movePoints+1)) * (i+1)))1035            if not self._conn.sendTouchMove(nx, ny): return False1036            time.sleep(delayBetweenMoves)1037        if delayAfterMoves > 0:1038            self._conn.sendTouchMove(x2, y2)1039            time.sleep(delayAfterMoves)1040        if delayAfterMoves >= 0:1041            if self._conn.sendTouchUp(x2, y2):1042                return True1043            else:1044                return False1045        else:1046            return True1047    def enableVisualLog(self, filenameOrObj,1048                        screenshotWidth="240", thumbnailWidth="",1049                        timeFormat="%s.%f", delayedDrawing=False,1050                        copyBitmapsToScreenshotDir=False):1051        """1052        Start writing visual HTML log on this device object.1053        Parameters:1054          filenameOrObj (string or a file object)1055                  The file to which the log is written.1056          screenshotWidth (string, optional)1057                  Width of screenshot images in HTML.1058                  The default is "240".1059          thumbnailWidth (string, optional)1060                  Width of thumbnail images in HTML.1061                  The default is "", that is, original size.1062          timeFormat (string, optional)1063                  Timestamp format. The default is "%s.%f".1064                  Refer to strftime documentation.1065          delayedDrawing (boolean, optional)1066                  If True, screenshots with highlighted icons, words1067                  and gestures are not created during the1068                  test. Instead, only shell commands are stored for1069                  later execution. The value True can significantly1070                  save test execution time and disk space. The default1071                  is False.1072          copyBitmapsToScreenshotDir (boolean, optional)1073                  If True, every logged bitmap file will be copied to1074                  bitmaps directory in screenshotDir. The default is1075                  False.1076        """1077        if type(filenameOrObj) == str:1078            try:1079                outFileObj = file(filenameOrObj, "w")1080                self._visualLogFileObj = outFileObj1081            except Exception, e:1082                _fmbtLog('Failed to open file "%s" for logging.' % (filenameOrObj,))1083                raise1084        else:1085            outFileObj = filenameOrObj1086            # someone else opened the file => someone else will close it1087            self._visualLogFileObj = None1088        if hasattr(outFileObj, "name"):1089            if outFileObj.name in self._visualLogFilenames:1090                raise ValueError('Visual logging on file "%s" is already enabled' % (outFileObj.name,))1091            else:1092                self._visualLogFilenames.add(outFileObj.name)1093        self._visualLog = _VisualLog(self, outFileObj, screenshotWidth,1094                                     thumbnailWidth, timeFormat, delayedDrawing,1095                                     copyBitmapsToScreenshotDir)1096    def visualLog(self, *args):1097        """Writes parameters to the visual log, given that visual logging is1098        enabled.1099        """1100        pass1101    def intCoords(self, (x, y)):1102        """1103        Convert floating point coordinate values in range [0.0, 1.0] to1104        screen coordinates.1105        """1106        width, height = self.screenSize()1107        return _intCoords((x, y), (width, height))1108    def ocrEngine(self):1109        """1110        Returns the OCR engine that is used by default for new1111        screenshots.1112        """1113        return self._ocrEngine1114    def oirEngine(self):1115        """1116        Returns the OIR engine that is used by default for new1117        screenshots.1118        """1119        return self._oirEngine1120    def pressKey(self, keyName, long=False, hold=0.0):1121        """1122        Press a key.1123        Parameters:1124          keyName (string):1125                  the name of the key, like KEYCODE_HOME.1126          long (boolean, optional):1127                  if True, press the key for long time.1128          hold (float, optional):1129                  time in seconds to hold the key down.1130        """1131        if long and hold == 0.0:1132            hold = self._longPressHoldTime1133        if hold > 0.0:1134            try:1135                assert self._conn.sendKeyDown(keyName)1136                time.sleep(hold)1137                assert self._conn.sendKeyUp(keyName)1138            except AssertionError:1139                return False1140            return True1141        return self._conn.sendPress(keyName)1142    def _newScreenshotFilepath(self):1143        """1144        Returns path and filename for next screenshot file.1145        Makes sure the file can be written (necessary directory1146        structure exists).1147        """1148        t = datetime.datetime.now()1149        filename = _filenameTimestamp(t) + "-" + self._conn.target() + ".png"1150        filepath = os.path.join(self.screenshotDir(),1151                                t.strftime(self.screenshotSubdir()),1152                                filename)1153        necessaryDirs = os.path.dirname(filepath)1154        if necessaryDirs and not os.path.isdir(necessaryDirs):1155            try:1156                os.makedirs(necessaryDirs)1157            except Exception, e:1158                _fmbtLog('creating directory "%s" for screenshots failed: %s' %1159                         (necessaryDirs, e))1160                raise1161        return filepath1162    def _archiveScreenshot(self, filepath):1163        if self._screenshotArchiveMethod == "remove":...fmbtandroid.py
Source:fmbtandroid.py  
...846        self._lineRegEx = re.compile("(?P<indent>\s*)(?P<class>[\w.$]+)@(?P<id>[0-9A-Fa-f]{8} )(?P<properties>.*)")847        self._olderAndroidLineRegEx = re.compile("(?P<indent>\s*)(?P<class>[\w.$]+)@(?P<id>\w)(?P<properties>.*)")848        self._propRegEx = re.compile("(?P<prop>(?P<name>[^=]+)=(?P<len>\d+),)(?P<data>[^\s]* ?)")849        self._dump = dump850        self._rawDumpFilename = self.screenshotDir + os.sep + fmbtgti._filenameTimestamp() + "-" + self.serialNumber + ".view"851        file(self._rawDumpFilename, "w").write(self._dump)852        if displayToScreen == None:853            displayToScreen = lambda x, y: (x, y)854        try: self._parseDump(dump, self._rawDumpFilename, displayToScreen)855        except Exception, e:856            self._errors.append((-1, "", "Parser error"))857    def viewItems(self): return self._viewItems858    def errors(self): return self._errors859    def dumpRaw(self): return self._dump860    def dumpItems(self, itemList = None):861        if itemList == None: itemList = self._viewItems862        l = []863        for i in itemList:864            l.append(self._dumpItem(i))...Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!
