"Fossies" - the Fresh Open Source Software Archive 
Member "selenium-selenium-4.8.1/py/selenium/webdriver/firefox/webdriver.py" (17 Feb 2023, 13658 Bytes) of package /linux/www/selenium-selenium-4.8.1.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style:
standard) with prefixed line numbers.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "webdriver.py" see the
Fossies "Dox" file reference documentation and the last
Fossies "Diffs" side-by-side code changes report:
4.7.0_vs_4.8.0.
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 import base64
18 import os
19 import warnings
20 import zipfile
21 from contextlib import contextmanager
22 from io import BytesIO
23 from shutil import rmtree
24
25 from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
26 from selenium.webdriver.remote.webdriver import WebDriver as RemoteWebDriver
27
28 from .firefox_binary import FirefoxBinary
29 from .firefox_profile import FirefoxProfile
30 from .options import Options
31 from .remote_connection import FirefoxRemoteConnection
32 from .service import DEFAULT_EXECUTABLE_PATH
33 from .service import Service
34
35 # Default for log_path variable. To be deleted when deprecations for arguments are removed.
36 DEFAULT_LOG_PATH = None
37 DEFAULT_SERVICE_LOG_PATH = "geckodriver.log"
38
39
40 class WebDriver(RemoteWebDriver):
41 CONTEXT_CHROME = "chrome"
42 CONTEXT_CONTENT = "content"
43
44 def __init__(
45 self,
46 firefox_profile=None,
47 firefox_binary=None,
48 capabilities=None,
49 proxy=None,
50 executable_path=DEFAULT_EXECUTABLE_PATH,
51 options=None,
52 service_log_path=DEFAULT_SERVICE_LOG_PATH,
53 service_args=None,
54 service=None,
55 desired_capabilities=None,
56 log_path=DEFAULT_LOG_PATH,
57 keep_alive=True, # Todo: Why is this now unused?
58 ) -> None:
59 """Starts a new local session of Firefox.
60
61 Based on the combination and specificity of the various keyword
62 arguments, a capabilities dictionary will be constructed that
63 is passed to the remote end.
64
65 The keyword arguments given to this constructor are helpers to
66 more easily allow Firefox WebDriver sessions to be customised
67 with different options. They are mapped on to a capabilities
68 dictionary that is passed on to the remote end.
69
70 As some of the options, such as `firefox_profile` and
71 `options.profile` are mutually exclusive, precedence is
72 given from how specific the setting is. `capabilities` is the
73 least specific keyword argument, followed by `options`,
74 followed by `firefox_binary` and `firefox_profile`.
75
76 In practice this means that if `firefox_profile` and
77 `options.profile` are both set, the selected profile
78 instance will always come from the most specific variable.
79 In this case that would be `firefox_profile`. This will result in
80 `options.profile` to be ignored because it is considered
81 a less specific setting than the top-level `firefox_profile`
82 keyword argument. Similarly, if you had specified a
83 `capabilities["moz:firefoxOptions"]["profile"]` Base64 string,
84 this would rank below `options.profile`.
85
86 :param firefox_profile: Deprecated: Instance of ``FirefoxProfile`` object
87 or a string. If undefined, a fresh profile will be created
88 in a temporary location on the system.
89 :param firefox_binary: Deprecated: Instance of ``FirefoxBinary`` or full
90 path to the Firefox binary. If undefined, the system default
91 Firefox installation will be used.
92 :param capabilities: Deprecated: Dictionary of desired capabilities.
93 :param proxy: Deprecated: The proxy settings to use when communicating with
94 Firefox via the extension connection.
95 :param executable_path: Deprecated: Full path to override which geckodriver
96 binary to use for Firefox 47.0.1 and greater, which
97 defaults to picking up the binary from the system path.
98 :param options: Instance of ``options.Options``.
99 :param service: (Optional) service instance for managing the starting and stopping of the driver.
100 :param service_log_path: Deprecated: Where to log information from the driver.
101 :param service_args: Deprecated: List of args to pass to the driver service
102 :param desired_capabilities: Deprecated: alias of capabilities. In future
103 versions of this library, this will replace 'capabilities'.
104 This will make the signature consistent with RemoteWebDriver.
105 :param keep_alive: Whether to configure remote_connection.RemoteConnection to use
106 HTTP keep-alive.
107 """
108
109 if executable_path != DEFAULT_EXECUTABLE_PATH:
110 warnings.warn(
111 "executable_path has been deprecated, please pass in a Service object", DeprecationWarning, stacklevel=2
112 )
113 if capabilities or desired_capabilities:
114 warnings.warn(
115 "capabilities and desired_capabilities have been deprecated, please pass in a Service object",
116 DeprecationWarning,
117 stacklevel=2,
118 )
119 if firefox_binary:
120 warnings.warn(
121 "firefox_binary has been deprecated, please pass in a Service object", DeprecationWarning, stacklevel=2
122 )
123 self.binary = None
124 if firefox_profile:
125 warnings.warn(
126 "firefox_profile has been deprecated, please pass in an Options object",
127 DeprecationWarning,
128 stacklevel=2,
129 )
130 self.profile = None
131
132 if log_path != DEFAULT_LOG_PATH:
133 warnings.warn(
134 "log_path has been deprecated, please pass in a Service object", DeprecationWarning, stacklevel=2
135 )
136
137 # Service Arguments being deprecated.
138 if service_log_path != DEFAULT_SERVICE_LOG_PATH:
139 warnings.warn(
140 "service_log_path has been deprecated, please pass in a Service object",
141 DeprecationWarning,
142 stacklevel=2,
143 )
144 if service_args:
145 warnings.warn(
146 "service_args has been deprecated, please pass in a Service object", DeprecationWarning, stacklevel=2
147 )
148
149 self.service = service
150
151 # If desired capabilities is set, alias it to capabilities.
152 # If both are set ignore desired capabilities.
153 if not capabilities and desired_capabilities:
154 capabilities = desired_capabilities
155
156 if not capabilities:
157 capabilities = DesiredCapabilities.FIREFOX.copy()
158 if not options:
159 options = Options()
160
161 capabilities = dict(capabilities)
162
163 if capabilities.get("binary"):
164 options.binary = capabilities["binary"]
165
166 # options overrides capabilities
167 if options:
168 if options.binary:
169 self.binary = options.binary
170 if options.profile:
171 self.profile = options.profile
172
173 # firefox_binary and firefox_profile
174 # override options
175 if firefox_binary:
176 if isinstance(firefox_binary, str):
177 firefox_binary = FirefoxBinary(firefox_binary)
178 self.binary = firefox_binary
179 options.binary = firefox_binary
180 if firefox_profile:
181 if isinstance(firefox_profile, str):
182 firefox_profile = FirefoxProfile(firefox_profile)
183 self.profile = firefox_profile
184 options.profile = firefox_profile
185
186 if not capabilities.get("acceptInsecureCerts") or not options.accept_insecure_certs:
187 options.accept_insecure_certs = False
188
189 if not self.service:
190 self.service = Service(executable_path, service_args=service_args, log_path=service_log_path)
191 self.service.start()
192
193 executor = FirefoxRemoteConnection(
194 remote_server_addr=self.service.service_url, ignore_proxy=options._ignore_local_proxy
195 )
196 super().__init__(command_executor=executor, options=options, keep_alive=True)
197
198 self._is_remote = False
199
200 def quit(self) -> None:
201 """Quits the driver and close every associated window."""
202 try:
203 super().quit()
204 except Exception:
205 # We don't care about the message because something probably has gone wrong
206 pass
207
208 self.service.stop()
209
210 if self.profile:
211 try:
212 rmtree(self.profile.path)
213 if self.profile.tempfolder:
214 rmtree(self.profile.tempfolder)
215 except Exception as e:
216 print(str(e))
217
218 @property
219 def firefox_profile(self):
220 return self.profile
221
222 # Extension commands:
223
224 def set_context(self, context) -> None:
225 self.execute("SET_CONTEXT", {"context": context})
226
227 @contextmanager
228 def context(self, context):
229 """Sets the context that Selenium commands are running in using a
230 `with` statement. The state of the context on the server is saved
231 before entering the block, and restored upon exiting it.
232
233 :param context: Context, may be one of the class properties
234 `CONTEXT_CHROME` or `CONTEXT_CONTENT`.
235
236 Usage example::
237
238 with selenium.context(selenium.CONTEXT_CHROME):
239 # chrome scope
240 ... do stuff ...
241 """
242 initial_context = self.execute("GET_CONTEXT").pop("value")
243 self.set_context(context)
244 try:
245 yield
246 finally:
247 self.set_context(initial_context)
248
249 def install_addon(self, path, temporary=False) -> str:
250 """Installs Firefox addon.
251
252 Returns identifier of installed addon. This identifier can later
253 be used to uninstall addon.
254
255 :param path: Absolute path to the addon that will be installed.
256
257 :Usage:
258 ::
259
260 driver.install_addon('/path/to/firebug.xpi')
261 """
262
263 if os.path.isdir(path):
264 fp = BytesIO()
265 path_root = len(path) + 1 # account for trailing slash
266 with zipfile.ZipFile(fp, "w", zipfile.ZIP_DEFLATED) as zipped:
267 for base, dirs, files in os.walk(path):
268 for fyle in files:
269 filename = os.path.join(base, fyle)
270 zipped.write(filename, filename[path_root:])
271 addon = base64.b64encode(fp.getvalue()).decode("UTF-8")
272 else:
273 with open(path, "rb") as file:
274 addon = base64.b64encode(file.read()).decode("UTF-8")
275
276 payload = {"addon": addon, "temporary": temporary}
277 return self.execute("INSTALL_ADDON", payload)["value"]
278
279 def uninstall_addon(self, identifier) -> None:
280 """Uninstalls Firefox addon using its identifier.
281
282 :Usage:
283 ::
284
285 driver.uninstall_addon('addon@foo.com')
286 """
287 self.execute("UNINSTALL_ADDON", {"id": identifier})
288
289 def get_full_page_screenshot_as_file(self, filename) -> bool:
290 """Saves a full document screenshot of the current window to a PNG
291 image file. Returns False if there is any IOError, else returns True.
292 Use full paths in your filename.
293
294 :Args:
295 - filename: The full path you wish to save your screenshot to. This
296 should end with a `.png` extension.
297
298 :Usage:
299 ::
300
301 driver.get_full_page_screenshot_as_file('/Screenshots/foo.png')
302 """
303 if not filename.lower().endswith(".png"):
304 warnings.warn(
305 "name used for saved screenshot does not match file " "type. It should end with a `.png` extension",
306 UserWarning,
307 )
308 png = self.get_full_page_screenshot_as_png()
309 try:
310 with open(filename, "wb") as f:
311 f.write(png)
312 except OSError:
313 return False
314 finally:
315 del png
316 return True
317
318 def save_full_page_screenshot(self, filename) -> bool:
319 """Saves a full document screenshot of the current window to a PNG
320 image file. Returns False if there is any IOError, else returns True.
321 Use full paths in your filename.
322
323 :Args:
324 - filename: The full path you wish to save your screenshot to. This
325 should end with a `.png` extension.
326
327 :Usage:
328 ::
329
330 driver.save_full_page_screenshot('/Screenshots/foo.png')
331 """
332 return self.get_full_page_screenshot_as_file(filename)
333
334 def get_full_page_screenshot_as_png(self) -> bytes:
335 """Gets the full document screenshot of the current window as a binary
336 data.
337
338 :Usage:
339 ::
340
341 driver.get_full_page_screenshot_as_png()
342 """
343 return base64.b64decode(self.get_full_page_screenshot_as_base64().encode("ascii"))
344
345 def get_full_page_screenshot_as_base64(self) -> str:
346 """Gets the full document screenshot of the current window as a base64
347 encoded string which is useful in embedded images in HTML.
348
349 :Usage:
350 ::
351
352 driver.get_full_page_screenshot_as_base64()
353 """
354 return self.execute("FULL_PAGE_SCREENSHOT")["value"]