Source code for selenium.webdriver.common.selenium_manager

# Licensed to the Software Freedom Conservancy (SFC) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The SFC licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.
import json
import logging
import os
import platform
import subprocess
import sys
import sysconfig
from pathlib import Path
from typing import Optional

from selenium.common import WebDriverException

logger = logging.getLogger(__name__)


[docs] class SeleniumManager: """Wrapper for getting information from the Selenium Manager binaries. This implementation is still in beta, and may change. """
[docs] def binary_paths(self, args: list) -> dict: """Determines the locations of the requested assets. :Args: - args: the commands to send to the selenium manager binary. :Returns: dictionary of assets and their path """ args = [str(self._get_binary())] + args if logger.getEffectiveLevel() == logging.DEBUG: args.append("--debug") args.append("--language-binding") args.append("python") args.append("--output") args.append("json") return self._run(args)
@staticmethod def _get_binary() -> Path: """Determines the path of the correct Selenium Manager binary. :Returns: The Selenium Manager executable location :Raises: WebDriverException if the platform is unsupported """ compiled_path = Path(__file__).parent.joinpath("selenium-manager") exe = sysconfig.get_config_var("EXE") if exe is not None: compiled_path = compiled_path.with_suffix(exe) path: Optional[Path] = None if (env_path := os.getenv("SE_MANAGER_PATH")) is not None: logger.debug("Selenium Manager set by env SE_MANAGER_PATH to: %s", env_path) path = Path(env_path) elif compiled_path.exists(): path = compiled_path else: allowed = { ("darwin", "any"): "macos/selenium-manager", ("win32", "any"): "windows/selenium-manager.exe", ("cygwin", "any"): "windows/selenium-manager.exe", ("linux", "x86_64"): "linux/selenium-manager", ("freebsd", "x86_64"): "linux/selenium-manager", ("openbsd", "x86_64"): "linux/selenium-manager", } arch = platform.machine() if sys.platform in ("linux", "freebsd", "openbsd") else "any" if sys.platform in ["freebsd", "openbsd"]: logger.warning("Selenium Manager binary may not be compatible with %s; verify settings", sys.platform) location = allowed.get((sys.platform, arch)) if location is None: raise WebDriverException(f"Unsupported platform/architecture combination: {sys.platform}/{arch}") path = Path(__file__).parent.joinpath(location) if path is None or not path.is_file(): raise WebDriverException(f"Unable to obtain working Selenium Manager binary; {path}") logger.debug("Selenium Manager binary found at: %s", path) return path @staticmethod def _run(args: list[str]) -> dict: """Executes the Selenium Manager Binary. :Args: - args: the components of the command being executed. :Returns: The log string containing the driver location. """ command = " ".join(args) logger.debug("Executing process: %s", command) try: if sys.platform == "win32": completed_proc = subprocess.run(args, capture_output=True, creationflags=subprocess.CREATE_NO_WINDOW) else: completed_proc = subprocess.run(args, capture_output=True) stdout = completed_proc.stdout.decode("utf-8").rstrip("\n") stderr = completed_proc.stderr.decode("utf-8").rstrip("\n") output = json.loads(stdout) if stdout != "" else {"logs": [], "result": {}} except Exception as err: raise WebDriverException(f"Unsuccessful command executed: {command}") from err SeleniumManager._process_logs(output["logs"]) result = output["result"] if completed_proc.returncode: raise WebDriverException( f"Unsuccessful command executed: {command}; code: {completed_proc.returncode}\n{result}\n{stderr}" ) return result @staticmethod def _process_logs(log_items: list[dict]): for item in log_items: if item["level"] == "WARN": logger.warning(item["message"]) elif item["level"] in ["DEBUG", "INFO"]: logger.debug(item["message"])