Skip to content

Commit e03bf90

Browse files
committed
refactor[py]: Add type hints to options.py
- Added explicit type annotations to selenium.webdriver.common.options.py - Improved code clarity and static type checking - Ensured compatibility with modern type checkers like Pyright and Mypy
1 parent e992d25 commit e03bf90

File tree

1 file changed

+56
-39
lines changed

1 file changed

+56
-39
lines changed

py/selenium/webdriver/common/options.py

Lines changed: 56 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@
1919
from abc import ABCMeta
2020
from abc import abstractmethod
2121
from enum import Enum
22+
from typing import Any
2223
from typing import Optional
2324

24-
from selenium.common.exceptions import InvalidArgumentException
2525
from selenium.webdriver.common.proxy import Proxy
2626

2727

@@ -42,23 +42,28 @@ class PageLoadStrategy(str, Enum):
4242

4343

4444
class _BaseOptionsDescriptor:
45-
def __init__(self, name):
45+
def __init__(self, name: str):
4646
self.name = name
4747

48-
def __get__(self, obj, cls):
48+
def __get__(self, obj: object, cls: type[object]):
49+
if not isinstance(obj, BaseOptions):
50+
raise ValueError("Invalid object: Expected an instance of BaseOptions.")
4951
if self.name == "enableBidi":
5052
# whether BiDi is or will be enabled
51-
value = obj._caps.get("webSocketUrl")
53+
value = obj.capabilities.get("webSocketUrl")
5254
return value is True or isinstance(value, str)
5355
if self.name == "webSocketUrl":
5456
# Return socket url or None if not created yet
55-
value = obj._caps.get(self.name)
57+
value = obj.capabilities.get(self.name)
5658
return None if not isinstance(value, str) else value
5759
if self.name in ("acceptInsecureCerts", "strictFileInteractability", "setWindowRect", "se:downloadsEnabled"):
58-
return obj._caps.get(self.name, False)
59-
return obj._caps.get(self.name)
60+
return obj.capabilities.get(self.name, False)
61+
return obj.capabilities.get(self.name)
62+
63+
def __set__(self, obj: object, value: Any):
64+
if not isinstance(obj, BaseOptions):
65+
raise ValueError("Invalid object: Expected an instance of BaseOptions.")
6066

61-
def __set__(self, obj, value):
6267
if self.name == "enableBidi":
6368
obj.set_capability("webSocketUrl", value)
6469
else:
@@ -72,17 +77,20 @@ class _PageLoadStrategyDescriptor:
7277
:param strategy: the strategy corresponding to a document readiness state
7378
"""
7479

75-
def __init__(self, name):
80+
def __init__(self, name: str):
7681
self.name = name
7782

78-
def __get__(self, obj, cls):
79-
return obj._caps.get(self.name)
83+
def __get__(self, obj: object, cls: type[object]):
84+
if not isinstance(obj, BaseOptions):
85+
raise ValueError("Invalid object: Expected an instance of BaseOptions.")
86+
return obj.capabilities.get(self.name)
8087

81-
def __set__(self, obj, value):
82-
if value in ("normal", "eager", "none"):
83-
obj.set_capability(self.name, value)
84-
else:
88+
def __set__(self, obj: object, value: str):
89+
if not isinstance(obj, BaseOptions):
90+
raise ValueError("Invalid object: Expected an instance of BaseOptions.")
91+
if value not in ("normal", "eager", "none"):
8592
raise ValueError("Strategy can only be one of the following: normal, eager, none")
93+
obj.set_capability(self.name, value)
8694

8795

8896
class _UnHandledPromptBehaviorDescriptor:
@@ -95,20 +103,23 @@ class _UnHandledPromptBehaviorDescriptor:
95103
:returns: Values for implicit timeout, pageLoad timeout and script timeout if set (in milliseconds)
96104
"""
97105

98-
def __init__(self, name):
106+
def __init__(self, name: str):
99107
self.name = name
100108

101-
def __get__(self, obj, cls):
102-
return obj._caps.get(self.name)
109+
def __get__(self, obj: object, cls: type[object]):
110+
if not isinstance(obj, BaseOptions):
111+
raise ValueError("Invalid object: Expected an instance of BaseOptions.")
112+
return obj.capabilities.get(self.name)
103113

104-
def __set__(self, obj, value):
105-
if value in ("dismiss", "accept", "dismiss and notify", "accept and notify", "ignore"):
106-
obj.set_capability(self.name, value)
107-
else:
114+
def __set__(self, obj: object, value: str):
115+
if not isinstance(obj, BaseOptions):
116+
raise ValueError("Invalid object: Expected an instance of BaseOptions.")
117+
if value not in ("dismiss", "accept", "dismiss and notify", "accept and notify", "ignore"):
108118
raise ValueError(
109119
"Behavior can only be one of the following: dismiss, accept, dismiss and notify, "
110120
"accept and notify, ignore"
111121
)
122+
obj.set_capability(self.name, value)
112123

