"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"]