Skip to content

Commit ba85100

Browse files
committed
Switch to a custom Chrome downloader
It turns out that the Web Driver Manager downloads the very latest version of Chrome every time which causes conflicts on the machines that have slightly older versions: ``` selenium.common.exceptions.SessionNotCreatedException: Message: session not created: This version of ChromeDriver only supports Chrome version 133 Current browser version is 132.0.6834.110 with binary path /Applications/Google Chrome for Testing.app/Contents/MacOS/Google Chrome for Testing ``` strictdoc-project/strictdoc#2077 (comment)
1 parent df34a3a commit ba85100

1 file changed

Lines changed: 127 additions & 77 deletions

File tree

html2print/html2print.py

Lines changed: 127 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@
33
import atexit
44
import base64
55
import os.path
6+
import platform
67
import sys
8+
import zipfile
79
from datetime import datetime
810
from pathlib import Path
9-
from shutil import copy
1011
from time import sleep
1112
from typing import Dict, List, Optional
1213

@@ -15,13 +16,7 @@
1516
from selenium import webdriver
1617
from selenium.webdriver.chrome.options import Options
1718
from selenium.webdriver.chrome.service import Service
18-
from webdriver_manager.chrome import ChromeDriverManager
19-
from webdriver_manager.core.download_manager import WDMDownloadManager
20-
from webdriver_manager.core.driver import Driver
21-
from webdriver_manager.core.driver_cache import DriverCacheManager
22-
from webdriver_manager.core.file_manager import FileManager
23-
from webdriver_manager.core.http import HttpClient
24-
from webdriver_manager.core.os_manager import OperationSystemManager
19+
from webdriver_manager.core.os_manager import ChromeType, OperationSystemManager
2520

2621
__version__ = "0.0.8"
2722

@@ -39,52 +34,40 @@
3934
sys.stdout = open(sys.stdout.fileno(), mode="w", encoding="utf8", closefd=False)
4035

4136

42-
class HTML2Print_HTTPClient(HttpClient):
43-
def get(self, url, params=None, **kwargs) -> Response:
44-
last_error: Optional[Exception] = None
45-
for attempt in range(1, 3):
46-
print( # noqa: T201
47-
f"html2print: sending GET request attempt {attempt}: {url}"
48-
)
49-
try:
50-
return requests.get(url, params, timeout=(5, 5), **kwargs)
51-
except requests.exceptions.ConnectTimeout as connect_timeout_:
52-
last_error = connect_timeout_
53-
except requests.exceptions.ReadTimeout as read_timeout_:
54-
last_error = read_timeout_
55-
except Exception as exception_:
56-
raise AssertionError(
57-
"html2print: unknown exception", exception_
58-
) from None
37+
class ChromeDriverManager:
38+
def get_chrome_driver(self, path_to_cache_dir: str):
39+
chrome_version = self.get_chrome_version()
40+
chrome_major_version = chrome_version.split(".")[0]
41+
5942
print( # noqa: T201
60-
f"html2print: "
61-
f"failed to get response for URL: {url} with error: {last_error}"
43+
f"html2print: Installed Chrome version: {chrome_version}"
6244
)
6345

46+
system_map = {
47+
"Windows": "win32",
48+
"Darwin": "mac-arm64"
49+
if platform.machine() == "arm64"
50+
else "mac-x64",
51+
"Linux": "linux64",
52+
}
53+
os_type = system_map[platform.system()]
54+
is_windows = platform.system() == "Windows"
6455

