Skip to content

Commit 2dd95c6

Browse files
authored
tasks: add lint tasks: lint, format, mypy (#9)
1 parent f0edc50 commit 2dd95c6

File tree

6 files changed

+185
-29
lines changed

6 files changed

+185
-29
lines changed

hpdf/hpdf.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,11 @@
44
import base64
55
import os.path
66
import sys
7-
import tempfile
87
from datetime import datetime
98
from pathlib import Path
109
from shutil import copy
1110
from time import sleep
12-
from typing import Optional, List
11+
from typing import Dict, List, Optional
1312

1413
import requests
1514
from requests import Response
@@ -151,25 +150,28 @@ def get_pdf_from_html(driver, url) -> bytes:
151150
print("html2pdf: executing print command with ChromeDriver.") # noqa: T201
152151
result = driver.execute_cdp_cmd("Page.printToPDF", calculated_print_options)
153152

154-
class Done(Exception): pass
153+
class Done(Exception):
154+
pass
155155

156156
datetime_start = datetime.today()
157157

158-
logs = None
158+
logs: List[Dict[str, str]] = []
159159
try:
160160
while True:
161161
logs = driver.get_log("browser")
162162
for entry_ in logs:
163163
if "HTML2PDF4DOC time" in entry_["message"]:
164-
print("success: HTML2PDF completed its job.")
164+
print("success: HTML2PDF completed its job.") # noqa: T201
165165
raise Done
166166
if (datetime.today() - datetime_start).total_seconds() > 60:
167167
raise TimeoutError
168168
sleep(0.5)
169169
except Done:
170170
pass
171171
except TimeoutError:
172-
print("error: could not receive a successful completion status from HTML2PDF.")
172+
print( # noqa: T201
173+
"error: could not receive a successful completion status from HTML2PDF."
174+
)
173175
sys.exit(1)
174176

175177
print("html2pdf: JS logs from the print session:") # noqa: T201
@@ -244,19 +246,15 @@ def main():
244246
type=str,
245247
help="Optional path to a cache directory whereto the ChromeDriver is downloaded.",
246248
)
247-
parser.add_argument("paths", nargs='+', help="Paths to input HTML file.")
249+
parser.add_argument("paths", nargs="+", help="Paths to input HTML file.")
248250
args = parser.parse_args()
249251

250252
paths: List[str] = args.paths
251253

252254
path_to_cache_dir: str = (
253255
args.cache_dir
254256
if args.cache_dir is not None
255-
else (
256-
os.path.join(
257-
Path.home(), ".hpdf", "chromedriver"
258-
)
259-
)
257+
else (os.path.join(Path.home(), ".hpdf", "chromedriver"))
260258
)
261259
driver = create_webdriver(args.chromedriver, path_to_cache_dir)
262260

@@ -265,7 +263,9 @@ def exit_handler():
265263
print("html2pdf: exit handler: quitting the ChromeDriver.") # noqa: T201
266264
driver.quit()
267265

268-
assert len(paths) % 2 == 0, f"Expecting an even number of input/output path arguments: {paths}."
266+
assert len(paths) % 2 == 0, (
267+
f"Expecting an even number of input/output path arguments: {paths}."
268+
)
269269
for current_pair_idx in range(0, 2, len(paths)):
270270
path_to_input_html = paths[current_pair_idx]
271271
path_to_output_pdf = paths[current_pair_idx + 1]

requirements.development.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@ toml
33
packaging
44
setuptools
55

6+
#
7+
# Lint
8+
#
9+
mypy>=0.910
10+
ruff>=0.9
11+
612
#
713
# Integration tests
814
#

ruff.toml

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
target-version = "py38"
2+
line-length = 80
3+
4+
[lint]
5+
select = [
6+
"A",
7+
"ARG",
8+
"B",
9+
# "BLE",
10+
"C",
11+
"C4",
12+
# "C90" mccabe
13+
14+
# Not clear if this check is useful. Too many commas everywhere.
15+
# "COM",
16+
17+
# "D",
18+
# "DTZ",
19+
# "E",
20+
"EXE",
21+
"ERA",
22+
"F",
23+
# "FBT",
24+
"G",
25+
"I",
26+
"ISC",
27+
"ICN",
28+
# "N",
29+
"PGH",
30+
# "PIE",
31+
"PL", # Pylint
32+
# "PT", # pytest
33+
# "PTH",
34+
"Q", # Quotes
35+
# "RET",
36+
# "RUF",
37+
# "S",
38+
# "SIM",
39+
# "SLF",
40+
"T20",
41+
# "TCH",
42+
# "TRY",
43+
"UP",
44+
"W",
45+
"YTT",
46+
]
47+
48+
ignore = [
49+
# TBD: Unnecessary `list` comprehension (rewrite using `list()`)
50+
"C416",
51+
# TBD: Unnecessary `map` usage (rewrite using a `list` comprehension)
52+
"C417",
53+
54+
# X is too complex
55+
"C901",
56+
57+
"E501", # (line length violations).
58+
59+
# A warning by ruff format:
60+
# warning: The following rules may cause conflicts when used with the formatter: `ISC001`.
61+
"ISC001",
62+
63+
# Too many return statements
64+
"PLR0911",
65+
66+
# Too many branches
67+
"PLR0912",
68+
69+
# Too many arguments in function definition
70+
"PLR0913",
71+
72+
# Too many statements
73+
"PLR0915",
74+
75+
# TBD: Enable: Use `sys.exit()` instead of `exit`
76+
"PLR1722",
77+
78+
# Magic value used in comparison
79+
"PLR2004",
80+
81+
# Use `elif` instead of `else` then `if`, to reduce indentation
82+
"PLR5501",
83+
84+
"UP035", # [*] Import from `collections.abc` instead: `Iterator`
85+
"UP038", # [*] Use `X | Y` in `isinstance` call instead of `(X, Y)` (conflict with Pylint)
86+
]
87+
88+
# Avoid trying to fix flake8-bugbear (`B`) violations.
89+
unfixable = ["B"]
90+
91+
# Skip non UTF-8 test files
92+
# exclude = ["tests/**/invalid_file*"]
93+
94+
# B008 Do not perform function calls in argument defaults.
95+
# The call is performed only once at function definition time.
96+
97+
[lint.per-file-ignores]
98+
# "foo.py" = ["B008"]
99+
100+
# Some of our helpers have deliberatly the name of a standard library module
101+
102+
[lint.flake8-builtins]
103+
builtins-allowed-modules = ["math", "pickle", "string"]

tasks.py

Lines changed: 59 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,21 +60,76 @@ def bootstrap(context):
6060

6161
@task
6262
def build(context):
63-
run_invoke(context, "cd submodules/html2pdf && npm install && npm run build")
63+
run_invoke(
64+
context, "cd submodules/html2pdf && npm install && npm run build"
65+
)
6466

6567

6668
@task
6769
def format_readme(context):
68-
run_invoke(context, """
70+
run_invoke(
71+
context,
72+
"""
6973
prettier
7074
--write --print-width 80 --prose-wrap always --parser=markdown
7175
README.md
72-
""")
76+
""",
77+
)
7378

7479

7580
@task
81+
def lint_ruff_format(context):
82+
result: invoke.runners.Result = run_invoke(
83+
context,
84+
"""
85+
ruff
86+
format
87+
*.py
88+
hpdf/
89+
tests/integration/
90+
""",
91+
)
92+
# Ruff always exits with 0, so we handle the output.
93+
if "reformatted" in result.stdout:
94+
print("invoke: ruff format found issues") # noqa: T201
95+
result.exited = 1
96+
raise invoke.exceptions.UnexpectedExit(result)
97+
98+
99+
@task(aliases=["lr"])
100+
def lint_ruff(context):
101+
run_invoke(
102+
context,
103+
"""
104+
ruff check *.py hpdf/ --fix --cache-dir build/ruff
105+
""",
106+
)
107+
108+
109+
@task(aliases=["lm"])
110+
def lint_mypy(context):
111+
# These checks do not seem to be useful:
112+
# - import
113+
# - misc
114+
run_invoke(
115+
context,
116+
"""
117+
mypy hpdf/
118+
--show-error-codes
119+
--disable-error-code=import
120+
--disable-error-code=misc
121+
--cache-dir=build/mypy
122+
--strict
123+
--python-version=3.8
124+
""",
125+
)
126+
127+
128+
@task(aliases=["l"])
76129
def lint(context):
77-
pass
130+
lint_ruff_format(context)
131+
lint_ruff(context)
132+
lint_mypy(context)
78133

79134

80135
@task

tests/integration/check_exists.py

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -56,25 +56,19 @@
5656
else:
5757
if os.path.exists(args.input_path):
5858
print( # noqa: T201
59-
"error: expected path to not exist, but it does: {}".format(
60-
args.input_path
61-
),
59+
f"error: expected path to not exist, but it does: {args.input_path}",
6260
file=sys.stderr,
6361
)
6462
exit(1)
6563
if args.file and os.path.isfile(args.input_path):
6664
print( # noqa: T201
67-
"error: expected path to not exist, but is a file: {}".format(
68-
args.input_path
69-
),
65+
f"error: expected path to not exist, but is a file: {args.input_path}",
7066
file=sys.stderr,
7167
)
7268
exit(1)
7369
if args.dir and os.path.isdir(args.input_path):
7470
print( # noqa: T201
75-
"error: expected path to not exist, but is a directory: {}".format(
76-
args.input_path
77-
),
71+
f"error: expected path to not exist, but is a directory: {args.input_path}",
7872
file=sys.stderr,
7973
)
8074
exit(1)

tests/integration/expect_exit.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,7 @@
5151
unexpected_exit_code = process.returncode != expected_exit_code
5252
if unexpected_exit_code:
5353
print( # noqa: T201
54-
"error: expect_exit: expected exit code: {}, actual: {}".format(
55-
expected_exit_code, process.returncode
56-
)
54+
f"error: expect_exit: expected exit code: {expected_exit_code}, actual: {process.returncode}"
5755
)
5856

5957
unexpected_content = expect_no_content and len(stdout) > 0

0 commit comments

Comments
 (0)