From 27cb0ca650f196b3b3d761af6ce054581e6138d0 Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Thu, 28 Nov 2024 01:07:40 -0800 Subject: [PATCH 01/22] initial implementation --- appium/webdriver/webdriver.py | 24 ++++++++---------------- test/unit/webdriver/webdriver_test.py | 15 +++++++-------- 2 files changed, 15 insertions(+), 24 deletions(-) diff --git a/appium/webdriver/webdriver.py b/appium/webdriver/webdriver.py index 200d5f91..09229fda 100644 --- a/appium/webdriver/webdriver.py +++ b/appium/webdriver/webdriver.py @@ -22,7 +22,6 @@ WebDriverException, ) from selenium.webdriver.common.by import By -from selenium.webdriver.remote.client_config import ClientConfig from selenium.webdriver.remote.command import Command as RemoteCommand from selenium.webdriver.remote.remote_connection import RemoteConnection from typing_extensions import Self @@ -32,6 +31,7 @@ from appium.webdriver.common.appiumby import AppiumBy from .appium_connection import AppiumConnection +from .client_config import AppiumClientConfg from .errorhandler import MobileErrorHandler from .extensions.action_helpers import ActionHelpers from .extensions.android.activities import Activities @@ -205,24 +205,16 @@ class WebDriver( def __init__( # noqa: PLR0913 self, command_executor: Union[str, AppiumConnection] = 'http://127.0.0.1:4444/wd/hub', - keep_alive: bool = True, - direct_connection: bool = True, extensions: Optional[List['WebDriver']] = None, - strict_ssl: bool = True, options: Union[AppiumOptions, List[AppiumOptions], None] = None, - client_config: Optional[ClientConfig] = None, + client_config: Optional[AppiumClientConfg] = None, ): + if client_config is None: + # TODO: when command_executor is not string + client_config = client_config or AppiumClientConfg(remote_server_addr=command_executor) + if isinstance(command_executor, str): - client_config = client_config or ClientConfig( - remote_server_addr=command_executor, keep_alive=keep_alive, ignore_certificates=not strict_ssl - ) - client_config.remote_server_addr = command_executor command_executor = AppiumConnection(remote_server_addr=command_executor, client_config=client_config) - elif isinstance(command_executor, AppiumConnection) and strict_ssl is False: - logger.warning( - "Please set 'ignore_certificates' in the given 'appium.webdriver.appium_connection.AppiumConnection' or " - "'selenium.webdriver.remote.client_config.ClientConfig' instead. Ignoring." - ) super().__init__( command_executor=command_executor, @@ -237,8 +229,8 @@ def __init__( # noqa: PLR0913 self.error_handler = MobileErrorHandler() - if direct_connection: - self._update_command_executor(keep_alive=keep_alive) + if client_config.direct_connection: + self._update_command_executor(keep_alive=client_config.keep_alive) # add new method to the `find_by_*` pantheon By.IOS_PREDICATE = AppiumBy.IOS_PREDICATE diff --git a/test/unit/webdriver/webdriver_test.py b/test/unit/webdriver/webdriver_test.py index 47a4353e..90d4fcca 100644 --- a/test/unit/webdriver/webdriver_test.py +++ b/test/unit/webdriver/webdriver_test.py @@ -21,6 +21,7 @@ from appium import webdriver from appium.options.android import UiAutomator2Options from appium.webdriver.appium_connection import AppiumConnection +from appium.webdriver.client_config import AppiumClientConfg from appium.webdriver.webdriver import ExtensionBase, WebDriver from test.helpers.constants import SERVER_URL_BASE from test.unit.helper.test_helper import ( @@ -124,10 +125,11 @@ def test_create_session_register_uridirect(self): 'app': 'path/to/app', 'automationName': 'UIAutomator2', } + client_config = AppiumClientConfg(remote_server_addr=SERVER_URL_BASE, direct_connection=True) driver = webdriver.Remote( SERVER_URL_BASE, options=UiAutomator2Options().load_capabilities(desired_caps), - direct_connection=True, + client_config=client_config, ) assert 'http://localhost2:4800/special/path/wd/hub' == driver.command_executor._client_config.remote_server_addr @@ -164,10 +166,9 @@ def test_create_session_register_uridirect_no_direct_connect_path(self): 'app': 'path/to/app', 'automationName': 'UIAutomator2', } + client_config = AppiumClientConfg(remote_server_addr=SERVER_URL_BASE, direct_connection=True) driver = webdriver.Remote( - SERVER_URL_BASE, - options=UiAutomator2Options().load_capabilities(desired_caps), - direct_connection=True, + SERVER_URL_BASE, options=UiAutomator2Options().load_capabilities(desired_caps), client_config=client_config ) assert SERVER_URL_BASE == driver.command_executor._client_config.remote_server_addr @@ -382,19 +383,17 @@ def test_extention_command_check(self): class SubWebDriver(WebDriver): - def __init__(self, command_executor, direct_connection=False, options=None): + def __init__(self, command_executor, options=None): super().__init__( command_executor=command_executor, - direct_connection=direct_connection, options=options, ) class SubSubWebDriver(SubWebDriver): - def __init__(self, command_executor, direct_connection=False, options=None): + def __init__(self, command_executor, options=None): super().__init__( command_executor=command_executor, - direct_connection=direct_connection, options=options, ) From 7823cd729cd71cddcef9b683a555885820e51fa9 Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Thu, 28 Nov 2024 01:08:16 -0800 Subject: [PATCH 02/22] remove --- appium/webdriver/webdriver.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appium/webdriver/webdriver.py b/appium/webdriver/webdriver.py index 09229fda..377350b6 100644 --- a/appium/webdriver/webdriver.py +++ b/appium/webdriver/webdriver.py @@ -211,7 +211,7 @@ def __init__( # noqa: PLR0913 ): if client_config is None: # TODO: when command_executor is not string - client_config = client_config or AppiumClientConfg(remote_server_addr=command_executor) + client_config = AppiumClientConfg(remote_server_addr=command_executor) if isinstance(command_executor, str): command_executor = AppiumConnection(remote_server_addr=command_executor, client_config=client_config) From ce1f24323e49ec49cbad182a346adaa2c404154b Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Thu, 28 Nov 2024 01:10:24 -0800 Subject: [PATCH 03/22] add appium/webdriver/client_config.py --- appium/webdriver/client_config.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 appium/webdriver/client_config.py diff --git a/appium/webdriver/client_config.py b/appium/webdriver/client_config.py new file mode 100644 index 00000000..5ff8a524 --- /dev/null +++ b/appium/webdriver/client_config.py @@ -0,0 +1,23 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from selenium.webdriver.remote.client_config import ClientConfig + + +class AppiumClientConfg(ClientConfig): + def __init__(self, remote_server_addr: str, *args, **kwargs): + self._direct_connection = kwargs.pop('direct_connection', False) + super().__init__(remote_server_addr, *args, **kwargs) + + @property + def direct_connection(self) -> bool: + return self._direct_connection From 09e0c59241c2d3da36052121a177d9779df3267d Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Wed, 4 Dec 2024 00:56:54 -0800 Subject: [PATCH 04/22] remove duplicated args --- README.md | 37 ++++++++++++++++++++++++++++++- appium/webdriver/client_config.py | 2 +- appium/webdriver/webdriver.py | 14 +++++------- 3 files changed, 43 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 24ad09d5..95f4a84d 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,35 @@ For example, some changes in the Selenium binding could break the Appium client. > to keep compatible version combinations. +### Quick migration guide from v4 to v5 +- Please use `AppiumClientConfig` as `client_config` arguemnt in favor of client arguments below + - `keep_alive`, `direct_connection` and `strict_ssl` arguments. + ```python + SERVER_URL_BASE = 'http://127.0.0.1:4723' + # before + driver = webdriver.Remote( + SERVER_URL_BASE, + options=UiAutomator2Options().load_capabilities(desired_caps), + direct_connection=True, + keep_alive=False, + strict_ssl=False + ) + + # after + from appium.webdriver.client_config import AppiumClientConfig + client_config = AppiumClientConfig( + remote_server_addr=SERVER_URL_BASE, + direct_connection=True, + keep_alive=False, + ignore_certificates=True, + ) + driver = webdriver.Remote( + SERVER_URL_BASE, + options=UiAutomator2Options().load_capabilities(desired_caps), + client_config=client_config + ) + ``` + ### Quick migration guide from v3 to v4 - Removal - `MultiAction` and `TouchAction` are removed. Please use W3C WebDriver actions or `mobile:` extensions @@ -273,6 +302,7 @@ from appium import webdriver # If you use an older client then switch to desired_capabilities # instead: https://github.com/appium/python-client/pull/720 from appium.options.ios import XCUITestOptions +from appium.webdriver.client_config import AppiumClientConfig # load_capabilities API could be used to # load options mapping stored in a dictionary @@ -282,11 +312,16 @@ options = XCUITestOptions().load_capabilities({ 'app': '/full/path/to/app/UICatalog.app.zip', }) +client_config = AppiumClientConfig( + remote_server_addr='http://127.0.0.1:4723', + direct_connection=True +) + driver = webdriver.Remote( # Appium1 points to http://127.0.0.1:4723/wd/hub by default 'http://127.0.0.1:4723', options=options, - direct_connection=True + client_config=client_config ) ``` diff --git a/appium/webdriver/client_config.py b/appium/webdriver/client_config.py index 5ff8a524..6b09434c 100644 --- a/appium/webdriver/client_config.py +++ b/appium/webdriver/client_config.py @@ -13,7 +13,7 @@ from selenium.webdriver.remote.client_config import ClientConfig -class AppiumClientConfg(ClientConfig): +class AppiumClientConfig(ClientConfig): def __init__(self, remote_server_addr: str, *args, **kwargs): self._direct_connection = kwargs.pop('direct_connection', False) super().__init__(remote_server_addr, *args, **kwargs) diff --git a/appium/webdriver/webdriver.py b/appium/webdriver/webdriver.py index 377350b6..48fd5d3c 100644 --- a/appium/webdriver/webdriver.py +++ b/appium/webdriver/webdriver.py @@ -31,7 +31,7 @@ from appium.webdriver.common.appiumby import AppiumBy from .appium_connection import AppiumConnection -from .client_config import AppiumClientConfg +from .client_config import AppiumClientConfig from .errorhandler import MobileErrorHandler from .extensions.action_helpers import ActionHelpers from .extensions.android.activities import Activities @@ -204,17 +204,15 @@ class WebDriver( ): def __init__( # noqa: PLR0913 self, - command_executor: Union[str, AppiumConnection] = 'http://127.0.0.1:4444/wd/hub', + command_executor: Union[str, AppiumConnection] = 'http://127.0.0.1:4723', extensions: Optional[List['WebDriver']] = None, options: Union[AppiumOptions, List[AppiumOptions], None] = None, - client_config: Optional[AppiumClientConfg] = None, + client_config: Optional[AppiumClientConfig] = None, ): - if client_config is None: - # TODO: when command_executor is not string - client_config = AppiumClientConfg(remote_server_addr=command_executor) - if isinstance(command_executor, str): - command_executor = AppiumConnection(remote_server_addr=command_executor, client_config=client_config) + if client_config is None: + client_config = AppiumClientConfig(remote_server_addr=command_executor) + command_executor = AppiumConnection(client_config=client_config) super().__init__( command_executor=command_executor, From dd19cff5d69d80227952deda150ee8b70b862d2e Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Wed, 4 Dec 2024 01:03:19 -0800 Subject: [PATCH 05/22] remove duplicated args --- appium/webdriver/client_config.py | 5 +++++ appium/webdriver/webdriver.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/appium/webdriver/client_config.py b/appium/webdriver/client_config.py index 6b09434c..f57e8761 100644 --- a/appium/webdriver/client_config.py +++ b/appium/webdriver/client_config.py @@ -14,7 +14,12 @@ class AppiumClientConfig(ClientConfig): + """ClientConfig class for Appium Python client.""" + def __init__(self, remote_server_addr: str, *args, **kwargs): + """ + TODO: add description + """ self._direct_connection = kwargs.pop('direct_connection', False) super().__init__(remote_server_addr, *args, **kwargs) diff --git a/appium/webdriver/webdriver.py b/appium/webdriver/webdriver.py index 48fd5d3c..a40336da 100644 --- a/appium/webdriver/webdriver.py +++ b/appium/webdriver/webdriver.py @@ -204,7 +204,7 @@ class WebDriver( ): def __init__( # noqa: PLR0913 self, - command_executor: Union[str, AppiumConnection] = 'http://127.0.0.1:4723', + command_executor: Union[str, AppiumConnection] = 'http://127.0.0.1:4444', extensions: Optional[List['WebDriver']] = None, options: Union[AppiumOptions, List[AppiumOptions], None] = None, client_config: Optional[AppiumClientConfig] = None, From 3c1c02f153cddb81ec077b1260d8a3b0318733a8 Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Wed, 4 Dec 2024 01:09:50 -0800 Subject: [PATCH 06/22] fix typo --- appium/webdriver/webdriver.py | 2 +- test/unit/webdriver/webdriver_test.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/appium/webdriver/webdriver.py b/appium/webdriver/webdriver.py index a40336da..956c14e6 100644 --- a/appium/webdriver/webdriver.py +++ b/appium/webdriver/webdriver.py @@ -227,7 +227,7 @@ def __init__( # noqa: PLR0913 self.error_handler = MobileErrorHandler() - if client_config.direct_connection: + if client_config and client_config.direct_connection: self._update_command_executor(keep_alive=client_config.keep_alive) # add new method to the `find_by_*` pantheon diff --git a/test/unit/webdriver/webdriver_test.py b/test/unit/webdriver/webdriver_test.py index 90d4fcca..e85f92a9 100644 --- a/test/unit/webdriver/webdriver_test.py +++ b/test/unit/webdriver/webdriver_test.py @@ -21,7 +21,7 @@ from appium import webdriver from appium.options.android import UiAutomator2Options from appium.webdriver.appium_connection import AppiumConnection -from appium.webdriver.client_config import AppiumClientConfg +from appium.webdriver.client_config import AppiumClientConfig from appium.webdriver.webdriver import ExtensionBase, WebDriver from test.helpers.constants import SERVER_URL_BASE from test.unit.helper.test_helper import ( @@ -125,7 +125,7 @@ def test_create_session_register_uridirect(self): 'app': 'path/to/app', 'automationName': 'UIAutomator2', } - client_config = AppiumClientConfg(remote_server_addr=SERVER_URL_BASE, direct_connection=True) + client_config = AppiumClientConfig(remote_server_addr=SERVER_URL_BASE, direct_connection=True) driver = webdriver.Remote( SERVER_URL_BASE, options=UiAutomator2Options().load_capabilities(desired_caps), @@ -166,7 +166,7 @@ def test_create_session_register_uridirect_no_direct_connect_path(self): 'app': 'path/to/app', 'automationName': 'UIAutomator2', } - client_config = AppiumClientConfg(remote_server_addr=SERVER_URL_BASE, direct_connection=True) + client_config = AppiumClientConfig(remote_server_addr=SERVER_URL_BASE, direct_connection=True) driver = webdriver.Remote( SERVER_URL_BASE, options=UiAutomator2Options().load_capabilities(desired_caps), client_config=client_config ) From 2aabd72e2b6bea48fbac0224766bf4b5e3b73c9f Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Sun, 23 Feb 2025 00:17:21 -0800 Subject: [PATCH 07/22] add file_detector and remove redundant config --- README.md | 1 - appium/webdriver/client_config.py | 14 ++++++++++++-- appium/webdriver/webdriver.py | 8 +++++++- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 9fd93df3..b500a860 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,6 @@ For example, some changes in the Selenium binding could break the Appium client. # after from appium.webdriver.client_config import AppiumClientConfig client_config = AppiumClientConfig( - remote_server_addr=SERVER_URL_BASE, direct_connection=True, keep_alive=False, ignore_certificates=True, diff --git a/appium/webdriver/client_config.py b/appium/webdriver/client_config.py index f57e8761..ae2c0e29 100644 --- a/appium/webdriver/client_config.py +++ b/appium/webdriver/client_config.py @@ -14,15 +14,25 @@ class AppiumClientConfig(ClientConfig): - """ClientConfig class for Appium Python client.""" + """ClientConfig class for Appium Python client. + This class inherits selenium.webdriver.remote.client_config.ClientConfig. + """ def __init__(self, remote_server_addr: str, *args, **kwargs): """ - TODO: add description + Please refer to selenium.webdriver.remote.client_config.ClientConfig documentation + about available arguments. Only 'direct_connection' below is AppiumClientConfig + specific argument. + + Args: + direct_connection: If enables [directConnect](https://github.com/appium/python-client?tab=readme-ov-file#direct-connect-urls) + feature. """ self._direct_connection = kwargs.pop('direct_connection', False) super().__init__(remote_server_addr, *args, **kwargs) @property def direct_connection(self) -> bool: + """Return if [directConnect](https://github.com/appium/python-client?tab=readme-ov-file#direct-connect-urls) + is enabled.""" return self._direct_connection diff --git a/appium/webdriver/webdriver.py b/appium/webdriver/webdriver.py index 5c3519c5..63408120 100644 --- a/appium/webdriver/webdriver.py +++ b/appium/webdriver/webdriver.py @@ -23,6 +23,7 @@ ) from selenium.webdriver.common.by import By from selenium.webdriver.remote.command import Command as RemoteCommand +from selenium.webdriver.remote.file_detector import FileDetector from selenium.webdriver.remote.remote_connection import RemoteConnection from typing_extensions import Self @@ -204,18 +205,23 @@ class WebDriver( ): def __init__( # noqa: PLR0913 self, - command_executor: Union[str, AppiumConnection] = 'http://127.0.0.1:4444', + command_executor: Union[str, AppiumConnection] = 'http://127.0.0.1:4723', extensions: Optional[List['WebDriver']] = None, + file_detector: Optional[FileDetector] = None, options: Union[AppiumOptions, List[AppiumOptions], None] = None, client_config: Optional[AppiumClientConfig] = None, ): if isinstance(command_executor, str): if client_config is None: client_config = AppiumClientConfig(remote_server_addr=command_executor) + else: + client_config.remote_server_addr = command_executor + # To prevent generating RemoteConnection in selenium command_executor = AppiumConnection(client_config=client_config) super().__init__( command_executor=command_executor, + file_detector=file_detector, options=options, locator_converter=AppiumLocatorConverter(), web_element_cls=MobileWebElement, From 9569035b3e6da9f1ca7a67a2a1e7be006213b2d0 Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Sun, 23 Feb 2025 00:38:10 -0800 Subject: [PATCH 08/22] add test to check remote_server_addr priority --- README.md | 2 +- appium/webdriver/webdriver.py | 2 -- test/unit/webdriver/webdriver_test.py | 39 +++++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b500a860..c2d11016 100644 --- a/README.md +++ b/README.md @@ -76,12 +76,12 @@ For example, some changes in the Selenium binding could break the Appium client. # after from appium.webdriver.client_config import AppiumClientConfig client_config = AppiumClientConfig( + remote_server_addr=SERVER_URL_BASE, direct_connection=True, keep_alive=False, ignore_certificates=True, ) driver = webdriver.Remote( - SERVER_URL_BASE, options=UiAutomator2Options().load_capabilities(desired_caps), client_config=client_config ) diff --git a/appium/webdriver/webdriver.py b/appium/webdriver/webdriver.py index 63408120..55eb2df9 100644 --- a/appium/webdriver/webdriver.py +++ b/appium/webdriver/webdriver.py @@ -214,8 +214,6 @@ def __init__( # noqa: PLR0913 if isinstance(command_executor, str): if client_config is None: client_config = AppiumClientConfig(remote_server_addr=command_executor) - else: - client_config.remote_server_addr = command_executor # To prevent generating RemoteConnection in selenium command_executor = AppiumConnection(client_config=client_config) diff --git a/test/unit/webdriver/webdriver_test.py b/test/unit/webdriver/webdriver_test.py index e85f92a9..26681ce6 100644 --- a/test/unit/webdriver/webdriver_test.py +++ b/test/unit/webdriver/webdriver_test.py @@ -175,6 +175,45 @@ def test_create_session_register_uridirect_no_direct_connect_path(self): assert ['NATIVE_APP', 'CHROMIUM'] == driver.contexts assert isinstance(driver.command_executor, AppiumConnection) + @httpretty.activate + def test_create_session_remote_server_addr_treatment_with_appiumclientconfig(self): + # remote server add in AppiumRemoteCong will be prior than the string of 'command_executor' + # as same as Selenium behavior. + httpretty.register_uri( + httpretty.POST, + f'{SERVER_URL_BASE}/session', + body=json.dumps( + { + 'sessionId': 'session-id', + 'capabilities': { + 'deviceName': 'Android Emulator', + }, + } + ), + ) + + httpretty.register_uri( + httpretty.GET, + f'{SERVER_URL_BASE}/session/session-id/contexts', + body=json.dumps({'value': ['NATIVE_APP', 'CHROMIUM']}), + ) + + desired_caps = { + 'platformName': 'Android', + 'deviceName': 'Android Emulator', + 'app': 'path/to/app', + 'automationName': 'UIAutomator2', + } + client_config = AppiumClientConfig(remote_server_addr=SERVER_URL_BASE, direct_connection=True) + driver = webdriver.Remote( + 'http://localhost:8080/something/path', + options=UiAutomator2Options().load_capabilities(desired_caps), + client_config=client_config, + ) + + assert SERVER_URL_BASE == driver.command_executor._client_config.remote_server_addr + assert isinstance(driver.command_executor, AppiumConnection) + @httpretty.activate def test_get_events(self): driver = ios_w3c_driver() From 2bdbea8db0ce5907a32c2c9fa35f87d3a2581803 Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Mon, 10 Mar 2025 00:19:43 -0700 Subject: [PATCH 09/22] remove PLR0913, address http://127.0.0.1:4723 --- README.md | 1 + appium/webdriver/webdriver.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c2d11016..fe245543 100644 --- a/README.md +++ b/README.md @@ -86,6 +86,7 @@ For example, some changes in the Selenium binding could break the Appium client. client_config=client_config ) ``` +- Use `http://127.0.0.1:4723` as the default server url instead of `http://127.0.0.1:4444` ### Quick migration guide from v3 to v4 - Removal diff --git a/appium/webdriver/webdriver.py b/appium/webdriver/webdriver.py index 55eb2df9..5cb38f75 100644 --- a/appium/webdriver/webdriver.py +++ b/appium/webdriver/webdriver.py @@ -203,7 +203,7 @@ class WebDriver( Sms, SystemBars, ): - def __init__( # noqa: PLR0913 + def __init__( self, command_executor: Union[str, AppiumConnection] = 'http://127.0.0.1:4723', extensions: Optional[List['WebDriver']] = None, From b7fdaa408cecb9825ef75b218ca085c31ffc39c0 Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Mon, 10 Mar 2025 00:22:58 -0700 Subject: [PATCH 10/22] update the readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fe245543..d86e625d 100644 --- a/README.md +++ b/README.md @@ -86,7 +86,7 @@ For example, some changes in the Selenium binding could break the Appium client. client_config=client_config ) ``` -- Use `http://127.0.0.1:4723` as the default server url instead of `http://127.0.0.1:4444` +- Use `http://127.0.0.1:4723` as the default server url instead of `http://127.0.0.1:4444/wd/hub` ### Quick migration guide from v3 to v4 - Removal From d52e243b478ca9f5008f10ce432b2b996e10f65b Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Mon, 10 Mar 2025 00:24:56 -0700 Subject: [PATCH 11/22] add comment --- appium/webdriver/webdriver.py | 1 + 1 file changed, 1 insertion(+) diff --git a/appium/webdriver/webdriver.py b/appium/webdriver/webdriver.py index 5cb38f75..a2247f79 100644 --- a/appium/webdriver/webdriver.py +++ b/appium/webdriver/webdriver.py @@ -212,6 +212,7 @@ def __init__( client_config: Optional[AppiumClientConfig] = None, ): if isinstance(command_executor, str): + # Do not keep None to avoid warnings in Selenium which can prevent with ClientConfig instance usage. if client_config is None: client_config = AppiumClientConfig(remote_server_addr=command_executor) # To prevent generating RemoteConnection in selenium From b06ed8edab3dbc79d2996b22c12e4a24c599909e Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Mon, 10 Mar 2025 00:25:36 -0700 Subject: [PATCH 12/22] fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d86e625d..cd6ca42b 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ For example, some changes in the Selenium binding could break the Appium client. ### Quick migration guide from v4 to v5 -- Please use `AppiumClientConfig` as `client_config` arguemnt in favor of client arguments below +- Please use `AppiumClientConfig` as `client_config` arguemnt in favor of client argument below - `keep_alive`, `direct_connection` and `strict_ssl` arguments. ```python SERVER_URL_BASE = 'http://127.0.0.1:4723' From 64a6553a1fe69bb29d23959f38e5eb45dc5fbe8e Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Mon, 10 Mar 2025 23:59:51 -0700 Subject: [PATCH 13/22] extract --- appium/webdriver/webdriver.py | 24 +++++++++++++++++------- test/unit/webdriver/webdriver_test.py | 12 +++++++++++- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/appium/webdriver/webdriver.py b/appium/webdriver/webdriver.py index a2247f79..a096a449 100644 --- a/appium/webdriver/webdriver.py +++ b/appium/webdriver/webdriver.py @@ -175,6 +175,20 @@ def add_command(self) -> Tuple[str, str]: raise NotImplementedError() +def _get_client_config_and_connection( + command_executor: Union[str, AppiumConnection], client_config: Optional[AppiumClientConfig] +) -> tuple[AppiumConnection, Optional[AppiumClientConfig]]: + if not isinstance(command_executor): + return (command_executor, client_config) + + # command_executor is str + if client_config is None: + # Do not keep None to avoid warnings in Selenium + # which can prevent with ClientConfig instance usage. + client_config = AppiumClientConfig(remote_server_addr=command_executor) + return (AppiumConnection(client_config=client_config), client_config) + + class WebDriver( webdriver.Remote, ActionHelpers, @@ -211,13 +225,9 @@ def __init__( options: Union[AppiumOptions, List[AppiumOptions], None] = None, client_config: Optional[AppiumClientConfig] = None, ): - if isinstance(command_executor, str): - # Do not keep None to avoid warnings in Selenium which can prevent with ClientConfig instance usage. - if client_config is None: - client_config = AppiumClientConfig(remote_server_addr=command_executor) - # To prevent generating RemoteConnection in selenium - command_executor = AppiumConnection(client_config=client_config) - + command_executor, client_config = _get_client_config_and_connection( + command_executor=command_executor, client_config=client_config + ) super().__init__( command_executor=command_executor, file_detector=file_detector, diff --git a/test/unit/webdriver/webdriver_test.py b/test/unit/webdriver/webdriver_test.py index 26681ce6..e5d1baee 100644 --- a/test/unit/webdriver/webdriver_test.py +++ b/test/unit/webdriver/webdriver_test.py @@ -22,7 +22,7 @@ from appium.options.android import UiAutomator2Options from appium.webdriver.appium_connection import AppiumConnection from appium.webdriver.client_config import AppiumClientConfig -from appium.webdriver.webdriver import ExtensionBase, WebDriver +from appium.webdriver.webdriver import ExtensionBase, WebDriver, _get_client_config_and_connection from test.helpers.constants import SERVER_URL_BASE from test.unit.helper.test_helper import ( android_w3c_driver, @@ -420,6 +420,16 @@ def test_extention_command_check(self): 'script': 'mobile: startActivity', } == get_httpretty_request_body(httpretty.last_request()) + def test_get_client_config_and_connection(self): + command_executor, client_config = _get_client_config_and_connection( + command_executor='http://127.0.0.1:4723', client_config=None + ) + + assert isinstance(command_executor, AppiumConnection) + assert command_executor._url == 'http://127.0.0.1:4723' + assert isinstance(client_config, AppiumClientConfig) + assert client_config.remote_server_addr == 'http://127.0.0.1:4723' + class SubWebDriver(WebDriver): def __init__(self, command_executor, options=None): From 2b19e2eec1b7208aada7d2bd6fc06b3cbe89fd42 Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Tue, 11 Mar 2025 00:29:48 -0700 Subject: [PATCH 14/22] extract and followed the selenium --- appium/webdriver/webdriver.py | 14 ++++++++---- test/unit/webdriver/webdriver_test.py | 33 +++++++++++++++++++++++---- 2 files changed, 39 insertions(+), 8 deletions(-) diff --git a/appium/webdriver/webdriver.py b/appium/webdriver/webdriver.py index a096a449..f45f141c 100644 --- a/appium/webdriver/webdriver.py +++ b/appium/webdriver/webdriver.py @@ -175,11 +175,17 @@ def add_command(self) -> Tuple[str, str]: raise NotImplementedError() -def _get_client_config_and_connection( +def _get_remote_connection_and_client_config( command_executor: Union[str, AppiumConnection], client_config: Optional[AppiumClientConfig] ) -> tuple[AppiumConnection, Optional[AppiumClientConfig]]: - if not isinstance(command_executor): - return (command_executor, client_config) + """Return the pair of command executor and client config. + If the given command executor is a custome one, returned client config will + be None since the custom command executor has its own client config already. + The custom command executor's one will be prior than the given client config. + """ + if not isinstance(command_executor, str): + # Custom command executor will be prior than the given one. + return (command_executor, None) # command_executor is str if client_config is None: @@ -225,7 +231,7 @@ def __init__( options: Union[AppiumOptions, List[AppiumOptions], None] = None, client_config: Optional[AppiumClientConfig] = None, ): - command_executor, client_config = _get_client_config_and_connection( + command_executor, client_config = _get_remote_connection_and_client_config( command_executor=command_executor, client_config=client_config ) super().__init__( diff --git a/test/unit/webdriver/webdriver_test.py b/test/unit/webdriver/webdriver_test.py index e5d1baee..b4c11002 100644 --- a/test/unit/webdriver/webdriver_test.py +++ b/test/unit/webdriver/webdriver_test.py @@ -22,7 +22,7 @@ from appium.options.android import UiAutomator2Options from appium.webdriver.appium_connection import AppiumConnection from appium.webdriver.client_config import AppiumClientConfig -from appium.webdriver.webdriver import ExtensionBase, WebDriver, _get_client_config_and_connection +from appium.webdriver.webdriver import ExtensionBase, WebDriver, _get_remote_connection_and_client_config from test.helpers.constants import SERVER_URL_BASE from test.unit.helper.test_helper import ( android_w3c_driver, @@ -420,16 +420,41 @@ def test_extention_command_check(self): 'script': 'mobile: startActivity', } == get_httpretty_request_body(httpretty.last_request()) - def test_get_client_config_and_connection(self): - command_executor, client_config = _get_client_config_and_connection( + def test_get_client_config_and_connection_with_empty_config(self): + command_executor, client_config = _get_remote_connection_and_client_config( command_executor='http://127.0.0.1:4723', client_config=None ) assert isinstance(command_executor, AppiumConnection) - assert command_executor._url == 'http://127.0.0.1:4723' + assert command_executor._client_config == client_config assert isinstance(client_config, AppiumClientConfig) assert client_config.remote_server_addr == 'http://127.0.0.1:4723' + def test_get_client_config_and_connection(self): + command_executor, client_config = _get_remote_connection_and_client_config( + command_executor='http://127.0.0.1:4723', + client_config=AppiumClientConfig(remote_server_addr='http://127.0.0.1:4723/wd/hub'), + ) + + assert isinstance(command_executor, AppiumConnection) + # the client config in the command_executor is the given client config. + assert command_executor._client_config == client_config + assert isinstance(client_config, AppiumClientConfig) + assert client_config.remote_server_addr == 'http://127.0.0.1:4723/wd/hub' + + def test_get_client_config_and_connection_custom_appium_connection(self): + c_config = AppiumClientConfig(remote_server_addr='http://127.0.0.1:4723') + appium_connection = AppiumConnection(client_config=c_config) + + command_executor, client_config = _get_remote_connection_and_client_config( + command_executor=appium_connection, client_config=AppiumClientConfig(remote_server_addr='http://127.0.0.1:4723') + ) + + assert isinstance(command_executor, AppiumConnection) + # client config already defined in the command_executor will be userd. + assert command_executor._client_config != client_config + assert client_config is None + class SubWebDriver(WebDriver): def __init__(self, command_executor, options=None): From f56de0d164d021e4623859a2bb0717df75773d54 Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Tue, 11 Mar 2025 00:34:21 -0700 Subject: [PATCH 15/22] add comment --- appium/webdriver/webdriver.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/appium/webdriver/webdriver.py b/appium/webdriver/webdriver.py index f45f141c..61742991 100644 --- a/appium/webdriver/webdriver.py +++ b/appium/webdriver/webdriver.py @@ -184,7 +184,8 @@ def _get_remote_connection_and_client_config( The custom command executor's one will be prior than the given client config. """ if not isinstance(command_executor, str): - # Custom command executor will be prior than the given one. + # client config already defined in the custom command executor + # will be prior than the given one. return (command_executor, None) # command_executor is str From 299f283e7d9bed3791d5cebc2280dacc48aeb031 Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Sun, 16 Mar 2025 10:07:39 -0700 Subject: [PATCH 16/22] Update webdriver.py --- appium/webdriver/webdriver.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/appium/webdriver/webdriver.py b/appium/webdriver/webdriver.py index 61742991..85102abf 100644 --- a/appium/webdriver/webdriver.py +++ b/appium/webdriver/webdriver.py @@ -23,7 +23,6 @@ ) from selenium.webdriver.common.by import By from selenium.webdriver.remote.command import Command as RemoteCommand -from selenium.webdriver.remote.file_detector import FileDetector from selenium.webdriver.remote.remote_connection import RemoteConnection from typing_extensions import Self @@ -228,7 +227,6 @@ def __init__( self, command_executor: Union[str, AppiumConnection] = 'http://127.0.0.1:4723', extensions: Optional[List['WebDriver']] = None, - file_detector: Optional[FileDetector] = None, options: Union[AppiumOptions, List[AppiumOptions], None] = None, client_config: Optional[AppiumClientConfig] = None, ): @@ -237,7 +235,6 @@ def __init__( ) super().__init__( command_executor=command_executor, - file_detector=file_detector, options=options, locator_converter=AppiumLocatorConverter(), web_element_cls=MobileWebElement, From 5bf6cc612e48615080b62273d8c261290f70ffb0 Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Sun, 16 Mar 2025 16:52:38 -0700 Subject: [PATCH 17/22] Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- README.md | 2 +- appium/webdriver/webdriver.py | 2 +- test/unit/webdriver/webdriver_test.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index cd6ca42b..598bf658 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ For example, some changes in the Selenium binding could break the Appium client. ### Quick migration guide from v4 to v5 -- Please use `AppiumClientConfig` as `client_config` arguemnt in favor of client argument below +- Please use `AppiumClientConfig` as `client_config` argument in favor of client argument below - `keep_alive`, `direct_connection` and `strict_ssl` arguments. ```python SERVER_URL_BASE = 'http://127.0.0.1:4723' diff --git a/appium/webdriver/webdriver.py b/appium/webdriver/webdriver.py index 85102abf..16d27572 100644 --- a/appium/webdriver/webdriver.py +++ b/appium/webdriver/webdriver.py @@ -178,7 +178,7 @@ def _get_remote_connection_and_client_config( command_executor: Union[str, AppiumConnection], client_config: Optional[AppiumClientConfig] ) -> tuple[AppiumConnection, Optional[AppiumClientConfig]]: """Return the pair of command executor and client config. - If the given command executor is a custome one, returned client config will + If the given command executor is a custom one, returned client config will be None since the custom command executor has its own client config already. The custom command executor's one will be prior than the given client config. """ diff --git a/test/unit/webdriver/webdriver_test.py b/test/unit/webdriver/webdriver_test.py index b4c11002..443885d5 100644 --- a/test/unit/webdriver/webdriver_test.py +++ b/test/unit/webdriver/webdriver_test.py @@ -451,7 +451,7 @@ def test_get_client_config_and_connection_custom_appium_connection(self): ) assert isinstance(command_executor, AppiumConnection) - # client config already defined in the command_executor will be userd. + # client config already defined in the command_executor will be used. assert command_executor._client_config != client_config assert client_config is None From 72b2e4268484b5565508a4562a1597093f260673 Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Mon, 17 Mar 2025 01:40:17 -0700 Subject: [PATCH 18/22] update readme --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index cd6ca42b..4bb3ef1d 100644 --- a/README.md +++ b/README.md @@ -60,8 +60,8 @@ For example, some changes in the Selenium binding could break the Appium client. ### Quick migration guide from v4 to v5 -- Please use `AppiumClientConfig` as `client_config` arguemnt in favor of client argument below - - `keep_alive`, `direct_connection` and `strict_ssl` arguments. +- This change affecs only for a user who speficies `keep_alive`, `direct_connection` and `strict_ssl` arguments for `webdriver.Remote`: + - Please use `AppiumClientConfig` as `client_config` arguemnt as below: ```python SERVER_URL_BASE = 'http://127.0.0.1:4723' # before @@ -86,6 +86,7 @@ For example, some changes in the Selenium binding could break the Appium client. client_config=client_config ) ``` + - Note that you can keep using `webdriver.Remote(url, options=options, client_config=client_config)` format as well. Then, the `remote_server_addr` in `AppiumClientConfig` will prior than the `url` specified via `webdriver.Remote` - Use `http://127.0.0.1:4723` as the default server url instead of `http://127.0.0.1:4444/wd/hub` ### Quick migration guide from v3 to v4 From 8139b41feaba402181172c42fbd44fab2f82068e Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Mon, 17 Mar 2025 01:45:13 -0700 Subject: [PATCH 19/22] remove redundant command_executor check --- appium/webdriver/webdriver.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/appium/webdriver/webdriver.py b/appium/webdriver/webdriver.py index 61742991..b5e0816e 100644 --- a/appium/webdriver/webdriver.py +++ b/appium/webdriver/webdriver.py @@ -244,8 +244,7 @@ def __init__( client_config=client_config, ) - if hasattr(self, 'command_executor'): - self._add_commands() + self._add_commands() self.error_handler = MobileErrorHandler() From 25b5af069807ea794481f7c9513445292f8c3c8d Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Mon, 17 Mar 2025 02:04:49 -0700 Subject: [PATCH 20/22] modify a bit --- appium/webdriver/webdriver.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appium/webdriver/webdriver.py b/appium/webdriver/webdriver.py index 86269d73..7f8bf94b 100644 --- a/appium/webdriver/webdriver.py +++ b/appium/webdriver/webdriver.py @@ -175,7 +175,7 @@ def add_command(self) -> Tuple[str, str]: def _get_remote_connection_and_client_config( - command_executor: Union[str, AppiumConnection], client_config: Optional[AppiumClientConfig] + command_executor: Union[str, AppiumConnection], client_config: Optional[AppiumClientConfig] = None ) -> tuple[AppiumConnection, Optional[AppiumClientConfig]]: """Return the pair of command executor and client config. If the given command executor is a custom one, returned client config will From b727e1f10cf01d47e662d4899893546d0d48c8a6 Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Fri, 21 Mar 2025 19:59:25 +0900 Subject: [PATCH 21/22] fix typo and apply comment --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4bb3ef1d..e28ed7ea 100644 --- a/README.md +++ b/README.md @@ -60,8 +60,8 @@ For example, some changes in the Selenium binding could break the Appium client. ### Quick migration guide from v4 to v5 -- This change affecs only for a user who speficies `keep_alive`, `direct_connection` and `strict_ssl` arguments for `webdriver.Remote`: - - Please use `AppiumClientConfig` as `client_config` arguemnt as below: +- This change affects only for users who specify `keep_alive`, `direct_connection` and `strict_ssl` arguments for `webdriver.Remote`: + - Please use `AppiumClientConfig` as `client_config` argument similar to how it is specified below: ```python SERVER_URL_BASE = 'http://127.0.0.1:4723' # before @@ -86,7 +86,8 @@ For example, some changes in the Selenium binding could break the Appium client. client_config=client_config ) ``` - - Note that you can keep using `webdriver.Remote(url, options=options, client_config=client_config)` format as well. Then, the `remote_server_addr` in `AppiumClientConfig` will prior than the `url` specified via `webdriver.Remote` + - Note that you can keep using `webdriver.Remote(url, options=options, client_config=client_config)` format as well. + In such case the `remote_server_addr` argument of `AppiumClientConfig` constructor would have priority over the `url` argument of `webdriver.Remote` constructor. - Use `http://127.0.0.1:4723` as the default server url instead of `http://127.0.0.1:4444/wd/hub` ### Quick migration guide from v3 to v4 From f27054f8837e41ce4d987578810cf41ca659057c Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Fri, 21 Mar 2025 20:03:10 +0900 Subject: [PATCH 22/22] use new variable --- appium/webdriver/webdriver.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/appium/webdriver/webdriver.py b/appium/webdriver/webdriver.py index 7f8bf94b..9886c197 100644 --- a/appium/webdriver/webdriver.py +++ b/appium/webdriver/webdriver.py @@ -188,11 +188,11 @@ def _get_remote_connection_and_client_config( return (command_executor, None) # command_executor is str - if client_config is None: - # Do not keep None to avoid warnings in Selenium - # which can prevent with ClientConfig instance usage. - client_config = AppiumClientConfig(remote_server_addr=command_executor) - return (AppiumConnection(client_config=client_config), client_config) + + # Do not keep None to avoid warnings in Selenium + # which can prevent with ClientConfig instance usage. + new_client_config = AppiumClientConfig(remote_server_addr=command_executor) if client_config is None else client_config + return (AppiumConnection(client_config=new_client_config), new_client_config) class WebDriver(