Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
SeleniumHQ
GitHub Repository: SeleniumHQ/Selenium
Path: blob/trunk/py/selenium/webdriver/common/bidi/browser.py
1864 views
1
# Licensed to the Software Freedom Conservancy (SFC) under one
2
# or more contributor license agreements. See the NOTICE file
3
# distributed with this work for additional information
4
# regarding copyright ownership. The SFC licenses this file
5
# to you under the Apache License, Version 2.0 (the
6
# "License"); you may not use this file except in compliance
7
# with the License. You may obtain a copy of the License at
8
#
9
# http://www.apache.org/licenses/LICENSE-2.0
10
#
11
# Unless required by applicable law or agreed to in writing,
12
# software distributed under the License is distributed on an
13
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
# KIND, either express or implied. See the License for the
15
# specific language governing permissions and limitations
16
# under the License.
17
18
19
from typing import Any, Optional
20
21
from selenium.webdriver.common.bidi.common import command_builder
22
from selenium.webdriver.common.bidi.session import UserPromptHandler
23
from selenium.webdriver.common.proxy import Proxy
24
25
26
class ClientWindowState:
27
"""Represents a window state."""
28
29
FULLSCREEN = "fullscreen"
30
MAXIMIZED = "maximized"
31
MINIMIZED = "minimized"
32
NORMAL = "normal"
33
34
VALID_STATES = {FULLSCREEN, MAXIMIZED, MINIMIZED, NORMAL}
35
36
37
class ClientWindowInfo:
38
"""Represents a client window information."""
39
40
def __init__(
41
self,
42
client_window: str,
43
state: str,
44
width: int,
45
height: int,
46
x: int,
47
y: int,
48
active: bool,
49
):
50
self.client_window = client_window
51
self.state = state
52
self.width = width
53
self.height = height
54
self.x = x
55
self.y = y
56
self.active = active
57
58
def get_state(self) -> str:
59
"""Gets the state of the client window.
60
61
Returns:
62
-------
63
str: The state of the client window (one of the ClientWindowState constants).
64
"""
65
return self.state
66
67
def get_client_window(self) -> str:
68
"""Gets the client window identifier.
69
70
Returns:
71
-------
72
str: The client window identifier.
73
"""
74
return self.client_window
75
76
def get_width(self) -> int:
77
"""Gets the width of the client window.
78
79
Returns:
80
-------
81
int: The width of the client window.
82
"""
83
return self.width
84
85
def get_height(self) -> int:
86
"""Gets the height of the client window.
87
88
Returns:
89
-------
90
int: The height of the client window.
91
"""
92
return self.height
93
94
def get_x(self) -> int:
95
"""Gets the x coordinate of the client window.
96
97
Returns:
98
-------
99
int: The x coordinate of the client window.
100
"""
101
return self.x
102
103
def get_y(self) -> int:
104
"""Gets the y coordinate of the client window.
105
106
Returns:
107
-------
108
int: The y coordinate of the client window.
109
"""
110
return self.y
111
112
def is_active(self) -> bool:
113
"""Checks if the client window is active.
114
115
Returns:
116
-------
117
bool: True if the client window is active, False otherwise.
118
"""
119
return self.active
120
121
@classmethod
122
def from_dict(cls, data: dict) -> "ClientWindowInfo":
123
"""Creates a ClientWindowInfo instance from a dictionary.
124
125
Parameters:
126
-----------
127
data: A dictionary containing the client window information.
128
129
Returns:
130
-------
131
ClientWindowInfo: A new instance of ClientWindowInfo.
132
133
Raises:
134
------
135
ValueError: If required fields are missing or have invalid types.
136
"""
137
try:
138
client_window = data["clientWindow"]
139
if not isinstance(client_window, str):
140
raise ValueError("clientWindow must be a string")
141
142
state = data["state"]
143
if not isinstance(state, str):
144
raise ValueError("state must be a string")
145
if state not in ClientWindowState.VALID_STATES:
146
raise ValueError(f"Invalid state: {state}. Must be one of {ClientWindowState.VALID_STATES}")
147
148
width = data["width"]
149
if not isinstance(width, int) or width < 0:
150
raise ValueError(f"width must be a non-negative integer, got {width}")
151
152
height = data["height"]
153
if not isinstance(height, int) or height < 0:
154
raise ValueError(f"height must be a non-negative integer, got {height}")
155
156
x = data["x"]
157
if not isinstance(x, int):
158
raise ValueError(f"x must be an integer, got {type(x).__name__}")
159
160
y = data["y"]
161
if not isinstance(y, int):
162
raise ValueError(f"y must be an integer, got {type(y).__name__}")
163
164
active = data["active"]
165
if not isinstance(active, bool):
166
raise ValueError("active must be a boolean")
167
168
return cls(
169
client_window=client_window,
170
state=state,
171
width=width,
172
height=height,
173
x=x,
174
y=y,
175
active=active,
176
)
177
except (KeyError, TypeError) as e:
178
raise ValueError(f"Invalid data format for ClientWindowInfo: {e}")
179
180
181
class Browser:
182
"""
183
BiDi implementation of the browser module.
184
"""
185
186
def __init__(self, conn):
187
self.conn = conn
188
189
def create_user_context(
190
self,
191
accept_insecure_certs: Optional[bool] = None,
192
proxy: Optional[Proxy] = None,
193
unhandled_prompt_behavior: Optional[UserPromptHandler] = None,
194
) -> str:
195
"""Creates a new user context.
196
197
Parameters:
198
-----------
199
accept_insecure_certs: Optional flag to accept insecure TLS certificates
200
proxy: Optional proxy configuration for the user context
201
unhandled_prompt_behavior: Optional configuration for handling user prompts
202
203
Returns:
204
-------
205
str: The ID of the created user context.
206
"""
207
params: dict[str, Any] = {}
208
209
if accept_insecure_certs is not None:
210
params["acceptInsecureCerts"] = accept_insecure_certs
211
212
if proxy is not None:
213
params["proxy"] = proxy.to_bidi_dict()
214
215
if unhandled_prompt_behavior is not None:
216
params["unhandledPromptBehavior"] = unhandled_prompt_behavior.to_dict()
217
218
result = self.conn.execute(command_builder("browser.createUserContext", params))
219
return result["userContext"]
220
221
def get_user_contexts(self) -> list[str]:
222
"""Gets all user contexts.
223
224
Returns:
225
-------
226
List[str]: A list of user context IDs.
227
"""
228
result = self.conn.execute(command_builder("browser.getUserContexts", {}))
229
return [context_info["userContext"] for context_info in result["userContexts"]]
230
231
def remove_user_context(self, user_context_id: str) -> None:
232
"""Removes a user context.
233
234
Parameters:
235
-----------
236
user_context_id: The ID of the user context to remove.
237
238
Raises:
239
------
240
Exception: If the user context ID is "default" or does not exist.
241
"""
242
if user_context_id == "default":
243
raise Exception("Cannot remove the default user context")
244
245
params = {"userContext": user_context_id}
246
self.conn.execute(command_builder("browser.removeUserContext", params))
247
248
def get_client_windows(self) -> list[ClientWindowInfo]:
249
"""Gets all client windows.
250
251
Returns:
252
-------
253
List[ClientWindowInfo]: A list of client window information.
254
"""
255
result = self.conn.execute(command_builder("browser.getClientWindows", {}))
256
return [ClientWindowInfo.from_dict(window) for window in result["clientWindows"]]
257
258