Skip to content

[py] simplify error check in check_response for w3c#12255

Closed
KazuCocoa wants to merge 19 commits intoSeleniumHQ:trunkfrom
KazuCocoa:py-w3c-error
Closed

[py] simplify error check in check_response for w3c#12255
KazuCocoa wants to merge 19 commits intoSeleniumHQ:trunkfrom
KazuCocoa:py-w3c-error

Conversation

@KazuCocoa
Copy link
Copy Markdown
Contributor

@KazuCocoa KazuCocoa commented Jun 25, 2023

Thanks for contributing to Selenium!
A PR well described will help maintainers to quickly review and merge it

In Appium dev, I observed Python client did not handle exceptions properly. https://github.com/appium/python-client/pull/868/files#r1199231346 For example when a response had unknown method value in the error key, it raised a general WebDriverException. It looks like python client had a case that did not handle w3c response properly.

After a few investigation, probably the main reason was this python binding gives extra value for check_response. Maybe we can simplify it.

Description

in this pr, I have parsed error response by checking the error key as same as Appium Python client does after the above error case. This is should be the same as what currently Ruby binding also does.

So,

  1. get value from the response
  2. get error from the 1
  3. get the class mapping with the error value in 2
  4. Raise the error

With this PR, python client will not refer to status in the response. Ruby binding also does this already, and selenium v4 no longer support old protocol, I think this behavior should be ok for you.

I also noticed the input of check_response got nested value such as

{'status': 500, 'value': '{"value":{"error":"session not created","message":"session not created: This version of ChromeDriver only supports Chrome version 97\\nCurrent browser version is 114.0.5735.133 with binary path /Applications/Google Chrome.app/Contents/MacOS/Google Chrome","stacktrace":"0   chromedriver                        0x000000010c995e69 chromedriver + 5160553\\n1   chromedriver                        0x000000010c920593 chromedriver + 4679059\\n2   chromedriver                        0x000000010c4d42c8 chromedriver + 172744\\n3   chromedriver                        0x000000010c4faa93 chromedriver + 330387\\n4   chromedriver                        0x000000010c4f6636 chromedriver + 312886\\n5   chromedriver                        0x000000010c4f2cf6 chromedriver + 298230\\n6   chromedriver                        0x000000010c52d423 chromedriver + 537635\\n7   chromedriver                        0x000000010c527123 chromedriver + 512291\\n8   chromedriver                        0x000000010c4fcdce chromedriver + 339406\\n9   chromedriver                        0x000000010c4fe105 chromedriver + 344325\\n10  chromedriver                        0x000000010c95123e chromedriver + 4878910\\n11  chromedriver                        0x000000010c968d17 chromedriver + 4975895\\n12  chromedriver                        0x000000010c96ea3f chromedriver + 4999743\\n13  chromedriver                        0x000000010c96961a chromedriver + 4978202\\n14  chromedriver                        0x000000010c945bb1 chromedriver + 4832177\\n15  chromedriver                        0x000000010c985fd8 chromedriver + 5095384\\n16  chromedriver                        0x000000010c986161 chromedriver + 5095777\\n17  chromedriver                        0x000000010c99d2a8 chromedriver + 5190312\\n18  libsystem_pthread.dylib             0x00007ff8198a24e1 _pthread_start + 125\\n19  libsystem_pthread.dylib             0x00007ff81989df6b thread_start + 15\\n"}}'}
Traceback (most recent call last):

for probably backward compatibility. So, the response value has extra value for some reason. I guess for backward compatibility in the past.

In this PR, I have changed the behavior to pass only one value key to the check_response so that the check_response can expect only W3C error format as the argument. (test_handle_errors_better test code addresses this point.)

I also removed unused exception for w3c such as IME stuff.

Motivation and Context

I'd like to cleanup error handling for W3C format to help Appium Python client's implementation to reduce duplication code for both.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist

  • I have read the contributing document.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have added tests to cover my changes.
  • All new and existing tests passed.

if not status or status == ErrorCode.SUCCESS:

payload_dict = response
if type(response) != dict:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

prefer using isinstance

from selenium.common.exceptions import ElementNotInteractableException
from selenium.common.exceptions import ElementNotSelectableException
from selenium.common.exceptions import ElementNotVisibleException
from selenium.common.exceptions import ImeActivationFailedException
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this change makes it breaking