65-
class HTML2Print_CacheManager(DriverCacheManager):
66-
def __init__(self, file_manager: FileManager, path_to_cache_dir: str):
67-
super().__init__(file_manager=file_manager)
68-
self.path_to_cache_dir: str = path_to_cache_dir
69-
70-
def find_driver(self, driver: Driver):
71-
path_to_cached_chrome_driver_dir = os.path.join(
72-
self.path_to_cache_dir, "chromedriver"
73-
)
74-
75-
os_type = self.get_os_type()
76-
browser_type = driver.get_browser_type()
77-
browser_version = self._os_system_manager.get_browser_version_from_os(
78-
browser_type
56+
print( # noqa: T201
57+
f"html2print: OS system: {platform.system()}, OS type: {os_type}."
7958
)
80-
assert browser_version is not None, browser_version
8159

8260
path_to_cached_chrome_driver_dir = os.path.join(
83-
path_to_cached_chrome_driver_dir, browser_version, os_type
61+
path_to_cache_dir, chrome_major_version
8462
)
8563
path_to_cached_chrome_driver = os.path.join(
86-
path_to_cached_chrome_driver_dir, "chromedriver"
64+
path_to_cached_chrome_driver_dir,
65+
f"chromedriver-{os_type}",
66+
"chromedriver",
8767
)
68+
if is_windows:
69+
path_to_cached_chrome_driver += ".exe"
70+
8871
if os.path.isfile(path_to_cached_chrome_driver):
8972
print( # noqa: T201
9073
f"html2print: ChromeDriver exists in the local cache: "
@@ -95,25 +78,105 @@ def find_driver(self, driver: Driver):
9578
f"html2print: ChromeDriver does not exist in the local cache: "
9679
f"{path_to_cached_chrome_driver}"
9780
)
98-
path_to_downloaded_chrome_driver = super().find_driver(driver)
99-
if path_to_downloaded_chrome_driver is None:
100-
print( # noqa: T201
101-
f"html2print: could not get a downloaded ChromeDriver: "
102-
f"{path_to_cached_chrome_driver}"
81+
82+
path_to_downloaded_chrome_driver = self._download_chromedriver(
83+
chrome_major_version,
84+
os_type,
85+
path_to_cached_chrome_driver_dir,
86+
path_to_cached_chrome_driver,
87+
)
88+
assert os.path.isfile(path_to_downloaded_chrome_driver)
89+
os.chmod(path_to_downloaded_chrome_driver, 0o755)
90+
91+
return path_to_downloaded_chrome_driver
92+
93+
@staticmethod
94+
def _download_chromedriver(
95+
chrome_major_version,
96+
os_type: str,
97+
path_to_driver_cache_dir,
98+
path_to_cached_chrome_driver,
99+
):
100+
url = "https://googlechromelabs.github.io/chrome-for-testing/known-good-versions-with-downloads.json"
101+
response = ChromeDriverManager.send_http_get_request(url).json()
102+
103+
matching_versions = [
104+
item
105+
for item in response["versions"]
106+
if item["version"].startswith(chrome_major_version)
107+
]
108+
109+
if not matching_versions:
110+
raise Exception(
111+
f"No compatible ChromeDriver found for Chrome version {chrome_major_version}"
112+
)
113+
114+
latest_version = matching_versions[-1]
115+
116+
driver_url: str
117+
chrome_downloadable_versions = latest_version["downloads"][
118+
"chromedriver"
119+
]
120+
for chrome_downloadable_version_ in chrome_downloadable_versions:
121+
if chrome_downloadable_version_["platform"] == os_type:
122+
driver_url = chrome_downloadable_version_["url"]
123+
break
124+
else:
125+
raise RuntimeError(
126+
f"Could not find a downloadable URL from downloadable versions: {chrome_downloadable_versions}"
103127
)
104-
return None
105128

106129
print( # noqa: T201
107-
f"html2print: saving chromedriver to StrictDoc's local cache: "
108-
f"{path_to_downloaded_chrome_driver} -> {path_to_cached_chrome_driver}"
130+
f"html2print: downloading ChromeDriver from: {driver_url}"
109131
)
110-
Path(path_to_cached_chrome_driver_dir).mkdir(
111-
parents=True, exist_ok=True
132+
response = ChromeDriverManager.send_http_get_request(driver_url)
133+
134+
Path(path_to_driver_cache_dir).mkdir(parents=True, exist_ok=True)
135+
zip_path = os.path.join(path_to_driver_cache_dir, "chromedriver.zip")
136+
print( # noqa: T201
137+
f"html2print: saving downloaded ChromeDriver to path: {zip_path}"
112138
)
113-
copy(path_to_downloaded_chrome_driver, path_to_cached_chrome_driver)
139+
with open(zip_path, "wb") as file:
140+
file.write(response.content)
141+
142+
with zipfile.ZipFile(zip_path, "r") as zip_ref:
143+
zip_ref.extractall(path_to_driver_cache_dir)
114144

145+
if platform.system() == "Windows":
146+
path_to_cached_chrome_driver += ".exe"
147+
print( # noqa: T201
148+
f"html2print: ChromeDriver downloaded to: {path_to_cached_chrome_driver}"
149+
)
115150
return path_to_cached_chrome_driver
116151

152+
@staticmethod
153+
def send_http_get_request(url, params=None, **kwargs) -> Response:
154+
last_error: Optional[Exception] = None
155+
for attempt in range(1, 4):
156+
print( # noqa: T201
157+
f"html2print: sending GET request attempt {attempt}: {url}"
158+
)
159+
try:
160+
return requests.get(url, params, timeout=(5, 5), **kwargs)
161+
except requests.exceptions.ConnectTimeout as connect_timeout_:
162+
last_error = connect_timeout_
163+
except requests.exceptions.ReadTimeout as read_timeout_:
164+
last_error = read_timeout_
165+
except Exception as exception_:
166+
raise AssertionError(
167+
"html2print: unknown exception", exception_
168+
) from None
169+
print( # noqa: T201
170+
f"html2print: "
171+
f"failed to get response for URL: {url} with error: {last_error}"
172+
)
173+
174+
@staticmethod
175+
def get_chrome_version():
176+
os_manager = OperationSystemManager(os_type=None)
177+
version = os_manager.get_browser_version_from_os(ChromeType.GOOGLE)
178+
return version
179+
117180

118181
def get_inches_from_millimeters(mm: float) -> float:
119182
return mm / 25.4
@@ -190,23 +253,12 @@ class Done(Exception):
190253
return data
191254

192255

193-
def get_chrome_driver(path_to_cache_dir: str) -> str:
194-
cache_manager = HTML2Print_CacheManager(
195-
file_manager=FileManager(os_system_manager=OperationSystemManager()),
196-
path_to_cache_dir=path_to_cache_dir,
197-
)
198-
199-
http_client = HTML2Print_HTTPClient()
200-
download_manager = WDMDownloadManager(http_client)
201-
path_to_chrome = ChromeDriverManager(
202-
download_manager=download_manager, cache_manager=cache_manager
203-
).install()
204-
return path_to_chrome
205-
206-
207256
def create_webdriver(chromedriver: Optional[str], path_to_cache_dir: str):
257+
print("html2print: creating ChromeDriver service.", flush=True) # noqa: T201
208258
if chromedriver is None:
209-
path_to_chrome = get_chrome_driver(path_to_cache_dir)
259+
path_to_chrome = ChromeDriverManager().get_chrome_driver(
260+
path_to_cache_dir
261+
)
210262
else:
211263
path_to_chrome = chromedriver
212264
print(f"html2print: ChromeDriver available at path: {path_to_chrome}") # noqa: T201
@@ -295,22 +347,20 @@ def main():
295347
path_to_cache_dir: str
296348
if args.command == "get_driver":
297349
path_to_cache_dir = (
298-
args.cache_dir
299-
if args.cache_dir is not None
300-
else (DEFAULT_CACHE_DIR)
350+
args.cache_dir if args.cache_dir is not None else DEFAULT_CACHE_DIR
301351
)
302352

303-
path_to_chrome = get_chrome_driver(path_to_cache_dir)
353+
path_to_chrome = ChromeDriverManager().get_chrome_driver(
354+
path_to_cache_dir
355+
)
304356
print(f"html2print: ChromeDriver available at path: {path_to_chrome}") # noqa: T201
305357
sys.exit(0)
306358

307359
elif args.command == "print":
308360
paths: List[str] = args.paths
309361

310362
path_to_cache_dir = (
311-
args.cache_dir
312-
if args.cache_dir is not None
313-
else (DEFAULT_CACHE_DIR)
363+
args.cache_dir if args.cache_dir is not None else DEFAULT_CACHE_DIR
314364
)
315365
driver = create_webdriver(args.chromedriver, path_to_cache_dir)
316366

0 commit comments

Comments
 (0)