Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
SeleniumHQ
GitHub Repository: SeleniumHQ/Selenium
Path: blob/trunk/py/selenium/webdriver/common/bidi/emulation.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
from typing import Any, Optional, Union
19
20
from selenium.webdriver.common.bidi.common import command_builder
21
22
23
class GeolocationCoordinates:
24
"""Represents geolocation coordinates."""
25
26
def __init__(
27
self,
28
latitude: float,
29
longitude: float,
30
accuracy: float = 1.0,
31
altitude: Optional[float] = None,
32
altitude_accuracy: Optional[float] = None,
33
heading: Optional[float] = None,
34
speed: Optional[float] = None,
35
):
36
"""Initialize GeolocationCoordinates.
37
38
Parameters:
39
-----------
40
latitude: Latitude coordinate (-90.0 to 90.0).
41
longitude: Longitude coordinate (-180.0 to 180.0).
42
accuracy: Accuracy in meters (>= 0.0), defaults to 1.0.
43
altitude: Altitude in meters or None, defaults to None.
44
altitude_accuracy: Altitude accuracy in meters (>= 0.0) or None, defaults to None.
45
heading: Heading in degrees (0.0 to 360.0) or None, defaults to None.
46
speed: Speed in meters per second (>= 0.0) or None, defaults to None.
47
48
Raises:
49
------
50
ValueError: If coordinates are out of valid range or if altitude_accuracy is provided without altitude.
51
"""
52
self.latitude = latitude
53
self.longitude = longitude
54
self.accuracy = accuracy
55
self.altitude = altitude
56
self.altitude_accuracy = altitude_accuracy
57
self.heading = heading
58
self.speed = speed
59
60
@property
61
def latitude(self):
62
return self._latitude
63
64
@latitude.setter
65
def latitude(self, value):
66
if not (-90.0 <= value <= 90.0):
67
raise ValueError("latitude must be between -90.0 and 90.0")
68
self._latitude = value
69
70
@property
71
def longitude(self):
72
return self._longitude
73
74
@longitude.setter
75
def longitude(self, value):
76
if not (-180.0 <= value <= 180.0):
77
raise ValueError("longitude must be between -180.0 and 180.0")
78
self._longitude = value
79
80
@property
81
def accuracy(self):
82
return self._accuracy
83
84
@accuracy.setter
85
def accuracy(self, value):
86
if value < 0.0:
87
raise ValueError("accuracy must be >= 0.0")
88
self._accuracy = value
89
90
@property
91
def altitude(self):
92
return self._altitude
93
94
@altitude.setter
95
def altitude(self, value):
96
self._altitude = value
97
98
@property
99
def altitude_accuracy(self):
100
return self._altitude_accuracy
101
102
@altitude_accuracy.setter
103
def altitude_accuracy(self, value):
104
if value is not None and self.altitude is None:
105
raise ValueError("altitude_accuracy cannot be set without altitude")
106
if value is not None and value < 0.0:
107
raise ValueError("altitude_accuracy must be >= 0.0")
108
self._altitude_accuracy = value
109
110
@property
111
def heading(self):
112
return self._heading
113
114
@heading.setter
115
def heading(self, value):
116
if value is not None and not (0.0 <= value < 360.0):
117
raise ValueError("heading must be between 0.0 and 360.0")
118
self._heading = value
119
120
@property
121
def speed(self):
122
return self._speed
123
124
@speed.setter
125
def speed(self, value):
126
if value is not None and value < 0.0:
127
raise ValueError("speed must be >= 0.0")
128
self._speed = value
129
130
def to_dict(self) -> dict[str, Union[float, None]]:
131
result: dict[str, Union[float, None]] = {
132
"latitude": self.latitude,
133
"longitude": self.longitude,
134
"accuracy": self.accuracy,
135
}
136
137
if self.altitude is not None:
138
result["altitude"] = self.altitude
139
140
if self.altitude_accuracy is not None:
141
result["altitudeAccuracy"] = self.altitude_accuracy
142
143
if self.heading is not None:
144
result["heading"] = self.heading
145
146
if self.speed is not None:
147
result["speed"] = self.speed
148
149
return result
150
151
152
class GeolocationPositionError:
153
"""Represents a geolocation position error."""
154
155
TYPE_POSITION_UNAVAILABLE = "positionUnavailable"
156
157
def __init__(self, type: str = TYPE_POSITION_UNAVAILABLE):
158
if type != self.TYPE_POSITION_UNAVAILABLE:
159
raise ValueError(f'type must be "{self.TYPE_POSITION_UNAVAILABLE}"')
160
self.type = type
161
162
def to_dict(self) -> dict[str, str]:
163
return {"type": self.type}
164
165
166
class Emulation:
167
"""
168
BiDi implementation of the emulation module.
169
"""
170
171
def __init__(self, conn):
172
self.conn = conn
173
174
def set_geolocation_override(
175
self,
176
coordinates: Optional[GeolocationCoordinates] = None,
177
error: Optional[GeolocationPositionError] = None,
178
contexts: Optional[list[str]] = None,
179
user_contexts: Optional[list[str]] = None,
180
) -> None:
181
"""Set geolocation override for the given contexts or user contexts.
182
183
Parameters:
184
-----------
185
coordinates: Geolocation coordinates to emulate, or None.
186
error: Geolocation error to emulate, or None.
187
contexts: List of browsing context IDs to apply the override to.
188
user_contexts: List of user context IDs to apply the override to.
189
190
Raises:
191
------
192
ValueError: If both coordinates and error are provided, or if both contexts
193
and user_contexts are provided, or if neither contexts nor
194
user_contexts are provided.
195
"""
196
if coordinates is not None and error is not None:
197
raise ValueError("Cannot specify both coordinates and error")
198
199
if contexts is not None and user_contexts is not None:
200
raise ValueError("Cannot specify both contexts and userContexts")
201
202
if contexts is None and user_contexts is None:
203
raise ValueError("Must specify either contexts or userContexts")
204
205
params: dict[str, Any] = {}
206
207
if coordinates is not None:
208
params["coordinates"] = coordinates.to_dict()
209
elif error is not None:
210
params["error"] = error.to_dict()
211
212
if contexts is not None:
213
params["contexts"] = contexts
214
elif user_contexts is not None:
215
params["userContexts"] = user_contexts
216
217
self.conn.execute(command_builder("emulation.setGeolocationOverride", params))
218
219