Skip to content

[🐛 Bug]: [py] Mypy error - WebDriverWait.driver has attribute #15693

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
MarcelWilson opened this issue May 2, 2025 · 10 comments · Fixed by #15705
Closed

[🐛 Bug]: [py] Mypy error - WebDriverWait.driver has attribute #15693

MarcelWilson opened this issue May 2, 2025 · 10 comments · Fixed by #15705
Labels
C-py Python Bindings good first issue Good first issue for new contributors to start with I-defect Something is not working as intended R-help wanted Issues looking for contributions

Comments

@MarcelWilson
Copy link
Contributor

MarcelWilson commented May 2, 2025

Description

The following error from mypy occurs for WebDriverWait.__repr__

error: Item "WebElement" of the upper bound "WebDriver | WebElement" of type variable "D" has no attribute "session_id" [union-attr]

Explanation:
If you pass a WebElement into WebDriverWait, the repr will not be able to properly access the session_id attribute. Mypy is detecting this.

    def __repr__(self):
        return f'<{type(self).__module__}.{type(self).__name__} (session="{self._driver.session_id}")>'

My guess is there likely needs to be additional logic to access driver from WebElement.parent in those cases, or session_id needs to be exposed as an attribute of WebElement.

Reproducible Code

def __repr__(self):
        return f'<{type(self).__module__}.{type(self).__name__} (session="{self._driver.session_id}")>'
@MarcelWilson MarcelWilson added A-needs-triaging A Selenium member will evaluate this soon! I-defect Something is not working as intended labels May 2, 2025
@selenium-ci
Copy link
Member

@MarcelWilson, thank you for creating this issue. We will troubleshoot it as soon as we can.

Selenium Triage Team: remember to follow the Triage Guide

@github-actions github-actions bot added the C-py Python Bindings label May 2, 2025
@cgoldberg
Copy link
Contributor

Not surprising. I just ran our Mypy configuration across the codebase and we currently have 120 errors in 30 files! :)

If by chance you are interested in cleaning up our type checking, a PR would be very welcomed (If not, I'll get to it eventually).

You can run the Mypy job with:

tox -c py/tox.ini -e mypy

@cgoldberg cgoldberg added R-help wanted Issues looking for contributions and removed A-needs-triaging A Selenium member will evaluate this soon! labels May 3, 2025
@selenium-ci
Copy link
Member

This issue is looking for contributors.

Please comment below or reach out to us through our IRC/Slack/Matrix channels if you are interested.

@cgoldberg cgoldberg changed the title [🐛 Bug]: WebDriverWait.driver has attribute [🐛 Bug]: [py[ Mypy error - WebDriverWait.driver has attribute May 3, 2025
@cgoldberg cgoldberg changed the title [🐛 Bug]: [py[ Mypy error - WebDriverWait.driver has attribute [🐛 Bug]: [py] Mypy error - WebDriverWait.driver has attribute May 3, 2025
@shbenzer shbenzer added the good first issue Good first issue for new contributors to start with label May 3, 2025
@cgoldberg
Copy link
Contributor

For the larger issue: #15697

@MarcelWilson
Copy link
Contributor Author

If by chance you are interested in cleaning up our type checking, a PR would be very welcomed (If not, I'll get to it eventually).

I wouldn't mind giving it a go. The question then becomes about approach. Is it wise to expose the sessionid in WebElement?
Or is it preferred to do a check in the WebDriverWait and pull out the driver from there?

@cgoldberg
Copy link
Contributor

You need access to it from whichever class the __repr__ is on, right?

I don't have the code in front of me at the moment, but... Is driver referenced anywhere else in that module? If not, I'm not sure it belongs there at all.

@MarcelWilson
Copy link
Contributor Author

MarcelWilson commented May 6, 2025

Under the hood, WebDriverWait needs a WebDriver to pass into the method.

end_time = time.monotonic() + self._timeout
while True:
try:
value = method(self._driver)
if value:
return value
except self._ignored_exceptions as exc:
screen = getattr(exc, "screen", None)
stacktrace = getattr(exc, "stacktrace", None)
if time.monotonic() > end_time:
break
time.sleep(self._poll)
raise TimeoutException(message, screen, stacktrace)

However, it also accepts passing in WebElement since they also have the ability to make calls like find_element - as seen in several expected_condition functions.

def _predicate(driver: WebDriverOrWebElement):
try:
return _element_if_visible(driver.find_element(*locator))
except StaleElementReferenceException:
return False
return _predicate

The only real issue here is when WebDriver.__repr__ tries to access the attribute of session_id which currently only exists on the remote.WebDriver.

I see a couple of possibilities here:

  1. WebElement could expose session_id as a property. Since it already utilizes the attribute for it's own __repr__ it would be a small step

    def __repr__(self):
    return f'<{type(self).__module__}.{type(self).__name__} (session="{self._parent.session_id}", element="{self._id}")>'

  2. WebDriverWait would need to pull out the session_id from both objects in separate logic.

if driver:
    ...
elif element:
    ...

My hunch is the first approach makes the most sense (also has the smallest code change). But I fear this opinion may be biased as a user.

MarcelWilson pushed a commit to bandophahita/selenium that referenced this issue May 6, 2025
@MarcelWilson
Copy link
Contributor Author

I tried to submit a PR with the code change but it appears to have been automatically closed. I'm not sure I understand the objection. Maybe you can do something with the submission.

@cgoldberg
Copy link
Contributor

I just re-opened your PR... Our bot is a little aggressive with closing things :)

I'll review it later today. Thanks.

@titusfortner
Copy link
Member

Our bot is a little aggressive with closing things

When I close something instead of letting a bot do it, I'm mean
When a bot closes something and I re-open it, I'm helpful

😂

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-py Python Bindings good first issue Good first issue for new contributors to start with I-defect Something is not working as intended R-help wanted Issues looking for contributions
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants