Skip to content

Commit 0829768

Browse files
authored
Merge pull request #70 from strictdoc-project/stanislaw/handle
feat: improve error message when chrome is not yet installed
2 parents 1352912 + 2cafc22 commit 0829768

File tree

7 files changed

+102
-14
lines changed

7 files changed

+102
-14
lines changed

.github/workflows/ci-mac.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ on:
66

77
jobs:
88
build:
9-
runs-on: macos-13
9+
runs-on: macos-latest
1010

1111
strategy:
1212
matrix:

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,5 @@ __pycache__/
1515

1616
# Fuzz testing files.
1717
**.mut.**
18+
19+
.coverage

html2pdf4doc/main.py

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import sys
1010
import zipfile
1111
from datetime import datetime
12+
from enum import IntEnum
1213
from pathlib import Path
1314
from time import sleep, time
1415
from typing import Any, Dict, Iterator, List, Optional, Tuple, Union
@@ -58,6 +59,18 @@ def extract_page_count(logs: List[Dict[str, str]]) -> int:
5859
raise ValueError("No page count found in logs.")
5960

6061

62+
class HPDExitCode(IntEnum):
63+
GENERAL_ERROR = 1
64+
COULD_NOT_FIND_CHROME = 5
65+
DID_NOT_RECEIVE_SUCCESS_STATUS_FROM_HTML2PDF4DOC_JS = 6
66+
67+
68+
class HPDError(RuntimeError):
69+
def __init__(self, message: str, exit_code: int):
70+
super().__init__(message)
71+
self.exit_code: int = exit_code
72+
73+
6174
class IntRange:
6275
def __init__(self, imin: int, imax: int) -> None:
6376
self.imin: int = imin
@@ -87,9 +100,9 @@ def get_chrome_driver(self, path_to_cache_dir: str) -> str:
87100

88101
# If Web Driver Manager cannot detect Chrome, it returns None.
89102
if chrome_version is None:
90-
raise RuntimeError(
91-
"html2pdf4doc: "
92-
"Web Driver Manager could not detect an existing Chrome installation."
103+
raise HPDError(
104+
"Web Driver Manager could not detect an existing Chrome installation.",
105+
exit_code=HPDExitCode.COULD_NOT_FIND_CHROME,
93106
)
94107

95108
chrome_major_version = chrome_version.split(".")[0]
@@ -145,15 +158,16 @@ def get_chrome_driver(self, path_to_cache_dir: str) -> str:
145158

146159
return path_to_downloaded_chrome_driver
147160

148-
@staticmethod
161+
@classmethod
149162
def _download_chromedriver(
163+
cls,
150164
chrome_major_version: str,
151165
os_type: str,
152166
path_to_driver_cache_dir: str,
153167
path_to_cached_chrome_driver: str,
154168
) -> str:
155169
url = "https://googlechromelabs.github.io/chrome-for-testing/known-good-versions-with-downloads.json"
156-
response = ChromeDriverManager.send_http_get_request(url)
170+
response = cls.send_http_get_request(url)
157171
if response is None:
158172
raise RuntimeError(
159173
"Could not download known-good-versions-with-downloads.json"
@@ -195,7 +209,7 @@ def _download_chromedriver(
195209
print( # noqa: T201
196210
f"html2pdf4doc: downloading ChromeDriver from: {driver_url}"
197211
)
198-
response = ChromeDriverManager.send_http_get_request(driver_url)
212+
response = cls.send_http_get_request(driver_url)
199213

200214
if response is None:
201215
raise RuntimeError(
@@ -360,7 +374,9 @@ def __init__(self, page_count: int):
360374
"error: html2pdf4doc: "
361375
"could not receive a successful completion status from HTML2PDF4Doc."
362376
)
363-
sys.exit(1)
377+
sys.exit(
378+
HPDExitCode.DID_NOT_RECEIVE_SUCCESS_STATUS_FROM_HTML2PDF4DOC_JS
379+
)
364380

365381
bad_logs: List[Dict[str, str]] = []
366382

@@ -402,6 +418,7 @@ def __init__(self, page_count: int):
402418

403419

404420
def create_webdriver(
421+
chrome_driver_manager: ChromeDriverManager,
405422
chromedriver_argument: Optional[str],
406423
path_to_cache_dir: str,
407424
page_load_timeout: int,
@@ -411,7 +428,7 @@ def create_webdriver(
411428

412429
path_to_chrome_driver: str
413430
if chromedriver_argument is None:
414-
path_to_chrome_driver = ChromeDriverManager().get_chrome_driver(
431+
path_to_chrome_driver = chrome_driver_manager.get_chrome_driver(
415432
path_to_cache_dir
416433
)
417434
else:
@@ -475,7 +492,7 @@ def create_webdriver(
475492
return driver
476493

477494

478-
def main() -> None:
495+
def _main() -> None:
479496
if not os.path.isfile(PATH_TO_HTML2PDF4DOC_JS):
480497
raise RuntimeError(
481498
f"Corrupted html2pdf4doc package bundle. "
@@ -573,13 +590,15 @@ def main() -> None:
573590

574591
args = parser.parse_args()
575592

593+
chrome_driver_manager = ChromeDriverManager()
594+
576595
path_to_cache_dir: str
577596
if args.command == "get_driver":
578597
path_to_cache_dir = (
579598
args.cache_dir if args.cache_dir is not None else DEFAULT_CACHE_DIR
580599
)
581600

582-
path_to_chrome = ChromeDriverManager().get_chrome_driver(
601+
path_to_chrome = chrome_driver_manager.get_chrome_driver(
583602
path_to_cache_dir
584603
)
585604
print(f"html2pdf4doc: ChromeDriver available at path: {path_to_chrome}") # noqa: T201
@@ -594,6 +613,7 @@ def main() -> None:
594613
args.cache_dir if args.cache_dir is not None else DEFAULT_CACHE_DIR
595614
)
596615
driver: webdriver.Chrome = create_webdriver(
616+
chrome_driver_manager,
597617
args.chromedriver,
598618
path_to_cache_dir,
599619
page_load_timeout,
@@ -645,7 +665,15 @@ def exit_handler() -> None:
645665

646666
else:
647667
print("html2pdf4doc: unknown command.") # noqa: T201
648-
sys.exit(1)
668+
sys.exit(HPDExitCode.GENERAL_ERROR)
669+
670+
671+
def main() -> None:
672+
try:
673+
_main()
674+
except HPDError as error_:
675+
print("error: html2pdf4doc: " + str(error_), flush=True) # noqa: T201
676+
sys.exit(error_.exit_code)
649677

650678

651679
if __name__ == "__main__":

mypy.ini

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[mypy]
2+
3+
# We ignore build folder but mypy still follows into the Python packages.
4+
# The following is a way to skip it.
5+
[mypy-_pytest.*]
6+
follow_imports = skip

requirements.development.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ ruff>=0.9
1515
# Unit tests
1616
#
1717
pytest
18+
coverage
1819

1920
#
2021
# Integration tests

tasks.py

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ def lint_ruff_format(context):
116116
format
117117
*.py
118118
html2pdf4doc/
119+
tests/unit/
119120
tests/integration/
120121
""",
121122
)
@@ -131,7 +132,7 @@ def lint_ruff(context):
131132
run_invoke(
132133
context,
133134
"""
134-
ruff check *.py html2pdf4doc/ --fix --cache-dir build/ruff
135+
ruff check *.py html2pdf4doc/ tests/unit/ --fix --cache-dir build/ruff
135136
""",
136137
)
137138

@@ -144,7 +145,7 @@ def lint_mypy(context):
144145
run_invoke(
145146
context,
146147
"""
147-
mypy html2pdf4doc/
148+
mypy html2pdf4doc/ tests/unit/
148149
--show-error-codes
149150
--disable-error-code=import
150151
--disable-error-code=misc
@@ -162,6 +163,29 @@ def lint(context):
162163
lint_mypy(context)
163164

164165

166+
@task(aliases=["tu"])
167+
def test_unit(context, focus=None, output=False):
168+
focus_argument = f"-k {focus}" if focus is not None else ""
169+
output_argument = "--capture=no" if output else ""
170+
171+
cwd = os.getcwd()
172+
173+
path_to_coverage_file = f"{cwd}/build/coverage/unit/.coverage"
174+
run_invoke(
175+
context,
176+
f"""
177+
coverage run
178+
--data-file={path_to_coverage_file}
179+
-m pytest
180+
{focus_argument}
181+
{output_argument}
182+
-o cache_dir=build/pytest_unit
183+
-o junit_suite_name="HTML2PDF4Doc unit tests"
184+
tests/unit/
185+
""",
186+
)
187+
188+
165189
@task(aliases=["ti"])
166190
def test_integration(
167191
context,
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import tempfile
2+
from typing import Optional
3+
4+
import pytest
5+
6+
from html2pdf4doc.main import ChromeDriverManager, HPDError, HPDExitCode
7+
8+
9+
class FailingChromeDriverManager(ChromeDriverManager):
10+
@staticmethod
11+
def get_chrome_version() -> Optional[str]:
12+
return None
13+
14+
15+
def test_raises_error_when_cannot_detect_chrome() -> None:
16+
"""
17+
This first unit test is not great but it is a good start anyway.
18+
"""
19+
20+
chrome_driver_manager = FailingChromeDriverManager()
21+
22+
with tempfile.TemporaryDirectory() as tmpdir:
23+
with pytest.raises(Exception) as exc_info:
24+
_ = chrome_driver_manager.get_chrome_driver(tmpdir)
25+
26+
assert exc_info.type is HPDError
27+
assert exc_info.value.exit_code == HPDExitCode.COULD_NOT_FIND_CHROME

0 commit comments

Comments
 (0)