Skip to content

mypy error "Incompatible return value type" on webdriver.find_element #1147

Open

Description

@bandophahita

Mypy errors on the fact that appium.webdriver.WebDriver.find_element isn't overridden but indeed returns a different WebElement.

Reproducible Code

# no need to actually run this code, just send it through MyPy to see the error.

from appium.webdriver.common.appiumby import AppiumBy

from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from appium.webdriver import Remote
    from appium.webdriver.webelement import WebElement

def find_element(driver: Remote) -> WebElement:
    # should get a mypy error on next line
    return driver.find_element(AppiumBy.ACCESSIBILITY_ID, "demo button")


def find_elements(driver: Remote) -> WebElement:
    # should get a mypy error on next line
    return driver.find_elements(AppiumBy.ACCESSIBILITY_ID, "demo confetti")

mypy output:

mypy .
screenpy_appium/target.py:89: error: Incompatible return value type (got "selenium.webdriver.remote.webelement.WebElement", expected "appium.webdriver.webelement.WebElement")  [return-value]
screenpy_appium/target.py:98: error: Incompatible return value type (got "list[selenium.webdriver.remote.webelement.WebElement]", expected "list[appium.webdriver.webelement.WebElement]")  [return-value]
Found 2 errors in 1 file (checked 35 source files)

Solution

Annotations need to be added to appium.webdriver.WebDriver

class WebDriver(
    webdriver.Remote,
    ...
):
    if TYPE_CHECKING:
        def find_element(self, by=By.ID, value: Optional[str] = None) -> MobileWebElement:
            ...
        def find_elements(self, by=By.ID, value: Optional[str] = None) -> list[MobileWebElement]:
            ...

Activity

  1. KazuCocoa commented on Jul 24, 2025

    @KazuCocoa
    Member

    Hm, let me check. Here returns appium.webdriver.webelement.WebElement as their types:

    from typing import TYPE_CHECKING, Dict, List, Protocol, Union
    if TYPE_CHECKING:
    from appium.webdriver.webelement import WebElement
    class CanFindElements(Protocol):
    def find_element(self, by: str, value: Union[str, Dict, None] = None) -> 'WebElement': ...
    def find_elements(self, by: str, value: Union[str, Dict, None] = None) -> List['WebElement']: ...

  2. KazuCocoa commented on Jul 24, 2025

    @KazuCocoa
    Member

    What about this?
    #1148

  3. KazuCocoa commented on Jul 24, 2025

    @KazuCocoa
    Member

    Please try out 5.1.2

  4. bandophahita commented on Jul 25, 2025

    @bandophahita
    Author

    The inheritance of the protocol in this manner doesn't result in mypy understanding that the methods return the appium subclassed WebElement. As a result, the sample code in this issue still errors in mypy. (though, for a moment it seemed like clever way to solve the problem)

    In this case, I think you have to include the TYPE_CHECKING logic.

  5. KazuCocoa commented on Aug 2, 2025

    @KazuCocoa
    Member

    Hm, it looks like Protocol

    from typing import TYPE_CHECKING, Dict, List, Protocol, Union
    if TYPE_CHECKING:
    from appium.webdriver.webelement import WebElement
    class CanFindElements(Protocol):
    def find_element(self, by: str, value: Union[str, Dict, None] = None) -> 'WebElement': ...
    def find_elements(self, by: str, value: Union[str, Dict, None] = None) -> List['WebElement']: ...
    needs some adjustment for mypy. I'll explore/learn a bit more

  6. KazuCocoa commented on Aug 2, 2025

    @KazuCocoa
    Member
  7. KazuCocoa commented on Aug 7, 2025

    @KazuCocoa
    Member

    5.1.3 has the change. cc @bandophahita

    #1153

    It has a change like you suggested. Protocol usage for mypy needed some work, so the suggested one was the simplest so far.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions