Skip to content

Commit 0e29929

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 7ad32c6 commit 0e29929

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):
@@ -421,7 +438,7 @@ class BaseOptions(metaclass=ABCMeta):
421438
def __init__(self) -> None:
422439
super().__init__()
423440
self._caps = self.default_capabilities
424-
self._proxy = None
441+
self._proxy: Proxy | None = None
425442
self.set_capability("pageLoadStrategy", PageLoadStrategy.normal)
426443
self.mobile_options = None
427444
self._ignore_local_proxy = False
@@ -430,7 +447,7 @@ def __init__(self) -> None:
430447
def capabilities(self):
431448
return self._caps
432449

433-
def set_capability(self, name, value) -> None:
450+
def set_capability(self, name: Any, value: Any) -> None:
434451
"""Sets a capability."""
435452
self._caps[name] = value
436453

@@ -454,12 +471,12 @@ def enable_mobile(
454471
self.mobile_options["androidDeviceSerial"] = device_serial
455472

456473
@abstractmethod
457-
def to_capabilities(self):
474+
def to_capabilities(self) -> dict[Any, Any]:
458475
"""Convert options into capabilities dictionary."""
459476

460477
@property
461478
@abstractmethod
462-
def default_capabilities(self):
479+
def default_capabilities(self) -> dict[Any, Any]:
463480
"""Return minimal capabilities necessary as a dictionary."""
464481

465482
def ignore_local_proxy_environment_variables(self) -> None:
@@ -475,14 +492,14 @@ class ArgOptions(BaseOptions):
475492

476493
def __init__(self) -> None:
477494
super().__init__()
478-
self._arguments = []
495+
self._arguments: list[Any] = []
479496

480497
@property
481498
def arguments(self):
482499
""":Returns: A list of arguments needed for the browser."""
483500
return self._arguments
484501

485-
def add_argument(self, argument) -> None:
502+
def add_argument(self, argument: Any) -> None:
486503
"""Adds an argument to the list.
487504
488505
:Args:
@@ -511,5 +528,5 @@ def to_capabilities(self):
511528
return self._caps
512529

513530
@property
514-
def default_capabilities(self):
531+
def default_capabilities(self) -> dict[Any, Any]:
515532
return {}

0 commit comments

Comments
 (0)