113124

114125
class _TimeoutsDescriptor:
@@ -120,13 +131,17 @@ class _TimeoutsDescriptor:
120131
:returns: Values for implicit timeout, pageLoad timeout and script timeout if set (in milliseconds)
121132
"""
122133

123-
def __init__(self, name):
134+
def __init__(self, name: str):
124135
self.name = name
125136

126-
def __get__(self, obj, cls):
127-
return obj._caps.get(self.name)
137+
def __get__(self, obj: object, cls: type[object]):
138+
if not isinstance(obj, BaseOptions):
139+
raise ValueError("Invalid object: Expected an instance of BaseOptions.")
140+
return obj.capabilities.get(self.name)
128141

129-
def __set__(self, obj, value):
142+
def __set__(self, obj: object, value: dict[str, Any]):
143+
if not isinstance(obj, BaseOptions):
144+
raise ValueError("Invalid object: Expected an instance of BaseOptions.")
130145
if all(x in ("implicit", "pageLoad", "script") for x in value.keys()):
131146
obj.set_capability(self.name, value)
132147
else:
@@ -136,17 +151,19 @@ def __set__(self, obj, value):
136151
class _ProxyDescriptor:
137152
""":Returns: Proxy if set, otherwise None."""
138153

139-
def __init__(self, name):
154+
def __init__(self, name: str):
140155
self.name = name
141156

142-
def __get__(self, obj, cls):
157+
def __get__(self, obj: object, cls: type[object]):
158+
if not isinstance(obj, BaseOptions):
159+
raise ValueError("Invalid object: Expected an instance of BaseOptions.")
143160
return obj._proxy
144161

145-
def __set__(self, obj, value):
146-
if not isinstance(value, Proxy):
147-
raise InvalidArgumentException("Only Proxy objects can be passed in.")
162+
def __set__(self, obj: object, value: Proxy):
163+
if not isinstance(obj, BaseOptions):
164+
raise ValueError("Invalid object: Expected an instance of BaseOptions.")
148165
obj._proxy = value
149-
obj._caps[self.name] = value.to_capabilities()
166+
obj.capabilities[self.name] = value.to_capabilities()
150167

151168

152169
class BaseOptions(metaclass=ABCMeta):
@@ -443,7 +460,7 @@ class BaseOptions(metaclass=ABCMeta):
443460
def __init__(self) -> None:
444461
super().__init__()
445462
self._caps = self.default_capabilities
446-
self._proxy = None
463+
self._proxy: Proxy | None = None
447464
self.set_capability("pageLoadStrategy", PageLoadStrategy.normal)
448465
self.mobile_options = None
449466
self._ignore_local_proxy = False
@@ -452,7 +469,7 @@ def __init__(self) -> None:
452469
def capabilities(self):
453470
return self._caps
454471

455-
def set_capability(self, name, value) -> None:
472+
def set_capability(self, name: Any, value: Any) -> None:
456473
"""Sets a capability."""
457474
self._caps[name] = value
458475

@@ -476,12 +493,12 @@ def enable_mobile(
476493
self.mobile_options["androidDeviceSerial"] = device_serial
477494

478495
@abstractmethod
479-
def to_capabilities(self):
496+
def to_capabilities(self) -> dict[Any, Any]:
480497
"""Convert options into capabilities dictionary."""
481498

482499
@property
483500
@abstractmethod
484-
def default_capabilities(self):
501+
def default_capabilities(self) -> dict[Any, Any]:
485502
"""Return minimal capabilities necessary as a dictionary."""
486503

487504
def ignore_local_proxy_environment_variables(self) -> None:
@@ -497,14 +514,14 @@ class ArgOptions(BaseOptions):
497514

498515
def __init__(self) -> None:
499516
super().__init__()
500-
self._arguments = []
517+
self._arguments: list[Any] = []
501518

502519
@property
503520
def arguments(self):
504521
""":Returns: A list of arguments needed for the browser."""
505522
return self._arguments
506523

507-
def add_argument(self, argument) -> None:
524+
def add_argument(self, argument: Any) -> None:
508525
"""Adds an argument to the list.
509526
510527
:Args:
@@ -533,5 +550,5 @@ def to_capabilities(self):
533550
return self._caps
534551

535552
@property
536-
def default_capabilities(self):
553+
def default_capabilities(self) -> dict[Any, Any]:
537554
return {}

0 commit comments

Comments
 (0)