[py] cleanup for ruff b904 raise from - #18030
Conversation
`_get_cdp_details` re-raised as WebDriverException without a cause, hiding which capabilities key (`goog:chromeOptions` or `ms:edgeOptions`) returned None, so chain the AttributeError. `execute_script` suppresses the KeyError instead -- it carried nothing the message did not already say -- but the script id it did carry is now part of the message, so a caller with several pinned scripts can tell which one is missing.
The sibling raise a few lines down already passed `from err`; this branch is reached from the same EACCES handler and should report the same cause.
`clean_driver` collapsed two unrelated failures into one message: no --driver passed (TypeError from subscripting None) and a --driver that SupportedDrivers does not know (AttributeError from getattr). The second case reported "This test requires a --driver to be specified", which is untrue. argparse `choices=drivers` currently makes the second case unreachable, but only for as long as `drivers` and SupportedDrivers stay in sync, and the merged handler gave no hint when they drift. Split the two, and name the offending driver in the message. The other two fixtures do not call getattr, so their message is accurate; they just suppress the context.
…erver Causes that carry information are chained with `from err`. Two are suppressed instead: the LookupError from a ContextVar carries nothing beyond "unset", and the ConnectionRefusedError in Server.start is the success path -- it means the port was free -- so it would only mislead in a startup-timeout traceback.
Part of SeleniumHQ#17989. All 17 findings are addressed by the preceding commits, so the carve-out can go and the rule keeps new ones from landing.
`AddonFormatError` has no `__init__`, so the second positional argument never
became `__traceback__` -- it just landed in `args`, and with two args
`Exception.__str__` prints the whole tuple. Every add-on parsing failure ended
its traceback with a memory address:
AddonFormatError: ("[Errno 2] ... install.rdf", <traceback object at 0x7f..>)
The pattern dates to 983d5b2 (2014), a port of Python 2's three-argument
`raise`, which was the only way to keep the original traceback back then. The
preceding commit added `from e`, so `__cause__` now carries the cause properly
and the argument is redundant as well as noisy. It also kept every frame of
the caught exception alive for as long as the AddonFormatError was referenced.
This changes `str(exc)` and `exc.args` for the two raises that passed it. The
class is not re-exported from any package `__init__`, and the third raise in
the same file already passed a single argument.
`import sys` goes with them; nothing else in the file used it.
Qodo reviews are paused for this user.Troubleshooting steps vary by plan Learn more → On a Teams plan? Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center? |
There was a problem hiding this comment.
🔵 Needs a closer look
Add regression coverage for the intentional exception-message and chaining changes.
Pull request overview
This PR completes the Python Ruff B904 cleanup, making exception chaining deliberate and correcting Firefox add-on error formatting.
Changes:
- Adds explicit exception chaining or suppression.
- Improves script, CDP, service, and fixture diagnostics.
- Enables B904 enforcement and fixes
AddonFormatErrorconstruction.
File summaries
| File | Reviewed change |
|---|---|
py/selenium/webdriver/remote/webdriver.py |
Updates script and CDP exception handling. [P2] Add regression coverage for message and chaining behavior. |
py/selenium/webdriver/remote/server.py |
Chains port errors and suppresses expected startup context. |
py/selenium/webdriver/firefox/firefox_profile.py |
Corrects add-on exception construction and chaining. [P2] Add coverage for the resulting error text. |
py/selenium/webdriver/common/utils.py |
Adds causes to free-port errors. |
py/selenium/webdriver/common/service.py |
Chains service startup errors. |
py/pyproject.toml |
Removes the Ruff B904 exclusion. |
py/private/cdp.py |
Adds explicit CDP exception chaining. |
py/conftest.py |
Clarifies driver validation and exception handling. |
Review details
Suppressed comments (2)
py/selenium/webdriver/firefox/firefox_profile.py:295
- [P2] The
AddonFormatErrorconstruction is an intentional user-visible behavior change, but there is no test covering the resulting message. Add a unit test (ideally covering both this path and the XML-parse path below) that verifiesstr(exc)is the underlying error text rather than the old two-argument tuple representation.
raise AddonFormatError(str(e)) from e
py/selenium/webdriver/remote/webdriver.py:611
- [P2] Add a regression test for the intentional message and chaining change here.
test_calling_unpinned_script_causes_errorcurrently checks only the exception type, so it would not catch droppingscript.idfrom the message or reintroducing the implicitKeyErrorcontext that thisfrom Noneis meant to suppress.
raise JavascriptException(f"Pinned script could not be found: {script.id}") from None
- Files reviewed: 8/8 changed files
- Comments generated: 0
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
cgoldberg
left a comment
There was a problem hiding this comment.
LGTM. I like exception chaining
|
@cgoldberg thanks for your review |
🔗 Related Issues
💥 What does this PR do?
fixes leftovers in #17989 tranche 2
🔧 Implementation Notes
B904 has no autofix, and the mechanical reading of it (
from erreverywhere)is wrong in five places, so each of the 17 sites was decided individually:
from errwhere the cause carries information,from Nonewhere it does not —an unset
ContextVar'sLookupError, and theConnectionRefusedErrorinServer.start, which is the success signal (the port was free).Two sites needed more than a
from:execute_scriptmoved the script id intothe message rather than chain a
KeyErrorwhose whole content is that id, andclean_driversplit two failures that shared one (untrue for theAttributeErrorpath) message.py/pyproject.tomlis last so every commit stays green under//py:ruff-checkand the series bisects. TheAddonFormatErrorcleanup is aseparate commit placed after it: the second positional argument was a Python 2
three-argument-
raiseport thatfrom enow supersedes — it was never__traceback__, and with two argsException.__str__printed a memory addressinto every add-on parsing failure.
🤖 AI assistance
💡 Additional Considerations
🔄 Types of changes