通用逻辑

多次运行一个函数,直到成功运行

执行一个函数(可能有多个可变数量的参数),且尝试多次,直到成功或超出最大此时,最终实现是:

def multipleRetry(functionInfoDict, maxRetryNum=5, sleepInterval=0.1, isShowErrWhenFail=True):
    """
    do something, retry mutiple time if fail

    Args:
        functionInfoDict (dict): function info dict contain functionCallback and [optional] functionParaDict
        maxRetryNum (int): max retry number
        sleepInterval (float): sleep time of each interval when fail
        isShowErrWhenFail (bool): show error when fail if true
    Returns:
        bool
    Raises:
    """
    doSuccess = False
    functionCallback = functionInfoDict["functionCallback"]
    functionParaDict = functionInfoDict.get("functionParaDict", None)

    curRetryNum = maxRetryNum
    while curRetryNum > 0:
        if functionParaDict:
            doSuccess = functionCallback(**functionParaDict)
        else:
            doSuccess = functionCallback()

        if doSuccess:
            break

        time.sleep(sleepInterval)
        curRetryNum -= 1

    if not doSuccess:
        if isShowErrWhenFail:
            functionName = str(functionCallback)
            # '<bound method DevicesMethods.switchToAppStoreSearchTab of <src.AppCrawler.AppCrawler object at 0x1053abe80>>'
            logging.error("Still fail after %d retry for %s", maxRetryNum, functionName)
    return doSuccess

说明:

functionCallback函数类型都要符合:返回值是bool类型才可以

调用举例:

(1)没有额外参数

foundAndClickedWifi = CommonUtils.multipleRetry({"functionCallback": self.iOSFromSettingsIntoWifiList})

其中:

def iOSFromSettingsIntoWifiList(self):
。。。
    foundAndClickedWifi = self.findAndClickElement(query=wifiTextQuery, timeout=0.1)
    return foundAndClickedWifi

类似例子:

isSwitchOk = self.multipleRetry({"functionCallback": self.switchToAppStoreSearchTab})

对比之前原始写法:

isSwitchOk = self.switchToAppStoreSearchTab()

其他类似例子:

foundAndClickedDownload = self.multipleRetry({"functionCallback": self.appStoreStartDownload})

详见:

【已解决】AppStore自动安装iOS的app:逻辑优化加等待和多试几次

(2)有额外参数,参数个数:2个

searchInputQuery = {"type":"XCUIElementTypeSearchField", "name":"App Store"}
isInputOk = CommonUtils.multipleRetry(
    {
        "functionCallback": self.wait_element_setText,
        "functionParaDict": {
            "locator": searchInputQuery,
            "text": appName,
        }
    }
)

对比之前原始写法:

searchInputQuery = {"type":"XCUIElementTypeSearchField", "name":"App Store"}
isInputOk = self.wait_element_setText(searchInputQuery, appName)

其中wait_element_setText的定义是:

def wait_element_setText(self, locator, text):

对应着之前传入时的:

"functionParaDict": {
    "locator": searchInputQuery,
    "text": appName,
}

(3)有额外参数,且加上multipleRetry的额外参数

isSwitchOk = CommonUtils.multipleRetry(
    {"functionCallback": self.switchToAppStoreSearchTab},
    maxRetryNum = 10,
    sleepInterval = 0.5,
)

以及类似的:

isIntoDetailOk = self.multipleRetry(
    {
        "functionCallback": self.appStoreSearchResultIntoDetail,
        "functionParaDict": {
            "appName": appName,
        }
    },
    sleepInterval=0.5
)

之前原始写法:

isIntoDetailOk = self.appStoreSearchResultIntoDetail(appName)

注:

此处是后来加上的

sleepInterval=0.5

是因为后来遇到了,即使尝试了5次,依旧没找到,所以增加了没找到的延迟等待时间。

详见:

【已解决】AppStore自动安装iOS的app:逻辑优化加等待和多试几次

(4)

isIntoDetailOk = CommonUtils.multipleRetry(
    {
        "functionCallback": self.appStoreSearchResultIntoDetail,
        "functionParaDict": {
            "appName": appName,
        }
    },
    maxRetryNum = 10,
    sleepInterval = 0.5,
)

新版:新增参数isRespFullRetValue

此处最后更新:20200925

后续多次优化新增参数:是否返回完整信息

代码:

def multipleRetry(functionInfoDict, maxRetryNum=5, sleepInterval=0.1, isShowErrWhenFail=True, isRespFullRetValue=False):
    """do something, retry if single call failed, retry mutiple time until max retry number

    Args:
        functionInfoDict (dict): function info dict contain functionCallback and [optional] functionParaDict
        maxRetryNum (int): max retry number
        sleepInterval (float): sleep time (seconds) of each interval when fail
        isShowErrWhenFail (bool): show error when fail if true
        isRespFullRetValue (bool): whether return full return value of function call
    Returns:
        isRespFullRetValue=False: bool
        isRespFullRetValue=True: bool / tuple/list/...
    Raises:
    """
    finalReturnValue = None
    doSuccess = False
    functionCallback = functionInfoDict["functionCallback"]
    functionParaDict = functionInfoDict.get("functionParaDict", None)

    curRetryNum = maxRetryNum
    while curRetryNum > 0:
        if functionParaDict:
            # doSuccess = functionCallback(**functionParaDict)
            respValue = functionCallback(**functionParaDict)
        else:
            # doSuccess = functionCallback()
            respValue = functionCallback()

        doSuccess = False
        if isinstance(respValue, bool):
            doSuccess = bool(respValue)
        elif isinstance(respValue, tuple):
            doSuccess = bool(respValue[0])
        elif isinstance(respValue, list):
            doSuccess = bool(respValue[0])
        else:
            Exception("multipleRetry: Not support type of return value: %s" % respValue)

        if isRespFullRetValue:
            finalReturnValue = respValue
        else:
            finalReturnValue = doSuccess

        if doSuccess:
            break

        time.sleep(sleepInterval)
        curRetryNum -= 1

    if not doSuccess:
        if isShowErrWhenFail:
            functionName = str(functionCallback)
            # '<bound method DevicesMethods.switchToAppStoreSearchTab of <src.AppCrawler.AppCrawler object at 0x1053abe80>>'
            logging.error("Still fail after %d retry for %s", maxRetryNum, functionName)
    # return doSuccess
    return finalReturnValue

调用举例:

(1)默认不返回完整信息,只返回bool值

respBoolOrTuple = CommonUtils.multipleRetry(
    functionInfoDict = {
        "functionCallback": self.isGotoPayPopupPage,
        "functionParaDict": {
            "isRespLocation": False,
        },
    },
)

(2)返回完整信息

respBoolOrTuple = CommonUtils.multipleRetry(
    functionInfoDict = {
        "functionCallback": self.isGotoPayPopupPage,
        "functionParaDict": {
            "isRespLocation": True,
        },
    },
    isRespFullRetValue = True,
)

results matching ""

    No results matching ""