from selenium.common.exceptions import WebDriverException


class ExceptionMapping:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By removing this logic we make the client 100% incompatible with the legacy JWP protocol.

In scope of Appium I can guarantee that the server only supports W3C one and we do not care about JWP support anymore. I cannot guarantee this is the case in Selenium world though. Selenium java client, for example, still supports both JWP and W3C protocols, for example.

Leaving this decision up to client maintainers.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, need feedback at the point. I saw W3C flag removals in the past so I thought this client was removing old protocol behaviors but could be wrong

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Selenium does not support JWP, but there are still various pieces of JWP-only code left that haven't been removed. If it doesn't apply to w3c we want it gone. :)

LOGGER.debug(f"Remote response: data={data} | headers={response.headers}")
try:
if 300 <= statuscode < 304:
return self._request("GET", response.headers.get("location", None))
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this code looks suspicious to me as it might potentially fall into an endless recursion. Usually clients (including urllib3, which is this code base on) handle such stuff automatically with some default number of allowed redirect retries to avoid the above recursion issue.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was actually testing this out earlier this week for Sauce-related reasons... The default number of allowed redirects is 3, and that is actually what happens. You can set remote URL to http://demo.cyotek.com/features/redirectlooptest.php and see that you only get 3. I'm not sure what this loop does, I just know it didn't result in infinite retries.

@codecov-commenter
Copy link
Copy Markdown

Codecov Report

Patch coverage: 78.31% and project coverage change: +0.26 🎉

Comparison is base (cb2560d) 57.28% compared to head (ea1f26e) 57.54%.

❗ Current head ea1f26e differs from pull request most recent head d205577. Consider uploading reports for the commit d205577 to get more accurate results

❗ Your organization is not using the GitHub App Integration. As a result you may experience degraded service beginning May 15th. Please install the Github App Integration for your organization. Read more.

Additional details and impacted files
@@            Coverage Diff             @@
##            trunk   #12255      +/-   ##
==========================================
+ Coverage   57.28%   57.54%   +0.26%     
==========================================
  Files          86       86              
  Lines        5487     5432      -55     
  Branches      226      231       +5     
==========================================
- Hits         3143     3126      -17     
+ Misses       2118     2075      -43     
- Partials      226      231       +5     
Impacted Files Coverage Δ
py/selenium/common/__init__.py 100.00% <ø> (ø)
py/selenium/common/exceptions.py 100.00% <ø> (ø)
py/selenium/webdriver/remote/remote_connection.py 54.91% <0.00%> (+0.52%) ⬆️
py/selenium/webdriver/remote/webdriver.py 40.04% <0.00%> (-0.19%) ⬇️
py/selenium/webdriver/remote/errorhandler.py 90.47% <85.52%> (+18.79%) ⬆️

☔ View full report in Codecov by Sentry.
📢 Do you have feedback about the report comment? Let us know in this issue.

@titusfortner
Copy link
Copy Markdown
Member

Somehow you broke the cookie_test and the linter is also being particular.

@KazuCocoa
Copy link
Copy Markdown
Contributor Author

The cookies test returned non-w3c error response (according to the error result). I have added the pattern as a test case https://github.com/SeleniumHQ/selenium/pull/12255/files#diff-16a7f3559108027005862f77d542ca48d5dc188f7325ca4df1b73984f7de86c5R246-R256 for now to handle the case as well.

"""Error codes defined in the WebDriver wire protocol."""

# Keep in sync with org.openqa.selenium.remote.ErrorCodes and errorcodes.h
SUCCESS = 0
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need to use the Error codes at all anymore

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the ErrorCode class from errorhandler.py. in py/selenium/webdriver/remote/remote_connection.py, i have left 0 and 15 instead. The status probably safe to remove, but I'm not so confident to include the change in this PR since the value also has value (vanilla webdriver response) key. That may need to tweak properly at the same time, I think.

@KazuCocoa KazuCocoa marked this pull request as draft June 30, 2023 07:40
@KazuCocoa KazuCocoa marked this pull request as ready for review June 30, 2023 07:55
@KazuCocoa
Copy link
Copy Markdown
Contributor Author

