Skip to content

Commit 6e0c875

Browse files
ShauryaDushtcgoldbergnavin772
authored
[py] Fix : Mypy type annotation errors - 2 (#15848)
* [py] Fix : Mypy type annotation errors * Reverted changes in py\selenium\webdriver\common\bidi\browser.py * [py] Fix: two more files * Remove browser.py from PR * make changes as per bidi spec --------- Co-authored-by: Corey Goldberg <1113081+cgoldberg@users.noreply.github.com> Co-authored-by: Navin Chandra <navinchandra772@gmail.com>
1 parent abd2160 commit 6e0c875

File tree

3 files changed

+170
-56
lines changed

3 files changed

+170
-56
lines changed

py/selenium/webdriver/common/action_chains.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@ def pause(self, seconds: float | int) -> ActionChains:
273273
"""Pause all inputs for the specified duration in seconds."""
274274

275275
self.w3c_actions.pointer_action.pause(seconds)
276-
self.w3c_actions.key_action.pause(seconds)
276+
self.w3c_actions.key_action.pause(int(seconds))
277277

278278
return self
279279

py/selenium/webdriver/common/bidi/browsing_context.py

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

18-
from typing import Optional, Union
18+
from typing import Any, Callable, Optional, Union
1919

2020
from selenium.webdriver.common.bidi.common import command_builder
2121

@@ -66,12 +66,23 @@ def from_json(cls, json: dict) -> "NavigationInfo":
6666
-------
6767
NavigationInfo: A new instance of NavigationInfo.
6868
"""
69-
return cls(
70-
context=json.get("context"),
71-
navigation=json.get("navigation"),
72-
timestamp=json.get("timestamp"),
73-
url=json.get("url"),
74-
)
69+
context = json.get("context")
70+
if context is None or not isinstance(context, str):
71+
raise ValueError("context is required and must be a string")
72+
73+
navigation = json.get("navigation")
74+
if navigation is not None and not isinstance(navigation, str):
75+
raise ValueError("navigation must be a string")
76+
77+
timestamp = json.get("timestamp")
78+
if timestamp is None or not isinstance(timestamp, int) or timestamp < 0:
79+
raise ValueError("timestamp is required and must be a non-negative integer")
80+
81+
url = json.get("url")
82+
if url is None or not isinstance(url, str):
83+
raise ValueError("url is required and must be a string")
84+
85+
return cls(context, navigation, timestamp, url)
7586

7687

7788
class BrowsingContextInfo:
@@ -82,10 +93,10 @@ def __init__(
8293
context: str,
8394
url: str,
8495
children: Optional[list["BrowsingContextInfo"]],
96+
client_window: str,
97+
user_context: str,
8598
parent: Optional[str] = None,
86-
user_context: Optional[str] = None,
8799
original_opener: Optional[str] = None,
88-
client_window: Optional[str] = None,
89100
):
90101
self.context = context
91102
self.url = url
@@ -108,17 +119,49 @@ def from_json(cls, json: dict) -> "BrowsingContextInfo":
108119
BrowsingContextInfo: A new instance of BrowsingContextInfo.
109120
"""
110121
children = None
111-
if json.get("children") is not None:
112-
children = [BrowsingContextInfo.from_json(child) for child in json.get("children")]
122+
raw_children = json.get("children")
123+
if raw_children is not None:
124+
if not isinstance(raw_children, list):
125+
raise ValueError("children must be a list if provided")
126+
127+
children = []
128+
for child in raw_children:
129+
if not isinstance(child, dict):
130+
raise ValueError(f"Each child must be a dictionary, got {type(child)}")
131+
children.append(BrowsingContextInfo.from_json(child))
132+
133+
context = json.get("context")
134+
if context is None or not isinstance(context, str):
135+
raise ValueError("context is required and must be a string")
136+
137+
url = json.get("url")
138+
if url is None or not isinstance(url, str):
139+
raise ValueError("url is required and must be a string")
140+
141+
parent = json.get("parent")
142+
if parent is not None and not isinstance(parent, str):
143+
raise ValueError("parent must be a string if provided")
144+
145+
user_context = json.get("userContext")
146+
if user_context is None or not isinstance(user_context, str):
147+
raise ValueError("userContext is required and must be a string")
148+
149+
original_opener = json.get("originalOpener")
150+
if original_opener is not None and not isinstance(original_opener, str):
151+
raise ValueError("originalOpener must be a string if provided")
152+
153+
client_window = json.get("clientWindow")
154+
if client_window is None or not isinstance(client_window, str):
155+
raise ValueError("clientWindow is required and must be a string")
113156

114157
return cls(
115-
context=json.get("context"),
116-
url=json.get("url"),
158+
context=context,
159+
url=url,
117160
children=children,
118-
parent=json.get("parent"),
119-
user_context=json.get("userContext"),
120-
original_opener=json.get("originalOpener"),
121-
client_window=json.get("clientWindow"),
161+
client_window=client_window,
162+
user_context=user_context,
163+
parent=parent,
164+
original_opener=original_opener,
122165
)
123166

124167

@@ -148,12 +191,32 @@ def from_json(cls, json: dict) -> "DownloadWillBeginParams":
148191
-------
149192
DownloadWillBeginParams: A new instance of DownloadWillBeginParams.
150193
"""
194+
context = json.get("context")
195+
if context is None or not isinstance(context, str):
196+
raise ValueError("context is required and must be a string")
197+
198+
navigation = json.get("navigation")
199+
if navigation is not None and not isinstance(navigation, str):
200+
raise ValueError("navigation must be a string")
201+
202+
timestamp = json.get("timestamp")
203+
if timestamp is None or not isinstance(timestamp, int) or timestamp < 0:
204+
raise ValueError("timestamp is required and must be a non-negative integer")
205+
206+
url = json.get("url")
207+
if url is None or not isinstance(url, str):
208+
raise ValueError("url is required and must be a string")
209+
210+
suggested_filename = json.get("suggestedFilename")
211+
if suggested_filename is None or not isinstance(suggested_filename, str):
212+
raise ValueError("suggestedFilename is required and must be a string")
213+
151214
return cls(
152-
context=json.get("context"),
153-
navigation=json.get("navigation"),
154-
timestamp=json.get("timestamp"),
155-
url=json.get("url"),
156-
suggested_filename=json.get("suggestedFilename"),
215+
context=context,
216+
navigation=navigation,
217+
timestamp=timestamp,
218+
url=url,
219+
suggested_filename=suggested_filename,
157220
)
158221

159222

@@ -186,12 +249,32 @@ def from_json(cls, json: dict) -> "UserPromptOpenedParams":
186249
-------
187250
UserPromptOpenedParams: A new instance of UserPromptOpenedParams.
188251
"""
252+
context = json.get("context")
253+
if context is None or not isinstance(context, str):
254+
raise ValueError("context is required and must be a string")
255+
256+
handler = json.get("handler")
257+
if handler is None or not isinstance(handler, str):
258+
raise ValueError("handler is required and must be a string")
259+
260+
message = json.get("message")
261+
if message is None or not isinstance(message, str):
262+
raise ValueError("message is required and must be a string")
263+
264+
type_value = json.get("type")
265+
if type_value is None or not isinstance(type_value, str):
266+
raise ValueError("type is required and must be a string")
267+
268+
default_value = json.get("defaultValue")
269+
if default_value is not None and not isinstance(default_value, str):
270+
raise ValueError("defaultValue must be a string if provided")
271+
189272
return cls(
190-
context=json.get("context"),
191-
handler=json.get("handler"),
192-
message=json.get("message"),
193-
type=json.get("type"),
194-
default_value=json.get("defaultValue"),
273+
context=context,
274+
handler=handler,
275+
message=message,
276+
type=type_value,
277+
default_value=default_value,
195278
)
196279

197280

@@ -222,11 +305,27 @@ def from_json(cls, json: dict) -> "UserPromptClosedParams":
222305
-------
223306
UserPromptClosedParams: A new instance of UserPromptClosedParams.
224307
"""
308+
context = json.get("context")
309+
if context is None or not isinstance(context, str):
310+
raise ValueError("context is required and must be a string")
311+
312+
accepted = json.get("accepted")
313+
if accepted is None or not isinstance(accepted, bool):
314+
raise ValueError("accepted is required and must be a boolean")
315+
316+
type_value = json.get("type")
317+
if type_value is None or not isinstance(type_value, str):
318+
raise ValueError("type is required and must be a string")
319+
320+
user_text = json.get("userText")
321+
if user_text is not None and not isinstance(user_text, str):
322+
raise ValueError("userText must be a string if provided")
323+
225324
return cls(
226-
context=json.get("context"),
227-
accepted=json.get("accepted"),
228-
type=json.get("type"),
229-
user_text=json.get("userText"),
325+
context=context,
326+
accepted=accepted,
327+
type=type_value,
328+
user_text=user_text,
230329
)
231330

232331

@@ -253,9 +352,17 @@ def from_json(cls, json: dict) -> "HistoryUpdatedParams":
253352
-------
254353
HistoryUpdatedParams: A new instance of HistoryUpdatedParams.
255354
"""
355+
context = json.get("context")
356+
if context is None or not isinstance(context, str):
357+
raise ValueError("context is required and must be a string")
358+
359+
url = json.get("url")
360+
if url is None or not isinstance(url, str):
361+
raise ValueError("url is required and must be a string")
362+
256363
return cls(
257-
context=json.get("context"),
258-
url=json.get("url"),
364+
context=context,
365+
url=url,
259366
)
260367

261368

@@ -278,7 +385,11 @@ def from_json(cls, json: dict) -> "BrowsingContextEvent":
278385
-------
279386
BrowsingContextEvent: A new instance of BrowsingContextEvent.
280387
"""
281-
return cls(event_class=json.get("event_class"), **json)
388+
event_class = json.get("event_class")
389+
if event_class is None or not isinstance(event_class, str):
390+
raise ValueError("event_class is required and must be a string")
391+
392+
return cls(event_class=event_class, **json)
282393

283394

284395
class BrowsingContext:
@@ -339,7 +450,7 @@ def capture_screenshot(
339450
-------
340451
str: The Base64-encoded screenshot.
341452
"""
342-
params = {"context": context, "origin": origin}
453+
params: dict[str, Any] = {"context": context, "origin": origin}
343454
if format is not None:
344455
params["format"] = format
345456
if clip is not None:
@@ -383,7 +494,7 @@ def create(
383494
-------
384495
str: The browsing context ID of the created navigable.
385496
"""
386-
params = {"type": type}
497+
params: dict[str, Any] = {"type": type}
387498
if reference_context is not None:
388499
params["referenceContext"] = reference_context
389500
if background is not None:
@@ -411,7 +522,7 @@ def get_tree(
411522
-------
412523
List[BrowsingContextInfo]: A list of browsing context information.
413524
"""
414-
params = {}
525+
params: dict[str, Any] = {}
415526
if max_depth is not None:
416527
params["maxDepth"] = max_depth
417528
if root is not None:
@@ -434,7 +545,7 @@ def handle_user_prompt(
434545
accept: Whether to accept the prompt.
435546
user_text: The text to enter in the prompt.
436547
"""
437-
params = {"context": context}
548+
params: dict[str, Any] = {"context": context}
438549
if accept is not None:
439550
params["accept"] = accept
440551
if user_text is not None:
@@ -464,7 +575,7 @@ def locate_nodes(
464575
-------
465576
List[Dict]: A list of nodes.
466577
"""
467-
params = {"context": context, "locator": locator}
578+
params: dict[str, Any] = {"context": context, "locator": locator}
468579
if max_node_count is not None:
469580
params["maxNodeCount"] = max_node_count
470581
if serialization_options is not None:
@@ -564,7 +675,7 @@ def reload(
564675
-------
565676
Dict: A dictionary containing the navigation result.
566677
"""
567-
params = {"context": context}
678+
params: dict[str, Any] = {"context": context}
568679
if ignore_cache is not None:
569680
params["ignoreCache"] = ignore_cache
570681
if wait is not None:
@@ -593,7 +704,7 @@ def set_viewport(
593704
------
594705
Exception: If the browsing context is not a top-level traversable.
595706
"""
596-
params = {}
707+
params: dict[str, Any] = {}
597708
if context is not None:
598709
params["context"] = context
599710
if viewport is not None:
@@ -621,7 +732,7 @@ def traverse_history(self, context: str, delta: int) -> dict:
621732
result = self.conn.execute(command_builder("browsingContext.traverseHistory", params))
622733
return result
623734

624-
def _on_event(self, event_name: str, callback: callable) -> int:
735+
def _on_event(self, event_name: str, callback: Callable) -> int:
625736
"""Set a callback function to subscribe to a browsing context event.
626737
627738
Parameters:
@@ -665,7 +776,7 @@ def _callback(event_data):
665776

666777
return callback_id
667778

668-
def add_event_handler(self, event: str, callback: callable, contexts: Optional[list[str]] = None) -> int:
779+
def add_event_handler(self, event: str, callback: Callable, contexts: Optional[list[str]] = None) -> int:
669780
"""Add an event handler to the browsing context.
670781
671782
Parameters:
@@ -710,15 +821,18 @@ def remove_event_handler(self, event: str, callback_id: int) -> None:
710821
except KeyError:
711822
raise Exception(f"Event {event} not found")
712823

713-
event = BrowsingContextEvent(event_name)
824+
event_obj = BrowsingContextEvent(event_name)
714825

715-
self.conn.remove_callback(event, callback_id)
716-
self.subscriptions[event_name].remove(callback_id)
717-
if len(self.subscriptions[event_name]) == 0:
718-
params = {"events": [event_name]}
719-
session = Session(self.conn)
720-
self.conn.execute(session.unsubscribe(**params))
721-
del self.subscriptions[event_name]
826+
self.conn.remove_callback(event_obj, callback_id)
827+
if event_name in self.subscriptions:
828+
callbacks = self.subscriptions[event_name]
829+
if callback_id in callbacks:
830+
callbacks.remove(callback_id)
831+
if not callbacks:
832+
params = {"events": [event_name]}
833+
session = Session(self.conn)
834+
self.conn.execute(session.unsubscribe(**params))
835+
del self.subscriptions[event_name]
722836

723837
def clear_event_handlers(self) -> None:
724838
"""Clear all event handlers from the browsing context."""

py/selenium/webdriver/common/utils.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,12 @@ def find_connectable_ip(host: Union[str, bytes, bytearray, None], port: Optional
6464
for family, _, _, _, sockaddr in addrinfos:
6565
connectable = True
6666
if port:
67-
connectable = is_connectable(port, sockaddr[0])
67+
connectable = is_connectable(port, str(sockaddr[0]))
6868

6969
if connectable and family == socket.AF_INET:
70-
return sockaddr[0]
70+
return str(sockaddr[0])
7171
if connectable and not ip and family == socket.AF_INET6:
72-
ip = sockaddr[0]
72+
ip = str(sockaddr[0])
7373
return ip
7474

7575

@@ -132,7 +132,7 @@ def keys_to_typing(value: Iterable[AnyKey]) -> list[str]:
132132
for val in value:
133133
if isinstance(val, Keys):
134134
# Todo: Does this even work?
135-
characters.append(val)
135+
characters.append(str(val))
136136
elif isinstance(val, (int, float)):
137137
characters.extend(str(val))
138138
else:

0 commit comments

Comments
 (0)