Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
SeleniumHQ
GitHub Repository: SeleniumHQ/Selenium
Path: blob/trunk/py/selenium/webdriver/common/selenium_manager.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
import json
18
import logging
19
import os
20
import platform
21
import subprocess
22
import sys
23
import sysconfig
24
from pathlib import Path
25
from typing import Optional
26
27
from selenium.common import WebDriverException
28
29
logger = logging.getLogger(__name__)
30
31
32
class SeleniumManager:
33
"""Wrapper for getting information from the Selenium Manager binaries.
34
35
This implementation is still in beta, and may change.
36
"""
37
38
def binary_paths(self, args: list) -> dict:
39
"""Determines the locations of the requested assets.
40
41
:Args:
42
- args: the commands to send to the selenium manager binary.
43
:Returns: dictionary of assets and their path
44
"""
45
46
args = [str(self._get_binary())] + args
47
if logger.getEffectiveLevel() == logging.DEBUG:
48
args.append("--debug")
49
args.append("--language-binding")
50
args.append("python")
51
args.append("--output")
52
args.append("json")
53
54
return self._run(args)
55
56
@staticmethod
57
def _get_binary() -> Path:
58
"""Determines the path of the correct Selenium Manager binary.
59
60
:Returns: The Selenium Manager executable location
61
62
:Raises: WebDriverException if the platform is unsupported
63
"""
64
65
compiled_path = Path(__file__).parent.joinpath("selenium-manager")
66
exe = sysconfig.get_config_var("EXE")
67
if exe is not None:
68
compiled_path = compiled_path.with_suffix(exe)
69
70
path: Optional[Path] = None
71
72
if (env_path := os.getenv("SE_MANAGER_PATH")) is not None:
73
logger.debug("Selenium Manager set by env SE_MANAGER_PATH to: %s", env_path)
74
path = Path(env_path)
75
elif compiled_path.exists():
76
path = compiled_path
77
else:
78
allowed = {
79
("darwin", "any"): "macos/selenium-manager",
80
("win32", "any"): "windows/selenium-manager.exe",
81
("cygwin", "any"): "windows/selenium-manager.exe",
82
("linux", "x86_64"): "linux/selenium-manager",
83
("freebsd", "x86_64"): "linux/selenium-manager",
84
("openbsd", "x86_64"): "linux/selenium-manager",
85
}
86
87
arch = platform.machine() if sys.platform in ("linux", "freebsd", "openbsd") else "any"
88
if sys.platform in ["freebsd", "openbsd"]:
89
logger.warning("Selenium Manager binary may not be compatible with %s; verify settings", sys.platform)
90
91
location = allowed.get((sys.platform, arch))
92
if location is None:
93
raise WebDriverException(f"Unsupported platform/architecture combination: {sys.platform}/{arch}")
94
95
path = Path(__file__).parent.joinpath(location)
96
97
if path is None or not path.is_file():
98
raise WebDriverException(f"Unable to obtain working Selenium Manager binary; {path}")
99
100
logger.debug("Selenium Manager binary found at: %s", path)
101
102
return path
103
104
@staticmethod
105
def _run(args: list[str]) -> dict:
106
"""Executes the Selenium Manager Binary.
107
108
:Args:
109
- args: the components of the command being executed.
110
:Returns: The log string containing the driver location.
111
"""
112
command = " ".join(args)
113
logger.debug("Executing process: %s", command)
114
try:
115
if sys.platform == "win32":
116
completed_proc = subprocess.run(args, capture_output=True, creationflags=subprocess.CREATE_NO_WINDOW)
117
else:
118
completed_proc = subprocess.run(args, capture_output=True)
119
stdout = completed_proc.stdout.decode("utf-8").rstrip("\n")
120
stderr = completed_proc.stderr.decode("utf-8").rstrip("\n")
121
output = json.loads(stdout) if stdout != "" else {"logs": [], "result": {}}
122
except Exception as err:
123
raise WebDriverException(f"Unsuccessful command executed: {command}") from err
124
125
SeleniumManager._process_logs(output["logs"])
126
result = output["result"]
127
if completed_proc.returncode:
128
raise WebDriverException(
129
f"Unsuccessful command executed: {command}; code: {completed_proc.returncode}\n{result}\n{stderr}"
130
)
131
return result
132
133
@staticmethod
134
def _process_logs(log_items: list[dict]):
135
for item in log_items:
136
if item["level"] == "WARN":
137
logger.warning(item["message"])
138
elif item["level"] in ["DEBUG", "INFO"]:
139
logger.debug(item["message"])
140
141