Updated. It would be appreciated to run the CI, thanks

@KazuCocoa KazuCocoa marked this pull request as draft June 30, 2023 16:27
@KazuCocoa KazuCocoa marked this pull request as ready for review July 1, 2023 08:32
@KazuCocoa
Copy link
Copy Markdown
Contributor Author

fixed the lint issue after applying the trunk

@KazuCocoa KazuCocoa requested a review from AutomatedTester July 3, 2023 03:19
@KazuCocoa KazuCocoa marked this pull request as draft July 15, 2023 05:31
@KazuCocoa
Copy link
Copy Markdown
Contributor Author

Hm.., tox seems good in Codespace:

@KazuCocoa ➜ /workspaces/selenium (py-w3c-error) $ tox -c py/tox.ini
docs: commands[0] /workspaces/selenium/py> sphinx-build -b html -d ../build/doctrees docs/source ../build/docs/api/py
Running Sphinx v1.8.2
loading pickled environment... done
building [mo]: targets for 0 po files that are out of date
building [html]: targets for 0 source files that are out of date
updating environment: [] 0 added, 4 changed, 0 removed
reading sources... [100%] webdriver_remote/selenium.webdriver.remote.webelement                                                                                                                                                                                                                                                                                                                   
looking for now-outdated files... none found
pickling environment... done
checking consistency... done
preparing documents... done
writing output... [100%] webdriver_remote/selenium.webdriver.remote.webelement                                                                                                                                                                                                                                                                                                                    
generating indices... genindex py-modindex
highlighting module code... [100%] typing                                                                                                                                                                                                                                                                                                                                                         
writing additional pages... search
copying static files... done
copying extra files... done
dumping search index in English (code: en) ... done
dumping object inventory... done
build succeeded.

The HTML pages are in ../build/docs/api/py.
docs: OK ✔ in 5.62 seconds
.pkg: _optional_hooks /workspaces/selenium/py> python /usr/local/python/3.10.8/lib/python3.10/site-packages/pyproject_api/_backend.py True setuptools.build_meta __legacy__
.pkg: get_requires_for_build_sdist /workspaces/selenium/py> python /usr/local/python/3.10.8/lib/python3.10/site-packages/pyproject_api/_backend.py True setuptools.build_meta __legacy__
.pkg: get_requires_for_build_wheel /workspaces/selenium/py> python /usr/local/python/3.10.8/lib/python3.10/site-packages/pyproject_api/_backend.py True setuptools.build_meta __legacy__
.pkg: prepare_metadata_for_build_wheel /workspaces/selenium/py> python /usr/local/python/3.10.8/lib/python3.10/site-packages/pyproject_api/_backend.py True setuptools.build_meta __legacy__
.pkg: build_sdist /workspaces/selenium/py> python /usr/local/python/3.10.8/lib/python3.10/site-packages/pyproject_api/_backend.py True setuptools.build_meta __legacy__
flake8: install_package /workspaces/selenium/py> python -I -m pip install --force-reinstall --no-deps /workspaces/selenium/py/.tox/.tmp/package/7/selenium-4.10.0.tar.gz
flake8: OK ✔ in 3.16 seconds
isort: install_package /workspaces/selenium/py> python -I -m pip install --force-reinstall --no-deps /workspaces/selenium/py/.tox/.tmp/package/8/selenium-4.10.0.tar.gz
.pkg: _exit /workspaces/selenium/py> python /usr/local/python/3.10.8/lib/python3.10/site-packages/pyproject_api/_backend.py True setuptools.build_meta __legacy__
  docs: OK (5.62=setup[0.19]+cmd[5.43] seconds)
  flake8: OK (3.16 seconds)
  isort: OK (1.99 seconds)
  congratulations :) (12.34 seconds)
@KazuCocoa ➜ /workspaces/selenium (py-w3c-error) $ 

@KazuCocoa KazuCocoa marked this pull request as ready for review July 15, 2023 06:02
@github-actions github-actions bot added the Stale label Apr 20, 2024
@github-actions github-actions bot closed this May 4, 2024
@titusfortner titusfortner added J-stale Applied to issues that become stale, and eventually closed. and removed Stale labels Mar 30, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

J-stale Applied to issues that become stale, and eventually closed.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants