• Appium新版本引发的一个问题


    Appium新版本引发的一个问题

    准备工作

    测试代码

    from appium import webdriver
    des_cap = {'platformName': 'android'}
    driver = webdriver.Remote(command_executor='http://127.0.0.1:4723/wd/hub',
                              desired_capabilities=des_cap)
    

    测试环境

    • python 3.10,虚拟环境
    • pycharm 2018 community
    • 测试时间 2023-7-20

    场景一: 默认安装 PASS

    • 在pycharm中安装appium-python-client,版本不指定,此时是2.11.1

    • 对应依赖selenium4.10.0

    • 执行示例代码

    • 测试通过

    • ??? 所以博主你要表达啥

    • 继续看下去

    场景二:appium-python-client2.6.0+selenium4.10 FAIL

    • 你根据指定版本安装appium-python-client为2.6,自动安装selenium4.10

    • 执行示例代码

    • 测试失败

    • 提示如下

      D:\Appium01\venv\Scripts\python.exe D:/Appium01/demo1.py
      Traceback (most recent call last):
        File "D:\Appium01\demo1.py", line 9, in 
          driver = webdriver.Remote(command_executor='http://127.0.0.1:4723/wd/hub',
        File "D:\Appium01\venv\lib\site-packages\appium\webdriver\webdriver.py", line 230, in __init__
          super().__init__(
      TypeError: WebDriver.__init__() got an unexpected keyword argument 'desired_capabilities'
      

    场景3:appium-python-client2.6.0+selenium4.3.0 PASS

    • 你应该是先安装selenium4.3.0
    • 然后再安装appium-python-client2.6.0
    • 都是指定版本安装
      • 有同学会说,谁会这样安装呢
      • 会的,因为你可能是先学selenium(我课程要求是4.3,最新的版本4.10的改进对我们没有太大意义,但底层确实改变了很多)
    • 测试通过

    问题说明

    TypeError 分析

    • 先看报错

      TypeError: WebDriver.__init__() got an unexpected keyword argument 'desired_capabilities'
      
    • 主要版本信息:

      • appium-python-client2.6.0
      • selenium4.10
    • 报错行

      driver = webdriver.Remote
      
    • Remote是个别名

       from .webdriver import WebDriver as Remote
      
    • 看WebDriver源码

      class WebDriver(
          webdriver.Remote,
          ActionHelpers,
          Activities,
          Applications,
          Clipboard,
          Context,
          Common,
          DeviceTime,
          Display,
          ExecuteDriver,
          ExecuteMobileCommand,
          Gsm,
          HardwareActions,
          ImagesComparison,
          IME,
          Keyboard,
          Location,
          LogEvent,
          Network,
          Performance,
          Power,
          RemoteFS,
          ScreenRecord,
          Session,
          Settings,
          Sms,
          SystemBars,
      ):
          def __init__(
              self,
              command_executor: str = 'http://127.0.0.1:4444/wd/hub',
              desired_capabilities: Optional[Dict] = None,
              browser_profile: str = None,
              proxy: str = None,
              keep_alive: bool = True,
              direct_connection: bool = True,
              extensions: Optional[List['WebDriver']] = None,
              strict_ssl: bool = True,
              options: Union[AppiumOptions, List[AppiumOptions]] = None,
          ):
      
    • __init__中传递了desired_capabilities没有问题

    • 继续分析堆栈

      File "D:\Appium01\venv\lib\site-packages\appium\webdriver\webdriver.py", line 230, in __init__
          super().__init__(
      
    • 继续看WebDriver此处源码

              super().__init__(
                  command_executor=AppiumConnection(command_executor, keep_alive=keep_alive),
                  desired_capabilities=desired_capabilities,
                  browser_profile=browser_profile,
                  proxy=proxy,
                  options=options,
              )
      
    • 这里也有desired_capabilities,为何报错了呢

    • 请看WebDriver的继承webdriver.Remote

      class WebDriver(BaseWebDriver):
          _web_element_cls = WebElement
          _shadowroot_cls = ShadowRoot
      
          def __init__(
              self,
              command_executor="http://127.0.0.1:4444",
              keep_alive=True,
              file_detector=None,
              options: Union[BaseOptions, List[BaseOptions]] = None,
          ) -> None:
      
    • 到这里你发现了,这个__init__里面没有desired_capabilities

    • 注意webdriver.Remote是隶属于selenium的,你此时的selenium是4.10,升级了,可能导致它remove了一些参数

    appium-python-client2.11.1+selenium4.10

    • 这是默认组合,要知道selenium也是4.10了,为何没有报错呢?

    • 其调用关系简单分析下

    • Remote__init__中,也支持desired_capabilities,但有如下信息

              # TODO: Remove the deprecated arg
              desired_capabilities: Optional[Dict] = None,
              
              if desired_capabilities is not None:
                  warnings.warn(
                      'desired_capabilities argument is deprecated and will be removed in future versions. '
                      'Use options instead.',
                      DeprecationWarning,
                  )
      
      • 后续要移除desired_capabilities
      • 用options替代(模仿selenium)
    • 关键的问题是在于,appium-python-client2.11.1中对父类__init__的调用是不携带desired_capabilities的

              super().__init__(
                  command_executor=command_executor,
                  options=dst_options,
              )
      
    • 完整代码片段如下

      class WebDriver(
          webdriver.Remote,
          ActionHelpers,
          Activities,
          Applications,
          Clipboard,
          Context,
          Common,
          DeviceTime,
          Display,
          ExecuteDriver,
          ExecuteMobileCommand,
          Gsm,
          HardwareActions,
          ImagesComparison,
          IME,
          Keyboard,
          Location,
          LogEvent,
          Network,
          Performance,
          Power,
          RemoteFS,
          ScreenRecord,
          Session,
          Settings,
          Sms,
          SystemBars,
      ):
          def __init__(
              self,
              command_executor: Union[str, AppiumConnection] = 'http://127.0.0.1:4444/wd/hub',
              # TODO: Remove the deprecated arg
              desired_capabilities: Optional[Dict] = None,
              # TODO: Remove the deprecated arg
              browser_profile: Union[str, None] = None,
              # TODO: Remove the deprecated arg
              proxy: Union[str, None] = None,
              keep_alive: bool = True,
              direct_connection: bool = True,
              extensions: Optional[List['WebDriver']] = None,
              strict_ssl: bool = True,
              options: Union[AppiumOptions, List[AppiumOptions], None] = None,
          ):
              if strict_ssl is False:
                  # pylint: disable=E1101
                  # noinspection PyPackageRequirements
                  import urllib3
      
                  # pylint: disable=E1101
                  # noinspection PyPackageRequirements
                  import urllib3.exceptions
      
                  # noinspection PyUnresolvedReferences
                  AppiumConnection.set_certificate_bundle_path(None)
                  urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
      
              if isinstance(command_executor, str):
                  command_executor = AppiumConnection(command_executor, keep_alive=keep_alive)
      
              if browser_profile is not None:
                  warnings.warn('browser_profile argument is deprecated and has no effect', DeprecationWarning)
      
              if proxy is not None:
                  warnings.warn('proxy argument is deprecated and has no effect', DeprecationWarning)
      
              if desired_capabilities is not None:
                  warnings.warn(
                      'desired_capabilities argument is deprecated and will be removed in future versions. '
                      'Use options instead.',
                      DeprecationWarning,
                  )
              # TODO: Remove the fallback after desired_capabilities removal
              dst_options = (
                  AppiumOptions().load_capabilities(desired_capabilities)
                  if desired_capabilities is not None and options is None
                  else options
              )
      
              super().__init__(
                  command_executor=command_executor,
                  options=dst_options,
              )
      

    appium-python-client2.6.0+selenium4.3.0

    • 想必分析到此处,你应该盲猜能知道为何这个也PASS了

    • 是因为selenium的版本中webdriver.Remote中是有desired_capabilities的

      class WebDriver(BaseWebDriver):
          _web_element_cls = WebElement
          _shadowroot_cls = ShadowRoot
      
          def __init__(self, command_executor='http://127.0.0.1:4444',
                       desired_capabilities=None, browser_profile=None, proxy=None,
                       keep_alive=True, file_detector=None, options: Union[BaseOptions, List[BaseOptions]] = None):
      

    总结

    • 最新版本appium-python-client即将不提供desired_capabilities的传参,但目前能用
    • 在selenium4.10中已经不支持desired_capabilities参数
    • 错误的搭配可能会引发上述问题,要么用最新的版本(默认安装),要么2个都用较低的版本
    • 留在最后的问题,那么在appium最新版中应该如何传递能力值呢?
    from appium import webdriver
    from appium.options.common import AppiumOptions
    
    option = AppiumOptions()
    option.set_capability('platformName','android')
    driver = webdriver.Remote(command_executor='http://127.0.0.1:4723/wd/hub',
                              options=option)
    
  • 相关阅读:
    参数化建模 vs. 直接建模【CAD】
    深信服科技:2023网络钓鱼趋势分析报告
    [k8s] 常见yml配置和详细解释
    网络编程
    【无标题】菜市场
    2021年下半年软件设计师下午真题答案及解析(五)
    浅析数据迁移工具Sqoop
    NetSuite 关闭期间的销售订单可否修改
    【STL源码剖析】STL六大组件功能与运用(目录)
    【Flowable】任务监听器(五)
  • 原文地址:https://www.cnblogs.com/wuxianfeng023/p/17567613.html