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 <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'
场景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最新版中应该如何传递能力值呢?