You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A few specific rules are ignored in pyproject.toml because they seemed overly pedantic.
Adds some missing type annotations
Updates several type annotations to use newer 3.10+ syntax instead of Unions
Removes the ./selenium/types.py type definition file and moves explicit type annotations into their respective modules. This file only contained a few types that weren't shared across many files and it's not really necessary to maintain a central file for this.
Makes test assertions more clear
Converts old string formatting to f-strings
🔄 Types of changes
Cleanup (formatting, renaming)
Bugfixes
PR Type
Enhancement, Tests
Description
Remove centralized selenium/types.py and inline type definitions
Update Python 3.10+ syntax: replace Union with | operator
cgoldberg
changed the title
WIP - [py] Add new ruff lint rules and fix violations
[py] Add new ruff lint rules, fix violations and type annotations
Dec 28, 2025
Generic: Robust Error Handling and Edge Case Management
Objective: Ensure comprehensive error handling that provides meaningful context and graceful degradation
Status: Assertion not raised: The exception handler constructs an AssertionError but does not raise it, allowing a failing click to incorrectly pass the test and silently hide the error.
Referred Code
try:
link.click()
exceptMoveTargetOutOfBoundsExceptionase:
AssertionError(f"Should not be out of bounds: {e.msg}")
Objective: To prevent the leakage of sensitive system information through error messages while providing sufficient detail for internal debugging.
Status: Path disclosure error: The raised exception includes local filesystem paths and environment-derived values (WEBDRIVER, HTML_ROOT), which may disclose internal details depending on where/ how this test utility is executed and surfaced.
✅ Raise the AssertionErrorSuggestion Impact:The commit fixed the same underlying issue (the test silently passing) by replacing the non-raised AssertionError expression with an explicit failure via pytest.fail(...), ensuring the test fails when the exception is caught.
code diff:
except MoveTargetOutOfBoundsException as e:
- AssertionError(f"Should not be out of bounds: {e.msg}")+ pytest.fail(f"Should not be out of bounds: {e.msg}")
Add a raise statement before AssertionError to ensure the test fails correctly when an exception is caught.
except MoveTargetOutOfBoundsException as e:
- AssertionError(f"Should not be out of bounds: {e.msg}")+ raise AssertionError(f"Should not be out of bounds: {e.msg}")
[Suggestion processed]
Suggestion importance[1-10]: 9
__
Why: The suggestion correctly identifies a critical bug where a test would silently pass instead of failing because the AssertionError was not raised.
High
High-level
Re-evaluate removing the centralized types file
The removal of selenium/types.py has caused duplication of complex type definitions. Consider restoring a centralized types file to improve maintainability.
# In py/selenium/webdriver/chrome/service.pyclassService(service.ChromiumService):
def__init__(
self,
...,
log_output: int|str|IO[Any] |None=None,
...
) ->None: ...
# In py/selenium/webdriver/edge/service.pyclassService(service.ChromiumService):
def__init__(
self,
...,
log_output: int|str|IO[Any] |None=None,
...
) ->None: ...
# ... and 4 other service files with the same duplicated type
After:
# In a restored py/selenium/types.pyfromtypingimportIO, AnySubprocessStdAlias=int|str|IO[Any]
# In py/selenium/webdriver/chrome/service.pyfromselenium.typesimportSubprocessStdAliasclassService(service.ChromiumService):
def__init__(
self,
...,
log_output: SubprocessStdAlias|None=None,
...
) ->None: ...
# In py/selenium/webdriver/edge/service.pyfromselenium.typesimportSubprocessStdAliasclassService(service.ChromiumService):
def__init__(
self,
...,
log_output: SubprocessStdAlias|None=None,
...
) ->None: ...
# ... and other service files use the alias
Suggestion importance[1-10]: 6
__
Why: The suggestion correctly identifies that removing selenium/types.py introduced duplicated complex type hints across multiple files, which impacts maintainability. This is a valid design-level concern.
Low
Learned best practice
✅ Validate caller-provided input shapeSuggestion Impact:The constructor was updated to return early when `raw` is None and to raise a TypeError if `raw` is not a dict, preventing attribute errors from calling `.get` on non-mapping inputs. A type annotation `raw: dict | None` was also added.
code diff:
- def __init__(self, raw=None):+ def __init__(self, raw: dict | None = None):
"""Creates a new Proxy.
Args:
raw: Raw proxy data. If None, default class values are used.
"""
- if raw:- if raw.get("proxyType"):- self.proxy_type = ProxyType.load(raw["proxyType"])- if raw.get("httpProxy"):- self.http_proxy = raw["httpProxy"]- if raw.get("noProxy"):- self.no_proxy = raw["noProxy"]- if raw.get("proxyAutoconfigUrl"):- self.proxy_autoconfig_url = raw["proxyAutoconfigUrl"]- if raw.get("sslProxy"):- self.sslProxy = raw["sslProxy"]- if raw.get("autodetect"):- self.auto_detect = raw["autodetect"]- if raw.get("socksProxy"):- self.socks_proxy = raw["socksProxy"]- if raw.get("socksUsername"):- self.socks_username = raw["socksUsername"]- if raw.get("socksPassword"):- self.socks_password = raw["socksPassword"]- if raw.get("socksVersion"):- self.socks_version = raw["socksVersion"]+ if raw is None:+ return+ if not isinstance(raw, dict):+ raise TypeError(f"`raw` must be a dict, got {type(raw)}")+ if raw.get("proxyType"):+ self.proxy_type = ProxyType.load(raw["proxyType"])+ if raw.get("httpProxy"):+ self.http_proxy = raw["httpProxy"]+ if raw.get("noProxy"):+ self.no_proxy = raw["noProxy"]+ if raw.get("proxyAutoconfigUrl"):+ self.proxy_autoconfig_url = raw["proxyAutoconfigUrl"]+ if raw.get("sslProxy"):+ self.sslProxy = raw["sslProxy"]+ if raw.get("autodetect"):+ self.auto_detect = raw["autodetect"]+ if raw.get("socksProxy"):+ self.socks_proxy = raw["socksProxy"]+ if raw.get("socksUsername"):+ self.socks_username = raw["socksUsername"]+ if raw.get("socksPassword"):+ self.socks_password = raw["socksPassword"]+ if raw.get("socksVersion"):+ self.socks_version = raw["socksVersion"]
raw.get(...) assumes raw is a mapping; add a type/structure guard (or normalize input) and raise a clear error for invalid types to avoid runtime attribute errors.
def __init__(self, raw=None):
"""Creates a new Proxy.
Args:
raw: Raw proxy data. If None, default class values are used.
"""
- if raw:- if raw.get("proxyType"):- self.proxy_type = ProxyType.load(raw["proxyType"])- if raw.get("httpProxy"):- self.http_proxy = raw["httpProxy"]- if raw.get("noProxy"):- self.no_proxy = raw["noProxy"]- if raw.get("proxyAutoconfigUrl"):- self.proxy_autoconfig_url = raw["proxyAutoconfigUrl"]- if raw.get("sslProxy"):- self.sslProxy = raw["sslProxy"]- if raw.get("autodetect"):- self.auto_detect = raw["autodetect"]- if raw.get("socksProxy"):- self.socks_proxy = raw["socksProxy"]- if raw.get("socksUsername"):- self.socks_username = raw["socksUsername"]- if raw.get("socksPassword"):- self.socks_password = raw["socksPassword"]- if raw.get("socksVersion"):- self.socks_version = raw["socksVersion"]+ if raw is None:+ return+ if not isinstance(raw, dict):+ raise TypeError(f"`raw` must be a dict, got {type(raw)!r}")+ if raw.get("proxyType"):+ self.proxy_type = ProxyType.load(raw["proxyType"])+ if raw.get("httpProxy"):+ self.http_proxy = raw["httpProxy"]+ if raw.get("noProxy"):+ self.no_proxy = raw["noProxy"]+ if raw.get("proxyAutoconfigUrl"):+ self.proxy_autoconfig_url = raw["proxyAutoconfigUrl"]+ if raw.get("sslProxy"):+ self.sslProxy = raw["sslProxy"]+ if raw.get("autodetect"):+ self.auto_detect = raw["autodetect"]+ if raw.get("socksProxy"):+ self.socks_proxy = raw["socksProxy"]+ if raw.get("socksUsername"):+ self.socks_username = raw["socksUsername"]+ if raw.get("socksPassword"):+ self.socks_password = raw["socksPassword"]+ if raw.get("socksVersion"):+ self.socks_version = raw["socksVersion"]+
[To ensure code accuracy, apply this suggestion manually]
Suggestion importance[1-10]: 6
__
Why:
Relevant best practice - Add explicit validation/guards at integration boundaries before using caller-provided inputs.
Low
General
✅ Refactor string formatting for better readabilitySuggestion Impact:The commit replaced the multiline `"abcd{}...".format(...) # noqa: UP032` construction with a `keys_to_send` list and `element.send_keys("".join(keys_to_send))`, matching the suggested readability refactor and removing the noqa.
Why: The suggestion correctly identifies an opportunity to refactor a complex str.format() call, improving readability and eliminating the need for a noqa comment.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
User description
💥 What does this PR do?
This is a general cleanup for the Python bindings:
Adds new rules and expands existing rules for the Python linter (ruff) and fixes all violations:
A few specific rules are ignored in
pyproject.tomlbecause they seemed overly pedantic.Adds some missing type annotations
Updates several type annotations to use newer 3.10+ syntax instead of Unions
Removes the
./selenium/types.pytype definition file and moves explicit type annotations into their respective modules. This file only contained a few types that weren't shared across many files and it's not really necessary to maintain a central file for this.Makes test assertions more clear
Converts old string formatting to f-strings
🔄 Types of changes
PR Type
Enhancement, Tests
Description
Remove centralized
selenium/types.pyand inline type definitionsUpdate Python 3.10+ syntax: replace
Unionwith|operatorAdd ruff lint rules (pydocstyle, pytest-style, pyupgrade, ruff-specific)
Fix pytest fixture scopes and improve test assertions
Modernize string formatting and simplify conditional logic
Diagram Walkthrough
File Walkthrough
17 files
Remove centralized type definitions fileInline SubprocessStdAlias type definitionInline SubprocessStdAlias type definitionRemove Union import, inline AnyDevice typeUpdate string formatting to f-stringSimplify dictionary checks with .get() methodInline SubprocessStdAlias, modernize Union syntaxInline AnyKey type definitionInline SubprocessStdAlias type definitionInline SubprocessStdAlias type definitionInline SubprocessStdAlias type definitionInline AnyKey type definitionModernize Union syntax and string formattingModernize Union syntax to pipe operatorInline WaitExcTypes, modernize Union syntaxRemove unused Union import, modernize f-stringsRemove Python 2 compatibility imports, modernize error handling1 files
Remove noqa comments from imports20 files
Remove fixture scope, fix pytest assertionsFix pytest parametrize tuple syntaxUpdate string formatting to f-stringSplit compound assertions into separate statementsUpdate string formatting to f-stringModernize string formattingConvert tuple to list in parametrizeSplit compound assertions into separate statementsAdd noqa comment for pyupgrade ruleFix variable naming and simplify assertionsSplit compound assertions into separate statementsSplit compound assertions into separate statementsRemove empty parentheses from fixture decoratorRemove empty parentheses from fixture decoratorUpdate string formatting to f-stringSplit compound assertion into separate statementsChange fixture from yield to returnChange fixture from yield to returnRemove fixture scope, change yield to returnFix variable naming and simplify assertions1 files
Expand ruff lint rules and add ignore exceptions