韶光暗淡 发表于 2023-7-21 10:13:05

一个新版本引发一个问题之Appium

本帖最后由 韶光暗淡 于 2023-7-21 10:19 编辑

准备工作
1、测试代码
<font size="3">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)</font>2、测试环境

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

3、场景一:默认安装PASS

[*]在pycharm中安装appium-python-client,版本不指定,此时是2.11.1
[*]对应依赖selenium4.10.0
[*]执行示例代码
[*]测试通过
[*]??? 所以博主你要表达啥
[*]继续看下去

4 场景二:appium-python-client2.6.0+selenium4.10 FAlL
[*]你根据指定版本安装appium-python-client为2.6,自动安装selenium4.10
[*]执行示例代码
[*]测试失败
[*]提示如下

<font size="3">D:\Appium01\venv\Scripts\python.exe D:/Appium01/demo1.py
Traceback (most recent call last):
File "D:\Appium01\demo1.py", line 9, in <module>
    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'</font>
五 场景3:appium-python-client2.6.0+selenium4.3.0 PASS
[*]你应该是先安装selenium4.3.0
[*]然后再安装appium-python-client2.6.0
[*]都是指定版本安装


[*]有同学会说,谁会这样安装呢
[*]会的,因为你可能是先学selenium(我课程要求是4.3,最新的版本4.10的改进对我们没有太大意义,但底层确实改变了很多)

[*]测试通过


6、问题说明TypeError 分析
先看报错
<font size="3">TypeError: WebDriver.__init__() got an unexpected keyword argument 'desired_capabilities'</font>
[*]主要版本信息:


[*]appium-python-client2.6.0
[*]selenium4.10

[*]报错行

<font size="3">driver = webdriver.Remote</font>Remote是个别名<font size="3"> from .webdriver import WebDriver as Remote</font>
看WebDriver源码
<font size="3">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 = None,
      browser_profile: str = None,
      proxy: str = None,
      keep_alive: bool = True,
      direct_connection: bool = True,
      extensions: Optional] = None,
      strict_ssl: bool = True,
      options: Union] = None,
    ):</font>
[*]__init__中传递了desired_capabilities没有问题
[*]继续分析堆栈

<font size="3">File "D:\Appium01\venv\lib\site-packages\appium\webdriver\webdriver.py", line 230, in __init__
    super().__init__(</font>
继续看WebDriver此处源码<font size="3">File "D:\Appium01\venv\lib\site-packages\appium\webdriver\webdriver.py", line 230, in __init__
    super().__init__(</font>继续看WebDriver此处源码
<font size="3">      super().__init__(
            command_executor=AppiumConnection(command_executor, keep_alive=keep_alive),
            desired_capabilities=desired_capabilities,
            browser_profile=browser_profile,
            proxy=proxy,
            options=options,
      )</font>
[*]这里也有desired_capabilities,为何报错了呢
[*]请看WebDriver的继承webdriver.Remote

<font size="3">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] = None,
    ) -> None:</font>

[*]到这里你发现了,这个__init__里面没有desired_capabilities
[*]注意webdriver.Remote是隶属于selenium的,你此时的selenium是4.10,升级了,可能导致它remove了一些参数

韶光暗淡 发表于 2023-7-21 10:17:48

6.2appium-python-client2.11.1+selenium4.10

[*]这是默认组合,要知道selenium也是4.10了,为何没有报错呢?
[*]其调用关系简单分析下
[*]在Remote的__init__中,也支持desired_capabilities,但有如下信息

<font size="3">      # TODO: Remove the deprecated arg
      desired_capabilities: Optional = 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,
            )</font>

[*]


[*]后续要移除desired_capabilities
[*]用options替代(模仿selenium)

[*]关键的问题是在于,appium-python-client2.11.1中对父类__init__的调用是不携带desired_capabilities的

<font size="3">      super().__init__(
            command_executor=command_executor,
            options=dst_options,
      )</font>
完整代码片段如下<font size="3">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 = 'http://127.0.0.1:4444/wd/hub',
      # TODO: Remove the deprecated arg
      desired_capabilities: Optional = None,
      # TODO: Remove the deprecated arg
      browser_profile: Union = None,
      # TODO: Remove the deprecated arg
      proxy: Union = None,
      keep_alive: bool = True,
      direct_connection: bool = True,
      extensions: Optional] = None,
      strict_ssl: bool = True,
      options: Union, 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,
      )</font>6.3appium-python-client2.6.0+selenium4.3.0

[*]想必分析到此处,你应该盲猜能知道为何这个也PASS了
[*]是因为selenium的版本中webdriver.Remote中是有desired_capabilities的



<font size="3">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] = None):</font>7.0总结:

[*]最新版本appium-python-client即将不提供desired_capabilities的传参,但目前能用
[*]在selenium4.10中已经不支持desired_capabilities参数
[*]错误的搭配可能会引发上述问题,要么用最新的版本(默认安装),要么2个都用较低的版本
[*]留在最后的问题,那么在appium最新版中应该如何传递能力值呢?

<font size="3">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)</font>
页: [1]
查看完整版本: 一个新版本引发一个问题之Appium