Best Python code snippet using fMBT_python
fmbtgti.py
Source:fmbtgti.py  
...154        os.access(srcFile, os.R_OK) and155        os.stat(srcFile).st_mtime < os.stat(dstFile).st_mtime):156        return # cached file is up-to-date157    subprocess.call([fmbt_config.imagemagick_convert, srcFile] + convertArgs + [dstFile])158def _ppFilename(origFilename, preprocess):159    return origFilename + ".fmbtoir.cache." + re.sub("[^a-zA-Z0-9.]", "", preprocess) + ".png"160def _intCoords((x, y), (width, height)):161    if 0 <= x <= 1 and type(x) == float: x = x * width162    if 0 <= y <= 1 and type(y) == float: y = y * height163    return (int(round(x)), int(round(y)))164def _boxOnRegion((x1, y1, x2, y2), (minX, minY, maxX, maxY), partial=True):165    if partial:166        return (x1 < x2 and ((minX <= x1 <= maxX) or (minX <= x2 <= maxX)) and167                y1 < y2 and ((minY <= y1 <= maxY) or (minY <= y2 <= maxY)))168    else:169        return (x1 < x2 and ((minX <= x1 <= maxX) and (minX <= x2 <= maxX)) and170                y1 < y2 and ((minY <= y1 <= maxY) and (minY <= y2 <= maxY)))171def _edgeDistanceInDirection((x, y), (width, height), direction):172    x, y = _intCoords((x, y), (width, height))173    direction = direction % 360 # -90 => 270, 765 => 45174    dirRad = math.radians(direction)175    if 0 < direction < 180:176        distTopBottom = y / math.sin(dirRad)177    elif 180 < direction < 360:178        distTopBottom = -(height - y) / math.sin(dirRad)179    else:180        distTopBottom = float('inf')181    if 90 < direction < 270:182        distLeftRight = -x / math.cos(dirRad)183    elif 270 < direction <= 360 or 0 <= direction < 90:184        distLeftRight = (width - x) / math.cos(dirRad)185    else:186        distLeftRight = float('inf')187    return min(distTopBottom, distLeftRight)188### Binding to eye4graphics C-library189class _Bbox(ctypes.Structure):190    _fields_ = [("left", ctypes.c_int32),191                ("top", ctypes.c_int32),192                ("right", ctypes.c_int32),193                ("bottom", ctypes.c_int32),194                ("error", ctypes.c_int32)]195class _Rgb888(ctypes.Structure):196    _fields_ = [("red", ctypes.c_uint8),197                ("green", ctypes.c_uint8),198                ("blue", ctypes.c_uint8)]199_libpath = ["", ".",200            os.path.dirname(os.path.abspath(__file__)),201            distutils.sysconfig.get_python_lib(plat_specific=1)]202_suffix = ".so"203if os.name == "nt":204    _suffix = ".dll"205for _dirname in _libpath:206    try:207        eye4graphics = ctypes.CDLL(os.path.join(_dirname , "eye4graphics"+_suffix))208        struct_bbox = _Bbox(0, 0, 0, 0, 0)209        eye4graphics.findNextColor.restype = ctypes.c_int210        eye4graphics.findNextHighErrorBlock.argtypes = [211            ctypes.c_void_p,212            ctypes.c_void_p,213            ctypes.c_int,214            ctypes.c_int,215            ctypes.c_double,216            ctypes.c_void_p]217        eye4graphics.findNextDiff.restype = ctypes.c_int218        eye4graphics.findNextDiff.argtypes = [219            ctypes.c_void_p,220            ctypes.c_void_p,221            ctypes.c_void_p,222            ctypes.c_double,223            ctypes.c_double,224            ctypes.c_void_p,225            ctypes.c_void_p,226            ctypes.c_int]227        eye4graphics.openImage.argtypes = [ctypes.c_char_p]228        eye4graphics.openImage.restype = ctypes.c_void_p229        eye4graphics.openedImageDimensions.argtypes = [ctypes.c_void_p, ctypes.c_void_p]230        eye4graphics.closeImage.argtypes = [ctypes.c_void_p]231        eye4graphics.rgb5652rgb.restype = ctypes.c_int232        eye4graphics.rgb5652rgb.argtypes = [233            ctypes.c_void_p,234            ctypes.c_int,235            ctypes.c_int,236            ctypes.c_void_p]237        break238    except: pass239else:240    raise ImportError("%s cannot load eye4graphics%s" % (__file__, _suffix))241def _e4gOpenImage(filename):242    image = eye4graphics.openImage(filename)243    if not image:244        raise IOError('Cannot open image "%s"' % (filename,))245    else:246        return image247def _e4gImageDimensions(e4gImage):248    struct_bbox = _Bbox(0, 0, 0, 0, 0)249    eye4graphics.openedImageDimensions(ctypes.byref(struct_bbox), e4gImage)250    return (struct_bbox.right, struct_bbox.bottom)251def _e4gImageIsBlank(filename):252    e4gImage = _e4gOpenImage(filename)253    rv = (eye4graphics.openedImageIsBlank(e4gImage) == 1)254    eye4graphics.closeImage(e4gImage)255    return rv256### end of binding to eye4graphics.so257def sortItems(items, criteria):258    """259    Returns GUIItems sorted according to given criteria260    Parameters:261      items (list of GUIItems):262              items to be sorted263      criteria (string):264              Supported values:265              "topleft" - sort by top left coordinates of items266              "area" - sort by areas of items267    """268    if criteria == "topleft":269        top_left_items = [(i.bbox()[1], i.bbox()[0], i) for i in items]270        top_left_items.sort()271        return [tli[2] for tli in top_left_items]272    elif criteria == "area":273        area_items = [274            ((i.bbox()[2] - i.bbox()[0]) * (i.bbox()[3] - i.bbox()[1]), i)275            for i in items]276        area_items.sort()277        return [ai[1] for ai in area_items]278    else:279        raise ValueError('invalid sort criteria "%s"' % (criteria,))280class GUITestConnection(object):281    """282    Implements GUI testing primitives needed by GUITestInterface.283    All send* and recv* methods return284    - True on success285    - False on user error (unknown keyName, coordinates out of range)286    - raise Exception on framework error (connection lost, missing287      dependencies).288    """289    def sendPress(self, keyName):290        return self.sendKeyDown(keyName) and self.sendKeyUp(keyName)291    def sendKeyDown(self, keyName):292        raise NotImplementedError('sendKeyDown("%s") needed but not implemented.' % (keyName,))293    def sendKeyUp(self, keyName):294        raise NotImplementedError('sendKeyUp("%s") needed but not implemented.' % (keyName,))295    def sendTap(self, x, y):296        return self.sendTouchDown(x, y) and self.sendTouchUp(x, y)297    def sendTouchDown(self, x, y):298        raise NotImplementedError('sendTouchDown(%d, %d) needed but not implemented.' % (x, y))299    def sendTouchMove(self, x, y):300        raise NotImplementedError('sendTouchMove(%d, %d) needed but not implemented.' % (x, y))301    def sendTouchUp(self, x, y):302        raise NotImplementedError('sendTouchUp(%d, %d) needed but not implemented.' % (x, y))303    def sendType(self, text):304        raise NotImplementedError('sendType("%s") needed but not implemented.' % (text,))305    def recvScreenshot(self, filename):306        """307        Saves screenshot from the GUI under test to given filename.308        """309        raise NotImplementedError('recvScreenshot("%s") needed but not implemented.' % (filename,))310    def recvScreenUpdated(self, waitTime, pollDelay):311        """312        Wait until the screen has been updated, but no longer than the313        timeout (waitTime). Return True if the screen was updated314        before the timeout, otherwise False.315        Implementing this method is optional. If not implemented, the316        method returns None, and an inefficient recvScreenshot-based317        implementation is used instead from fmbtgti. pollDelay can be318        ignored if more efficient solutions are available319        (update-event based triggering, for instance).320        """321        return None322    def target(self):323        """324        Returns a string that is unique to each test target. For325        instance, Android device serial number.326        """327        return "GUITestConnectionTarget"328class SimulatedGUITestConnection(GUITestConnection):329    """330    Simulates GUITestConnection: records method calls and fakes screenshots331    All send* methods return True. recvScreenshot returns always True332    if non-empty list of fake screenshot filenames is given (see333    constructor and setScreenshotFilenames). Otherwise it returns334    False.335    """336    def __init__(self, screenshotFilenames=()):337        """338        Parameters:339          screenshotFilenames (tuple of filenames):340                  calling recvScreenshot uses next item in this tuple as341                  the observed screenshot.342        """343        GUITestConnection.__init__(self)344        self.setScreenshotFilenames(screenshotFilenames)345        self._calls = []346        for recordedMethod in ("sendPress", "sendKeyDown", "sendKeyUp",347                               "sendTap", "sendTouchDown", "sendTouchMove",348                               "sendTouchUp", "sendType"):349            self.__dict__[recordedMethod] = self._recorder(recordedMethod)350    def _recorder(self, method):351        return lambda *args, **kwargs: self._calls.append(352            (time.time(), method, args, kwargs)) or True353    def history(self):354        return self._calls355    def clearHistory(self):356        self._calls = []357    def setScreenshotFilenames(self, screenshotFilenames):358        self._screenshotFilenames = screenshotFilenames359        self._nextScreenshotFilename = 0360    def recvScreenshot(self, filename):361        self._calls.append((time.time(), "recvScreenshot", (filename,), {}))362        if self._screenshotFilenames:363            if self._nextScreenshotFilename >= len(self._screenshotFilenames):364                self._nextScreenshotFilename = 0365            fakeFilename = self._screenshotFilenames[self._nextScreenshotFilename]366            self._nextScreenshotFilename += 1367            if not os.access(fakeFilename, os.R_OK):368                raise IOError('screenshot file not found: "%s"' % (fakeFilename,))369            shutil.copy(fakeFilename, filename)370            return True371        else:372            return False373    def target(self):374        return "SimulatedGUITestConnection"375class OrEngine(object):376    """377    Optical recognition engine. Base class for OCR and OIR engines,378    enables registering engine instances.379    """380    def __init__(self, *args, **kwargs):381        pass382    def register(self, defaultOcr=False, defaultOir=False):383        """384        Register this engine instance to the list of OCR and/or OIR385        engines.386        Parameters:387          defaultOcr (optional, boolean):388                  if True, use this OCR engine by default in all new389                  GUITestInterface instances. The default is False.390          defaultOir (optional, boolean):391                  if True, use this OIR engine by default in all new392                  GUITestInterface instances. The default is False.393        Returns the index with which the engine was registered to the394        list of OCR or OIR engines. If this instance implements both395        OCR and OIR engines, returns pair (OCR index, OIR index).396        """397        # Allow a single engine implement both OCR and OIR engine398        # interfaces. Therefore, it must be possible to call399        # e.register(defaultOcr=True, defaultOir=True).400        #401        global _g_defaultOcrEngine, _g_defaultOirEngine402        global _g_ocrEngines, _g_oirEngines403        engineIndexes = []404        if isinstance(self, OcrEngine):405            if not self in _g_ocrEngines:406                _g_ocrEngines.append(self)407            engineIndexes.append(_g_ocrEngines.index(self))408            if defaultOcr:409                _g_defaultOcrEngine = self410        if isinstance(self, OirEngine):411            if not self in _g_oirEngines:412                _g_oirEngines.append(self)413            engineIndexes.append(_g_oirEngines.index(self))414            if defaultOir:415                _g_defaultOirEngine = self416        if len(engineIndexes) == 1:417            return engineIndexes[0]418        else:419            return engineIndexes420class OcrEngine(OrEngine):421    """422    This is an abstract interface for OCR engines that can be plugged423    into fmbtgti.GUITestInterface instances and Screenshots.424    To implement an OCR engine, you need to override _findText() at425    minimum. See _findText documentation in this class for426    requirements.427    If possible in your OCR engine, you can provide _dumpOcr() to428    reveal what is recognized in screenshots.429    For efficient caching of results and freeing cached results, you430    can override _addScreenshot() and _removeScreenshot(). Every431    screenshot is added before findText() or dumpOcr().432    A typical usage of OcrEngine instance:433    - oe.addScreenshot(ss)434    - oe.findText(ss, text1, <engine/screenshot/find-specific-args>)435    - oe.findText(ss, text2, <engine/screenshot/find-specific-args>)436    - oe.removeScreenshot(ss)437    Note that there may be several screenshots added before they are438    removed.439    """440    def __init__(self, *args, **kwargs):441        super(OcrEngine, self).__init__(*args, **kwargs)442        self._ssFindTextDefaults = {}443        self._findTextDefaults = {}444        ocrFindArgs, _ = _takeOcrArgs(self, kwargs)445        self._setFindTextDefaults(ocrFindArgs)446    def dumpOcr(self, screenshot, **kwargs):447        """448        Returns what is recognized in the screenshot. For debugging449        purposes.450        """451        ocrArgs = self.__ocrArgs(screenshot, **kwargs)452        return self._dumpOcr(screenshot, **ocrArgs)453    def _dumpOcr(self, screenshot, **kwargs):454        return None455    def addScreenshot(self, screenshot, **findTextDefaults):456        """457        Prepare for finding text from the screenshot.458        Parameters:459          screenshot (fmbtgti.Screenshot)460                  screenshot object to be searched from.461          other parameters (optional)462                  findText defaults for this screenshot.463        Notice that there may be many screenshots simultaneously.464        Do not keep reference to the screenshot object.465        """466        self.setScreenshotFindTextDefaults(screenshot, **findTextDefaults)467        return self._addScreenshot(screenshot, **findTextDefaults)468    def _addScreenshot(self, screenshot, **findTextDefaults):469        pass470    def removeScreenshot(self, screenshot):471        """472        OCR queries on the screenshot will not be made anymore.473        """474        self._removeScreenshot(screenshot)475        try:476            del self._ssFindTextDefaults[id(screenshot)]477        except KeyError:478            raise KeyError('screenshot "%s" does not have findTextDefaults. '479                           'If OcrEngine.addScreenshot() is overridden, it '480                           '*must* call parent\'s addScreenshot.' % (screenshot.filename(),))481    def _removeScreenshot(self, screenshot):482        pass483    def setFindTextDefaults(self, **findTextDefaults):484        return self._setFindTextDefaults(findTextDefaults, screenshot=None)485    def setScreenshotFindTextDefaults(self, screenshot, **findTextDefaults):486        return self._setFindTextDefaults(findTextDefaults, screenshot=screenshot)487    def _setFindTextDefaults(self, defaults, screenshot=None):488        """489        Set default values for optional arguments for findText().490        Parameters:491          defaults (dictionary)492                  Default keyword arguments and their values.493          screenshot (optional, fmbtgti.Screenshot instance)494                  Use the defaults for findText on this screenshot. If495                  the defaults are None, make them default for all496                  screenshots. Screenshot-specific defaults override497                  engine default.498        """499        if screenshot == None:500            self._findTextDefaults.update(defaults)501        else:502            ssid = id(screenshot)503            if not ssid in self._ssFindTextDefaults:504                self._ssFindTextDefaults[ssid] = self._findTextDefaults.copy()505            self._ssFindTextDefaults[ssid].update(defaults)506    def findTextDefaults(self, screenshot=None):507        if screenshot == None:508            return self._findTextDefaults509        elif id(screenshot) in self._ssFindTextDefaults:510            return self._ssFindTextDefaults[id(screenshot)]511        else:512            return None513    def _findTextArgNames(self):514        """515        Returns names of optional findText arguments.516        """517        return inspect.getargspec(self._findText).args[3:]518    def __ocrArgs(self, screenshot, **priorityArgs):519        ocrArgs = {}520        ocrArgs.update(self._findTextDefaults)521        ssId = id(screenshot)522        if ssId in self._ssFindTextDefaults:523            ocrArgs.update(self._ssFindTextDefaults[ssId])524        ocrArgs.update(priorityArgs)525        return ocrArgs526    def findText(self, screenshot, text, **kwargs):527        """528        Return list of fmbtgti.GUIItems that match to text.529        """530        ocrArgs = self.__ocrArgs(screenshot, **kwargs)531        return self._findText(screenshot, text, **ocrArgs)532    def _findText(self, screenshot, text, **kwargs):533        """534        Find appearances of text from the screenshot.535        Parameters:536          screenshot (fmbtgti.Screenshot)537                  Screenshot from which text is to be searched538                  for. Use Screenshot.filename() to get the filename.539          text (string)540                  text to be searched for.541          other arguments (engine specific)542                  kwargs contain keyword arguments given to543                  findText(screenshot, text, ...), already extended544                  first with screenshot-specific findTextDefaults, then545                  with engine-specific findTextDefaults.546                  _findText *must* define all engine parameters as547                  explicit keyword arguments:548                  def _findText(self, screenshot, text, engArg1=42):549                      ...550        Return list of fmbtgti.GUIItems.551        """552        raise NotImplementedError("_findText needed but not implemented.")553class _EyenfingerOcrEngine(OcrEngine):554    """555    OCR engine parameters that can be used in all556    ...OcrText() methods (swipeOcrText, tapOcrText, findItemsByOcrText, ...):557      match (float, optional):558              minimum match score in range [0.0, 1.0].  The default is559              1.0 (exact match).560      area ((left, top, right, bottom), optional):561              search from the given area only. Left, top, right and562              bottom are either absolute coordinates (integers) or563              floats in range [0.0, 1.0]. In the latter case they are564              scaled to screenshot dimensions. The default is (0.0,565              0.0, 1.0, 1.0), that is, search everywhere in the566              screenshot.567      lang (string, optional):568              pass given language option to Tesseract. See supported569              LANGUAGES (-l) in Tesseract documentation. The default570              is "eng" (English).571      pagesegmodes (list of integers, optional):572              try all integers as tesseract -pagesegmode573              arguments. The default is [3], another good option could574              be [3, 6].575      preprocess (string, optional):576              preprocess filter to be used in OCR for better577              result. Refer to eyenfinger.autoconfigure to search for578              a good one, or try with ImageMagick's convert:579              $ convert screenshot.png <preprocess> screenshot-pp.png580              $ tesseract screenshot-pp.png stdout581      configfile (string, optional):582              Tesseract configuration file.583    Example: limit recognized characters to hexadecimals by creating file584    "hexchars" with content585        tessedit_char_whitelist 0123456789abcdefABCDEF586    To use this file in a single run, pass it to any Ocr method:587        dut.verifyOcrText("DEADBEEF", configfile="hexchars")588    or to use it on every Ocr method, set it as a default:589        dut.ocrEngine().setFindTextDefaults(configfile="hexchars")590    """591    class _OcrResults(object):592        __slots__ = ("filename", "screenSize", "pagesegmodes", "preprocess", "area", "words", "lang", "configfile")593        def __init__(self, filename, screenSize):594            self.filename = filename595            self.screenSize = screenSize596            self.pagesegmodes = None597            self.preprocess = None598            self.area = None599            self.words = None600            self.lang = None601            self.configfile = None602    def __init__(self, *args, **engineDefaults):603        engineDefaults["area"] = engineDefaults.get("area", (0.0, 0.0, 1.0, 1.0))604        engineDefaults["lang"] = engineDefaults.get("lang", "eng")605        engineDefaults["match"] = engineDefaults.get("match", 1.0)606        engineDefaults["pagesegmodes"] = engineDefaults.get("pagesegmodes", _OCRPAGESEGMODES)607        engineDefaults["preprocess"] = engineDefaults.get("preprocess", _OCRPREPROCESS)608        engineDefaults["configfile"] = engineDefaults.get("configfile", None)609        super(_EyenfingerOcrEngine, self).__init__(*args, **engineDefaults)610        self._ss = {} # OCR results for screenshots611    def _addScreenshot(self, screenshot, **findTextDefaults):612        ssId = id(screenshot)613        self._ss[ssId] = _EyenfingerOcrEngine._OcrResults(screenshot.filename(), screenshot.size())614    def _removeScreenshot(self, screenshot):615        ssId = id(screenshot)616        if ssId in self._ss:617            del self._ss[ssId]618    def _findText(self, screenshot, text, match=None, preprocess=None, area=None, pagesegmodes=None, lang=None, configfile=None):619        ssId = id(screenshot)620        self._assumeOcrResults(screenshot, preprocess, area, pagesegmodes, lang, configfile)621        for ppfilter in self._ss[ssId].words.keys():622            try:623                score_text_bbox_list = eyenfinger.findText(624                    text, self._ss[ssId].words[ppfilter], match=match)625                if not score_text_bbox_list:626                    continue627                else:628                    break629            except eyenfinger.BadMatch:630                continue631        else:632            return []633        retval = [GUIItem("OCR text (match %.2f)" % (score,),634                          bbox, self._ss[ssId].filename,635                          ocrFind=text, ocrFound=matching_text)636                  for score, matching_text, bbox in score_text_bbox_list]637        return retval638    def _dumpOcr(self, screenshot, match=None, preprocess=None, area=None, pagesegmodes=None, lang=None, configfile=None):639        ssId = id(screenshot)640        self._assumeOcrResults(screenshot, preprocess, area, pagesegmodes, lang, configfile)641        w = []642        for ppfilter in self._ss[ssId].preprocess:643            for word in self._ss[ssId].words[ppfilter]:644                for appearance, (wid, middle, bbox) in enumerate(self._ss[ssId].words[ppfilter][word]):645                    (x1, y1, x2, y2) = bbox646                    w.append((word, (x1, y1, x2, y2)))647        return sorted(set(w), key=lambda i:(i[1][1]/8, i[1][0]))648    def _assumeOcrResults(self, screenshot, preprocess, area, pagesegmodes, lang, configfile):649        ssId = id(screenshot)650        if not type(preprocess) in (list, tuple):651            preprocess = [preprocess]652        if (self._ss[ssId].words == None653            or self._ss[ssId].preprocess != preprocess654            or self._ss[ssId].area != area655            or self._ss[ssId].lang != lang656            or self._ss[ssId].configfile != configfile):657            self._ss[ssId].words = {}658            self._ss[ssId].preprocess = preprocess659            self._ss[ssId].area = area660            self._ss[ssId].lang = lang661            self._ss[ssId].configfile = configfile662            for ppfilter in preprocess:663                pp = ppfilter % { "zoom": "-resize %sx" % (self._ss[ssId].screenSize[0] * 2) }664                try:665                    eyenfinger.iRead(source=self._ss[ssId].filename, ocr=True, preprocess=pp, ocrArea=area, ocrPageSegModes=pagesegmodes, lang=lang, configfile=configfile)666                except Exception:667                    self._ss[ssId].words = None668                    raise669                self._ss[ssId].words[ppfilter] = eyenfinger._g_words670def _defaultOcrEngine():671    if _g_defaultOcrEngine:672        return _g_defaultOcrEngine673    else:674        _EyenfingerOcrEngine().register(defaultOcr=True)675        return _g_defaultOcrEngine676class OirEngine(OrEngine):677    """678    This is an abstract interface for OIR (optical image recognition)679    engines that can be plugged into fmbtgti.GUITestInterface680    instances and Screenshots.681    To implement an OIR engine, you need to override _findBitmap() at682    minimum. See _findBitmap documentation in this class for683    requirements.684    This base class provides full set of OIR parameters to685    _findBitmap. The parameters are combined from686    - OirEngine find defaults, specified when OirEngine is687      instantiated.688    - Screenshot instance find defaults.689    - bitmap / bitmap directory find defaults (read from the690      .fmbtoirrc that is in the same directory as the bitmap).691    - ...Bitmap() method parameters.692    The latter in the list override the former.693    For efficient caching of results and freeing cached results, you694    can override _addScreenshot() and _removeScreenshot(). Every695    screenshot is added before findBitmap().696    A typical usage of OirEngine instance:697    - oe.addScreenshot(ss)698    - oe.findBitmap(ss, bmpFilename1, <engine/screenshot/find-specific-args>)699    - oe.findBitmap(ss, bmpFilename2, <engine/screenshot/find-specific-args>)700    - oe.removeScreenshot(ss)701    Note that there may be several screenshots added before they are702    removed. ss is a Screenshot instance. Do not keep references to703    Screenshot intances, otherwise garbage collector will not remove704    them.705    """706    def __init__(self, *args, **kwargs):707        super(OirEngine, self).__init__(*args, **kwargs)708        self._ssFindBitmapDefaults = {}709        self._findBitmapDefaults = {}710        oirArgs, _ = _takeOirArgs(self, kwargs)711        self._setFindBitmapDefaults(oirArgs)712    def addScreenshot(self, screenshot, **findBitmapDefaults):713        """714        Prepare for finding bitmap from the screenshot.715        Parameters:716          screenshot (fmbtgti.Screenshot)717                  screenshot object to be searched from.718          other parameters (optional)719                  findBitmap defaults for this screenshot.720        Notice that there may be many screenshots simultaneously.721        Do not keep reference to the screenshot object.722        """723        self.setScreenshotFindBitmapDefaults(screenshot, **findBitmapDefaults)724        return self._addScreenshot(screenshot, **findBitmapDefaults)725    def _addScreenshot(self, screenshot, **findBitmapDefaults):726        pass727    def removeScreenshot(self, screenshot):728        """729        OIR queries on the screenshot will not be made anymore.730        """731        self._removeScreenshot(screenshot)732        try:733            del self._ssFindBitmapDefaults[id(screenshot)]734        except KeyError:735            raise KeyError('screenshot "%s" does not have findBitmapDefaults. '736                           'If OirEngine.addScreenshot() is overridden, it '737                           '*must* call parent\'s addScreenshot.' % (screenshot.filename(),))738    def _removeScreenshot(self, screenshot):739        pass740    def setFindBitmapDefaults(self, **findBitmapDefaults):741        return self._setFindBitmapDefaults(findBitmapDefaults, screenshot=None)742    def setScreenshotFindBitmapDefaults(self, screenshot, **findBitmapDefaults):743        return self._setFindBitmapDefaults(findBitmapDefaults, screenshot=screenshot)744    def _setFindBitmapDefaults(self, defaults, screenshot=None):745        """746        Set default values for optional arguments for findBitmap().747        Parameters:748          defaults (dictionary)749                  Default keyword arguments and their values.750          screenshot (optional, fmbtgti.Screenshot instance)751                  Use the defaults for findBitmap on this screenshot. If752                  the defaults are None, make them default for all753                  screenshots. Screenshot-specific defaults override754                  engine default.755        """756        if screenshot == None:757            self._findBitmapDefaults.update(defaults)758        else:759            ssid = id(screenshot)760            if not ssid in self._ssFindBitmapDefaults:761                self._ssFindBitmapDefaults[ssid] = self._findBitmapDefaults.copy()762            self._ssFindBitmapDefaults[ssid].update(defaults)763    def findBitmapDefaults(self, screenshot=None):764        if screenshot == None:765            return self._findBitmapDefaults766        elif id(screenshot) in self._ssFindBitmapDefaults:767            return self._ssFindBitmapDefaults[id(screenshot)]768        else:769            return None770    def _findBitmapArgNames(self):771        """772        Returns names of optional findBitmap arguments.773        """774        return inspect.getargspec(self._findBitmap).args[3:]775    def __oirArgs(self, screenshot, bitmap, **priorityArgs):776        oirArgs = {}777        oirArgs.update(self._findBitmapDefaults)778        ssId = id(screenshot)779        if ssId in self._ssFindBitmapDefaults:780            oirArgs.update(self._ssFindBitmapDefaults[ssId])781        oirArgs.update(priorityArgs)782        return oirArgs783    def findBitmap(self, screenshot, bitmap, **kwargs):784        """785        Return list of fmbtgti.GUIItems that match to bitmap.786        """787        oirArgs = self.__oirArgs(screenshot, bitmap, **kwargs)788        bitmapLocsFilename = bitmap + _g_forcedLocExt789        if os.access(bitmapLocsFilename, os.R_OK):790            # Use hardcoded bitmap locations file instead of real OIR791            # bitmap.png.locs file format:792            # [(x11, y11, x12, y12), ..., (xn1, yn1, xn2, yn2)]793            try:794                bboxList = eval(file(bitmapLocsFilename).read().strip())795                foundItems = []796                for (left, top, right, bottom) in bboxList:797                    x1, y1 = _intCoords((left, top), screenshot.size())798                    x2, y2 = _intCoords((right, bottom), screenshot.size())799                    foundItems.append(800                        GUIItem("bitmap location", (x1, y1, x2, y2),801                                screenshot.filename(), bitmap=bitmapLocsFilename))802                return foundItems803            except Exception, e:804                raise ValueError('Error reading bounding box list from %s: %s' %805                                 repr(bitmapLocsFilename), e)806        return self._findBitmap(screenshot, bitmap, **oirArgs)807    def _findBitmap(self, screenshot, bitmap, **kwargs):808        """809        Find appearances of bitmap from the screenshot.810        Parameters:811          screenshot (fmbtgti.Screenshot)812                  Screenshot from which bitmap is to be searched813                  for. Use Screenshot.filename() to get the filename.814          bitmap (string)815                  bitmap to be searched for.816          other arguments (engine specific)817                  kwargs contain keyword arguments given to818                  findBitmap(screenshot, bitmap, ...), already extended819                  first with screenshot-specific findBitmapDefaults, then820                  with engine-specific findBitmapDefaults.821                  _findBitmap *must* define all engine parameters as822                  explicit keyword arguments:823                  def _findBitmap(self, screenshot, bitmap, engArg1=42):824                      ...825        Returns list of fmbtgti.GUIItems.826        """827        raise NotImplementedError("_findBitmap needed but not implemented.")828class _Eye4GraphicsOirEngine(OirEngine):829    """OIR engine parameters that can be used in all830    ...Bitmap() methods (swipeBitmap, tapBitmap, findItemsByBitmap, ...):831      colorMatch (float, optional):832              required color matching accuracy. The default is 1.0833              (exact match). For instance, 0.75 requires that every834              pixel's every RGB component value on the bitmap is at835              least 75 % match with the value of corresponding pixel's836              RGB component in the screenshot.837      opacityLimit (float, optional):838              threshold for comparing pixels with non-zero alpha839              channel. Pixels less opaque than the given threshold are840              skipped in match comparison. The default is 0, that is,841              alpha channel is ignored.842      area ((left, top, right, bottom), optional):843              search bitmap from the given area only. Left, top right844              and bottom are either absolute coordinates (integers) or845              floats in range [0.0, 1.0]. In the latter case they are846              scaled to screenshot dimensions. The default is (0.0,847              0.0, 1.0, 1.0), that is, search everywhere in the848              screenshot.849      limit (integer, optional):850              number of returned matches is limited to the limit. The851              default is -1: all matches are returned. Applicable in852              findItemsByBitmap.853      allowOverlap (boolean, optional):854              allow returned icons to overlap. If False, returned list855              contains only non-overlapping bounding boxes. The856              default is False.857      scale (float or pair of floats, optional):858              scale to be applied to the bitmap before859              matching. Single float is a factor for both X and Y860              axis, pair of floats is (xScale, yScale). The default is861              1.0.862      bitmapPixelSize (integer, optional):863              size of pixel rectangle on bitmap for which there must864              be same color on corresponding screenshot rectangle.  If865              scale is 1.0, default is 1 (rectangle is 1x1). If scale866              != 1.0, the default is 2 (rectangle is 2x2).867      screenshotPixelSize (integer, optional):868              size of pixel rectangle on screenshot in which there869              must be a same color pixel as in the corresponding870              rectangle on bitmap. The default is scale *871              bitmapPixelSize.872      preprocess (string, optional):873              preprocess parameters that are executed to both screenshot874              and reference bitmap before running findBitmap. By default875              there is no preprocessing.876              Example: d.verifyBitmap("ref.png", preprocess="-threshold 60%")877              will execute two imagemagick commands:878                1. convert screenshot.png -threshold 60% screenshot-pp.png879                2. convert ref.png -threshold 60% ref-pp.png880              and then search for ref-pp.png in screenshot-pp.png. This results881              in black-and-white comparison (immune to slight color changes).882    If unsure about parameters, but you have a bitmap that should be883    detected in a screenshot, try obj.oirEngine().adjustParameters().884    Example:885    d.enableVisualLog("params.html")886    screenshot = d.refreshScreenshot()887    results = d.oirEngine().adjustParameters(screenshot, "mybitmap.png")888    if results:889        item, params = results[0]890        print "found %s with parameters:" % (item,)891        print "\n".join(sorted(["  %s = %s" % (k, params[k]) for k in params]))892        print "verify:", d.verifyBitmap("mybitmap.png", **params)893    Notice, that you can force refreshScreenshot to load old screenshot:894    d.refreshScreenshot("old.png")895    """896    def __init__(self, *args, **engineDefaults):897        engineDefaults["colorMatch"] = engineDefaults.get("colorMatch", 1.0)898        engineDefaults["opacityLimit"] = engineDefaults.get("opacityLimit", 0.0)899        engineDefaults["area"] = engineDefaults.get("area", (0.0, 0.0, 1.0, 1.0))900        engineDefaults["limit"] = engineDefaults.get("limit", -1)901        engineDefaults["allowOverlap"] = engineDefaults.get("allowOverlap", False)902        engineDefaults["scale"] = engineDefaults.get("scale", 1.0)903        engineDefaults["bitmapPixelSize"] = engineDefaults.get("bitmapPixelSize", 0)904        engineDefaults["screenshotPixelSize"] = engineDefaults.get("screenshotPixelSize", 0)905        engineDefaults["preprocess"] = engineDefaults.get("preprocess", "")906        OirEngine.__init__(self, *args, **engineDefaults)907        self._openedImages = {}908        # openedRelatedScreenshots maps a screenshot filename to909        # a list of preprocessed screenshot objects. All those objects910        # must be closed when the screenshot is removed.911        self._openedRelatedScreenshots = {}912        self._findBitmapCache = {}913    def _addScreenshot(self, screenshot, **findBitmapDefaults):914        filename = screenshot.filename()915        self._openedImages[filename] = _e4gOpenImage(filename)916        # make sure size() is available, this can save an extra917        # opening of the screenshot file.918        if screenshot.size(allowReadingFile=False) == None:919            screenshot.setSize(_e4gImageDimensions(self._openedImages[filename]))920        self._findBitmapCache[filename] = {}921    def _removeScreenshot(self, screenshot):922        filename = screenshot.filename()923        if filename in self._openedRelatedScreenshots:924            for screenshotPP in self._openedRelatedScreenshots[filename]:925                self._removeScreenshot(screenshotPP)926            del self._openedRelatedScreenshots[filename]927        eye4graphics.closeImage(self._openedImages[filename])928        del self._openedImages[filename]929        del self._findBitmapCache[filename]930    def adjustParameters(self, screenshot, bitmap,931                         scaleRange = [p/100.0 for p in range(110,210,10)],932                         colorMatchRange = [p/100.0 for p in range(100,60,-10)],933                         pixelSizeRange = range(2,5),934                         resultCount = 1,935                         **oirArgs):936        """937        Search for scale, colorMatch, bitmapPixelSize and938        screenshotPixelSize parameters that find the bitmap in the939        screenshot.940        Parameters:941          screenshot (Screenshot instance):942                  screenshot that contains the bitmap.943          bitmap (string):944                  bitmap filename.945          scaleRange (list of floats, optional):946                  scales to go through.947                  The default is: 1.1, 1.2, ... 2.0.948          colorMatchRange (list of floats, optional):949                  colorMatches to try out.950                  The default is: 1.0, 0.9, ... 0.7.951          pixelSizeRange (list of integers, optional):952                  values for bitmapPixelSize and screenshotPixelSize.953                  The default is: [2, 3]954          resultCount (integer, optional):955                  number of parameter combinations to be found.956                  The default is 1. 0 is unlimited.957          other OIR parameters: as usual, refer to engine documentation.958        Returns list of pairs: (GUIItem, findParams), where959        GUIItem is the detected item (GUIItem.bbox() is the box around it),960        and findParams is a dictionary containing the parameters.961        """962        if not screenshot.filename() in self._findBitmapCache:963            self.addScreenshot(screenshot)964            ssAdded = True965        else:966            ssAdded = False967        retval = []968        for colorMatch in colorMatchRange:969            for pixelSize in pixelSizeRange:970                for scale in scaleRange:971                    findParams = oirArgs.copy()972                    findParams.update({"colorMatch": colorMatch,973                                       "limit": 1,974                                       "scale": scale,975                                       "bitmapPixelSize": pixelSize,976                                       "screenshotPixelSize": pixelSize})977                    results = self.findBitmap(screenshot, bitmap,978                                               **findParams)979                    if results:980                        retval.append((results[0], findParams))981                        if len(retval) == resultCount:982                            return retval983        if ssAdded:984            self.removeScreenshot(screenshot)985        return retval986    def _findBitmap(self, screenshot, bitmap, colorMatch=None,987                    opacityLimit=None, area=None, limit=None,988                    allowOverlap=None, scale=None,989                    bitmapPixelSize=None, screenshotPixelSize=None,990                    preprocess=None):991        """992        Find items on the screenshot that match to bitmap.993        """994        ssFilename = screenshot.filename()995        ssSize = screenshot.size()996        cacheKey = (bitmap, colorMatch, opacityLimit, area, limit,997                    scale, bitmapPixelSize, screenshotPixelSize, preprocess)998        if cacheKey in self._findBitmapCache[ssFilename]:999            return self._findBitmapCache[ssFilename][cacheKey]1000        self._findBitmapCache[ssFilename][cacheKey] = []1001        if preprocess:1002            ssFilenamePP = _ppFilename(ssFilename, preprocess)1003            bitmapPP = _ppFilename(bitmap, preprocess)1004            if not ssFilenamePP in self._openedImages:1005                _convert(ssFilename, preprocess, ssFilenamePP)1006                screenshotPP = Screenshot(ssFilenamePP)1007                self.addScreenshot(screenshotPP)1008                if not ssFilename in self._openedRelatedScreenshots:1009                    self._openedRelatedScreenshots[ssFilename] = []1010                self._openedRelatedScreenshots[ssFilename].append(screenshotPP)1011            _convert(bitmap, preprocess, bitmapPP)1012            ssFilename = ssFilenamePP1013            bitmap = bitmapPP1014            self._findBitmapCache[ssFilename][cacheKey] = []1015        e4gIcon = _e4gOpenImage(bitmap)1016        matchCount = 01017        leftTopRightBottomZero = (_intCoords((area[0], area[1]), ssSize) +...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!!
