Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
SeleniumHQ
GitHub Repository: SeleniumHQ/Selenium
Path: blob/trunk/py/selenium/webdriver/common/selenium_manager.py
4007 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
import json
19
import logging
20
import os
21
import platform
22
import subprocess
23
import sys
24
import sysconfig
25
from pathlib import Path
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
44
Returns:
45
Dictionary of assets and their path.
46
"""
47
args = [str(self._get_binary())] + args
48
if logger.getEffectiveLevel() == logging.DEBUG:
49
args.append("--debug")
50
args.append("--language-binding")
51
args.append("python")
52
args.append("--output")
53
args.append("json")
54
55
return self._run(args)
56
57
@staticmethod
58
def _get_binary() -> Path:
59
"""Determines the path of the Selenium Manager binary.
60
61
Location of the binary is checked in this order:
62
63
1. location set in an environment variable
64
2. location where setuptools-rust places the compiled binary (built from the sdist package)
65
3. location where we ship binaries in the wheel package for the platform this is running on
66
4. give up
67
68
Returns:
69
The Selenium Manager executable location.
70
71
Raises:
72
WebDriverException: If the platform is unsupported or Selenium Manager executable can't be found.
73
"""
74
compiled_path = Path(__file__).parent.joinpath("selenium-manager")
75
exe = sysconfig.get_config_var("EXE")
76
if exe is not None:
77
compiled_path = compiled_path.with_suffix(exe)
78
79
path: Path | None = None
80
81
if (env_path := os.getenv("SE_MANAGER_PATH")) is not None:
82
logger.debug(f"Selenium Manager set by env SE_MANAGER_PATH to: {env_path}")
83
path_candidate = Path(env_path)
84
if not path_candidate.is_file():
85
raise WebDriverException(f"SE_MANAGER_PATH does not point to a file: {env_path}")
86
path = path_candidate
87
elif compiled_path.is_file():
88
path = compiled_path
89
else:
90
allowed = {
91
("darwin", "any"): "macos/selenium-manager",
92
("win32", "any"): "windows/selenium-manager.exe",
93
("cygwin", "any"): "windows/selenium-manager.exe",
94
("linux", "x86_64"): "linux/selenium-manager",
95
("freebsd", "x86_64"): "linux/selenium-manager",
96
("openbsd", "x86_64"): "linux/selenium-manager",
97
}
98
99
arch = platform.machine() if sys.platform in ("linux", "freebsd", "openbsd") else "any"
100
if sys.platform in ["freebsd", "openbsd"]:
101
logger.warning(f"Selenium Manager binary may not be compatible with {sys.platform}; verify settings")
102
103
location = allowed.get((sys.platform, arch))
104
if location is None:
105
raise WebDriverException(f"Unsupported platform/architecture combination: {sys.platform}/{arch}")
106
107
path = Path(__file__).parent.joinpath(location)
108
109
if path is None or not path.is_file():
110
raise WebDriverException(f"Unable to obtain working Selenium Manager binary; {path}")
111
112
logger.debug(f"Selenium Manager binary found at: {path}")
113
114
return path
115
116
@staticmethod
117
def _run(args: list[str]) -> dict:
118
"""Executes the Selenium Manager Binary.
119
120
Args:
121
args: the components of the command being executed.
122
123
Returns:
124
The log string containing the driver location.
125
"""
126
command = " ".join(args)
127
logger.debug("Executing process: %s", command)
128
try:
129
if sys.platform == "win32":
130
completed_proc = subprocess.run(args, capture_output=True, creationflags=subprocess.CREATE_NO_WINDOW)
131
else:
132
completed_proc = subprocess.run(args, capture_output=True)
133
stdout = completed_proc.stdout.decode("utf-8").rstrip("\n")
134
stderr = completed_proc.stderr.decode("utf-8").rstrip("\n")
135
output = json.loads(stdout) if stdout != "" else {"logs": [], "result": {}}
136
except Exception as err:
137
raise WebDriverException(f"Unsuccessful command executed: {command}") from err
138
139
SeleniumManager._process_logs(output["logs"])
140
result = output["result"]
141
if completed_proc.returncode:
142
raise WebDriverException(
143
f"Unsuccessful command executed: {command}; code: {completed_proc.returncode}\n{result}\n{stderr}"
144
)
145
return result
146
147
@staticmethod
148
def _process_logs(log_items: list[dict]):
149
for item in log_items:
150
if item["level"] == "WARN":
151
logger.warning(item["message"])
152
elif item["level"] in ["DEBUG", "INFO"]:
153
logger.debug(item["message"])
154
155