Skip to content

Commit 80b13e8

Browse files
authored
[py] Fix remaining mypy errors and enable CI for type checking (#16837)
1 parent 0ff9728 commit 80b13e8

25 files changed

+151
-107
lines changed

.github/workflows/ci-python.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ jobs:
5252
pip install tox
5353
- name: Run type checking
5454
run: |
55-
tox -c py/tox.ini || true
55+
tox -c py/tox.ini
5656
env:
5757
TOXENV: typecheck
5858

py/BUILD.bazel

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -314,11 +314,14 @@ py_wheel(
314314
python_requires = ">=3.10",
315315
python_tag = "py3",
316316
requires = [
317-
"urllib3[socks]>=2.5.0,<3.0",
317+
"certifi>=2025.10.5",
318318
"trio>=0.31.0,<1.0",
319319
"trio-websocket>=0.12.2,<1.0",
320-
"certifi>=2025.10.5",
320+
"trio-typing>=0.10.0",
321+
"types-certifi>=2021.10.8.3",
322+
"types-urllib3>=1.26.25.14",
321323
"typing_extensions>=4.15.0,<5.0",
324+
"urllib3[socks]>=2.6.0,<3.0",
322325
"websocket-client>=1.8.0,<2.0",
323326
],
324327
strip_path_prefixes = [

py/pyproject.toml

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,14 @@ classifiers = [
2626
"Programming Language :: Python :: 3.14",
2727
]
2828
dependencies = [
29-
"urllib3[socks]>=2.6.0,<3.0",
29+
"certifi>=2025.10.5",
3030
"trio>=0.31.0,<1.0",
3131
"trio-websocket>=0.12.2,<1.0",
32-
"certifi>=2025.10.5",
32+
"trio-typing>=0.10.0",
33+
"types-certifi>=2021.10.8.3",
34+
"types-urllib3>=1.26.25.14",
3335
"typing_extensions>=4.15.0,<5.0",
36+
"urllib3[socks]>=2.6.0,<3.0",
3437
"websocket-client>=1.8.0,<2.0",
3538
]
3639

@@ -48,10 +51,6 @@ lint = [
4851
]
4952
typecheck = [
5053
"mypy==1.19.1",
51-
"types-urllib3==1.26.25.14",
52-
"types-certifi==2021.10.8.3",
53-
"trio-typing==0.10.0",
54-
"trio-websocket>=0.12.2,<1.0",
5554
]
5655
validate = [
5756
"validate-pyproject==0.24.1",
@@ -111,14 +110,11 @@ testpaths = ["test"]
111110
# mypy global options
112111
[tool.mypy]
113112
exclude = "selenium/webdriver/common/devtools"
114-
# The aim in future here is we would be able to turn (most) of these flags on, however the typing technical
115-
# debt is quite colossal right now. For now we should maybe get everything working with the config here
116-
# then look at going after partially or completely untyped defs as a phase-2.
117-
files = "selenium"
113+
# The aim in future is we would be able to turn (most) of these flags on
118114
# warn about per-module sections in the config file that do not match any files processed.
119115
warn_unused_configs = true
120116
# disallows subclassing of typing.Any.
121-
disallow_subclassing_any = false
117+
disallow_subclassing_any = true
122118
# disallow usage of generic types that do not specify explicit type parameters.
123119
disallow_any_generics = false
124120
# disallow calling functions without type annotations from functions that have type annotations.
@@ -132,7 +128,7 @@ check_untyped_defs = false
132128
# reports an error whenever a function with type annotations is decorated with a decorator without annotations.
133129
disallow_untyped_decorators = false
134130
# changes the treatment of arguments with a default value of None by not implicitly making their type `typing.Optional`.
135-
no_implicit_optional = false
131+
no_implicit_optional = true
136132
# warns about casting an expression to it's inferred type.
137133
warn_redundant_casts = true
138134
# warns about unneeded `# type: ignore` comments.

py/requirements.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,11 @@ sortedcontainers==2.4.0
5151
tomli==2.3.0
5252
tox==4.32.0
5353
trio==0.32.0
54+
trio-typing==0.10.0
5455
trio-websocket==0.12.2
5556
twine==6.2.0
57+
types-certifi==2021.10.8.3
58+
types-urllib3==1.26.25.14
5659
typing_extensions==4.15.0
5760
urllib3[socks]==2.6.2
5861
virtualenv==20.35.4

py/requirements_lock.txt

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44
#
55
# bazel run //py:requirements.update
66
#
7+
async-generator==1.10 \
8+
--hash=sha256:01c7bf666359b4967d2cda0000cc2e4af16a0ae098cbffcb8472fb9e8ad6585b \
9+
--hash=sha256:6ebb3d106c12920aaae42ccb6f787ef5eefdcdd166ea3d628fa8476abe712144
10+
# via trio-typing
711
attrs==25.4.0 \
812
--hash=sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11 \
913
--hash=sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373
@@ -360,6 +364,7 @@ importlib-metadata==8.7.1 \
360364
# via
361365
# -r py/requirements.txt
362366
# keyring
367+
# trio-typing
363368
inflection==0.5.1 \
364369
--hash=sha256:1a29730d366e996aaacffb2f1f1cb9593dc38e2ddd30c91250c6dde09ea9b417 \
365370
--hash=sha256:f38b2b640938a4f35ade69ac3d053042959b62a0f1076a5bbaa1b9526605a8a2
@@ -420,6 +425,10 @@ more-itertools==10.8.0 \
420425
# -r py/requirements.txt
421426
# jaraco-classes
422427
# jaraco-functools
428+
mypy-extensions==1.1.0 \
429+
--hash=sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505 \
430+
--hash=sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558
431+
# via trio-typing
423432
nh3==0.3.2 \
424433
--hash=sha256:019ecbd007536b67fdf76fab411b648fb64e2257ca3262ec80c3425c24028c80 \
425434
--hash=sha256:03d617e5c8aa7331bd2659c654e021caf9bba704b109e7b2b28b039a00949fe5 \
@@ -466,6 +475,7 @@ packaging==25.0 \
466475
# pyproject-api
467476
# pytest
468477
# tox
478+
# trio-typing
469479
# twine
470480
platformdirs==4.5.1 \
471481
--hash=sha256:61d5cdcc6065745cdd94f0f878977f8de9437be93de97c1c12f853c9c0cdcbda \
@@ -640,7 +650,12 @@ trio==0.32.0 \
640650
# via
641651
# -r py/requirements.txt
642652
# pytest-trio
653+
# trio-typing
643654
# trio-websocket
655+
trio-typing==0.10.0 \
656+
--hash=sha256:065ee684296d52a8ab0e2374666301aec36ee5747ac0e7a61f230250f8907ac3 \
657+
--hash=sha256:6d0e7ec9d837a2fe03591031a172533fbf4a1a95baf369edebfc51d5a49f0264
658+
# via -r py/requirements.txt
644659
trio-websocket==0.12.2 \
645660
--hash=sha256:22c72c436f3d1e264d0910a3951934798dcc5b00ae56fc4ee079d46c7cf20fae \
646661
--hash=sha256:df605665f1db533f4a386c94525870851096a223adcb97f72a07e8b4beba45b6
@@ -649,6 +664,14 @@ twine==6.2.0 \
649664
--hash=sha256:418ebf08ccda9a8caaebe414433b0ba5e25eb5e4a927667122fbe8f829f985d8 \
650665
--hash=sha256:e5ed0d2fd70c9959770dce51c8f39c8945c574e18173a7b81802dab51b4b75cf
651666
# via -r py/requirements.txt
667+
types-certifi==2021.10.8.3 \
668+
--hash=sha256:72cf7798d165bc0b76e1c10dd1ea3097c7063c42c21d664523b928e88b554a4f \
669+
--hash=sha256:b2d1e325e69f71f7c78e5943d410e650b4707bb0ef32e4ddf3da37f54176e88a
670+
# via -r py/requirements.txt
671+
types-urllib3==1.26.25.14 \
672+
--hash=sha256:229b7f577c951b8c1b92c1bc2b2fdb0b49847bd2af6d1cc2a2e3dd340f3bda8f \
673+
--hash=sha256:9683bbb7fb72e32bfe9d2be6e04875fbe1b3eeec3cbb4ea231435aa7fd6b4f0e
674+
# via -r py/requirements.txt
652675
typing-extensions==4.15.0 \
653676
--hash=sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466 \
654677
--hash=sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548
@@ -657,6 +680,7 @@ typing-extensions==4.15.0 \
657680
# cryptography
658681
# exceptiongroup
659682
# tox
683+
# trio-typing
660684
# virtualenv
661685
urllib3[socks]==2.6.2 \
662686
--hash=sha256:016f9c98bb7e98085cb2b4b17b87d2c702975664e4f060c6532e64d1c1a5e797 \

py/selenium/webdriver/chrome/remote_connection.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ def __init__(
2828
self,
2929
remote_server_addr: str,
3030
keep_alive: bool = True,
31-
ignore_proxy: bool | None = False,
31+
ignore_proxy: bool = False,
3232
client_config: ClientConfig | None = None,
3333
) -> None:
3434
super().__init__(

py/selenium/webdriver/chrome/webdriver.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
# specific language governing permissions and limitations
1616
# under the License.
1717

18-
1918
from selenium.webdriver.chrome.options import Options
2019
from selenium.webdriver.chrome.service import Service
2120
from selenium.webdriver.chromium.webdriver import ChromiumDriver
@@ -36,7 +35,7 @@ def __init__(
3635
Starts the service and then creates new instance of chrome driver.
3736
3837
Args:
39-
options: This takes an instance of ChromeOptions.
38+
options: Instance of Options.
4039
service: Service object for handling the browser driver if you need to pass extra details.
4140
keep_alive: Whether to configure ChromeRemoteConnection to use HTTP keep-alive.
4241
"""

py/selenium/webdriver/chromium/remote_connection.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def __init__(
2626
vendor_prefix: str,
2727
browser_name: str,
2828
keep_alive: bool = True,
29-
ignore_proxy: bool | None = False,
29+
ignore_proxy: bool = False,
3030
client_config: ClientConfig | None = None,
3131
) -> None:
3232
client_config = client_config or ClientConfig(

py/selenium/webdriver/chromium/webdriver.py

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
# specific language governing permissions and limitations
1616
# under the License.
1717

18-
1918
from selenium.webdriver.chromium.options import ChromiumOptions
2019
from selenium.webdriver.chromium.remote_connection import ChromiumRemoteConnection
2120
from selenium.webdriver.chromium.service import ChromiumService
@@ -29,8 +28,8 @@ class ChromiumDriver(LocalWebDriver):
2928

3029
def __init__(
3130
self,
32-
browser_name: str | None = None,
33-
vendor_prefix: str | None = None,
31+
browser_name: str,
32+
vendor_prefix: str,
3433
options: ChromiumOptions | None = None,
3534
service: ChromiumService | None = None,
3635
keep_alive: bool = True,
@@ -40,17 +39,17 @@ def __init__(
4039
Args:
4140
browser_name: Browser name used when matching capabilities.
4241
vendor_prefix: Company prefix to apply to vendor-specific WebDriver extension commands.
43-
options: This takes an instance of ChromiumOptions.
42+
options: Instance of ChromiumOptions.
4443
service: Service object for handling the browser driver if you need to pass extra details.
4544
keep_alive: Whether to configure ChromiumRemoteConnection to use HTTP keep-alive.
4645
"""
4746
self.service = service if service else ChromiumService()
48-
options = options if options else ChromiumOptions()
47+
self.options = options if options else ChromiumOptions()
4948

50-
finder = DriverFinder(self.service, options)
49+
finder = DriverFinder(self.service, self.options)
5150
if finder.get_browser_path():
52-
options.binary_location = finder.get_browser_path()
53-
options.browser_version = None
51+
self.options.binary_location = finder.get_browser_path()
52+
self.options.browser_version = None
5453

5554
self.service.path = self.service.env_path() or finder.get_driver_path()
5655
self.service.start()
@@ -60,11 +59,11 @@ def __init__(
6059
browser_name=browser_name,
6160
vendor_prefix=vendor_prefix,
6261
keep_alive=keep_alive,
63-
ignore_proxy=options._ignore_local_proxy,
62+
ignore_proxy=self.options._ignore_local_proxy,
6463
)
6564

6665
try:
67-
super().__init__(command_executor=executor, options=options)
66+
super().__init__(command_executor=executor, options=self.options)
6867
except Exception:
6968
self.quit()
7069
raise

py/selenium/webdriver/common/bidi/cdp.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,8 @@ def _handle_event(self, data: dict):
300300
data: event as a JSON dictionary
301301
"""
302302
global devtools
303+
if devtools is None:
304+
raise RuntimeError("CDP devtools module not loaded. Call import_devtools() first.")
303305
event = devtools.util.parse_json_event(data)
304306
logger.debug("Received event: %s", event)
305307
to_remove = set()
@@ -424,6 +426,8 @@ async def open_session(self, target_id) -> AsyncIterator[CdpSession]:
424426
async def connect_session(self, target_id) -> "CdpSession":
425427
"""Returns a new :class:`CdpSession` connected to the specified target."""
426428
global devtools
429+
if devtools is None:
430+
raise RuntimeError("CDP devtools module not loaded. Call import_devtools() first.")
427431
session_id = await self.execute(devtools.target.attach_to_target(target_id, True))
428432
session = CdpSession(self.ws, session_id, target_id)
429433
self.sessions[session_id] = session
@@ -435,6 +439,8 @@ async def _reader_task(self):
435439
Dispatches responses to commands and events to listeners.
436440
"""
437441
global devtools
442+
if devtools is None:
443+
raise RuntimeError("CDP devtools module not loaded. Call import_devtools() first.")
438444
while True:
439445
try:
440446
message = await self.ws.get_message()

0 commit comments

Comments
 (0)