Skip to content

Commit 22869c4

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 22869c4

1 file changed

Lines changed: 125 additions & 77 deletions

File tree

html2print/html2print.py

Lines changed: 125 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,103 @@ 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+
print( # noqa: T201
146+
f"html2print: ChromeDriver downloaded to: {path_to_cached_chrome_driver}"
147+
)
115148
return path_to_cached_chrome_driver
116149

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

118179
def get_inches_from_millimeters(mm: float) -> float:
119180
return mm / 25.4
@@ -190,23 +251,12 @@ class Done(Exception):
190251
return data
191252

192253

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-
207254
def create_webdriver(chromedriver: Optional[str], path_to_cache_dir: str):
255+
print("html2print: creating ChromeDriver service.", flush=True) # noqa: T201
208256
if chromedriver is None:
209-
path_to_chrome = get_chrome_driver(path_to_cache_dir)
257+
path_to_chrome = ChromeDriverManager().get_chrome_driver(
258+
path_to_cache_dir
259+
)
210260
else:
211261
path_to_chrome = chromedriver
212262
print(f"html2print: ChromeDriver available at path: {path_to_chrome}") # noqa: T201
@@ -295,22 +345,20 @@ def main():
295345
path_to_cache_dir: str
296346
if args.command == "get_driver":
297347
path_to_cache_dir = (
298-
args.cache_dir
299-
if args.cache_dir is not None
300-
else (DEFAULT_CACHE_DIR)
348+
args.cache_dir if args.cache_dir is not None else DEFAULT_CACHE_DIR
301349
)
302350

303-
path_to_chrome = get_chrome_driver(path_to_cache_dir)
351+
path_to_chrome = ChromeDriverManager().get_chrome_driver(
352+
path_to_cache_dir
353+
)
304354
print(f"html2print: ChromeDriver available at path: {path_to_chrome}") # noqa: T201
305355
sys.exit(0)
306356

307357
elif args.command == "print":
308358
paths: List[str] = args.paths
309359

310360
path_to_cache_dir = (
311-
args.cache_dir
312-
if args.cache_dir is not None
313-
else (DEFAULT_CACHE_DIR)
361+
args.cache_dir if args.cache_dir is not None else DEFAULT_CACHE_DIR
314362
)
315363
driver = create_webdriver(args.chromedriver, path_to_cache_dir)
316364

0 commit comments

Comments
 (0)