Skip to content

Commit ad6d093

Browse files
author
Jeffrey Wright
committed
Issue 434: Type annotations for basereport.py.
1 parent cfd32d0 commit ad6d093

File tree

1 file changed

+54
-34
lines changed

1 file changed

+54
-34
lines changed

src/pytest_html/basereport.py

Lines changed: 54 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -10,44 +10,64 @@
1010
from collections import defaultdict
1111
from html import escape
1212
from pathlib import Path
13+
from typing import Any
14+
from typing import DefaultDict
15+
from typing import Dict
16+
from typing import List
1317

1418
import pytest
19+
from _pytest.config import Config
20+
from _pytest.main import Session
21+
from _pytest.reports import CollectReport
22+
from _pytest.reports import TestReport
23+
from _pytest.terminal import TerminalReporter
24+
from jinja2.environment import Template
1525

1626
from pytest_html import __version__
1727
from pytest_html import extras
28+
from pytest_html.report_data import ReportData
1829

1930

2031
class BaseReport:
21-
def __init__(self, report_path, config, report_data, template, css):
22-
self._report_path = (
32+
def __init__(
33+
self,
34+
report_path: Path,
35+
config: Config,
36+
report_data: ReportData,
37+
template: Template,
38+
css: str,
39+
) -> None:
40+
self._report_path: Path = (
2341
Path.cwd() / Path(os.path.expandvars(report_path)).expanduser()
2442
)
2543
self._report_path.parent.mkdir(parents=True, exist_ok=True)
26-
self._config = config
27-
self._template = template
28-
self._css = css
29-
self._max_asset_filename_length = int(
44+
self._config: Config = config
45+
self._template: Template = template
46+
self._css: str = css
47+
self._max_asset_filename_length: int = int(
3048
config.getini("max_asset_filename_length")
3149
)
3250

33-
self._reports = defaultdict(dict)
34-
self._report = report_data
35-
self._report.title = self._report_path.name
51+
self._reports: DefaultDict = defaultdict(dict)
52+
self._report: ReportData = report_data
53+
self._report.title: str = self._report_path.name
3654

3755
@property
3856
def css(self):
3957
# implement in subclasses
4058
return
4159

42-
def _asset_filename(self, test_id, extra_index, test_index, file_extension):
60+
def _asset_filename(
61+
self, test_id: str, extra_index: int, test_index: int, file_extension: str
62+
) -> str:
4363
return "{}_{}_{}.{}".format(
4464
re.sub(r"[^\w.]", "_", test_id),
4565
str(extra_index),
4666
str(test_index),
4767
file_extension,
4868
)[-self._max_asset_filename_length :]
4969

50-
def _generate_report(self, self_contained=False):
70+
def _generate_report(self, self_contained: bool = False) -> None:
5171
generated = datetime.datetime.now()
5272
test_data = self._report.data
5373
test_data = json.dumps(test_data)
@@ -68,7 +88,7 @@ def _generate_report(self, self_contained=False):
6888

6989
self._write_report(rendered_report)
7090

71-
def _generate_environment(self):
91+
def _generate_environment(self) -> Dict[str, Any]:
7292
try:
7393
from pytest_metadata.plugin import metadata_key
7494

@@ -89,21 +109,21 @@ def _generate_environment(self):
89109

90110
return metadata
91111

92-
def _is_redactable_environment_variable(self, environment_variable):
112+
def _is_redactable_environment_variable(self, environment_variable: str) -> bool:
93113
redactable_regexes = self._config.getini("environment_table_redact_list")
94114
for redactable_regex in redactable_regexes:
95115
if re.match(redactable_regex, environment_variable):
96116
return True
97117

98118
return False
99119

100-
def _data_content(self, *args, **kwargs):
120+
def _data_content(self, *args, **kwargs) -> None:
101121
pass
102122

103-
def _media_content(self, *args, **kwargs):
123+
def _media_content(self, *args, **kwargs) -> None:
104124
pass
105125

106-
def _process_extras(self, report, test_id):
126+
def _process_extras(self, report: CollectReport, test_id: str) -> List[Any]:
107127
test_index = hasattr(report, "rerun") and report.rerun + 1 or 0
108128
report_extras = getattr(report, "extras", [])
109129
for extra_index, extra in enumerate(report_extras):
@@ -134,12 +154,12 @@ def _process_extras(self, report, test_id):
134154

135155
return report_extras
136156

137-
def _write_report(self, rendered_report):
157+
def _write_report(self, rendered_report: str) -> None:
138158
with self._report_path.open("w", encoding="utf-8") as f:
139159
f.write(rendered_report)
140160

141-
def _run_count(self):
142-
relevant_outcomes = ["passed", "failed", "xpassed", "xfailed"]
161+
def _run_count(self) -> str:
162+
relevant_outcomes: List[str] = ["passed", "failed", "xpassed", "xfailed"]
143163
counts = 0
144164
for outcome in self._report.outcomes.keys():
145165
if outcome in relevant_outcomes:
@@ -153,7 +173,7 @@ def _run_count(self):
153173

154174
return f"{counts}/{self._report.collected_items} {'tests' if plural else 'test'} done."
155175

156-
def _hydrate_data(self, data, cells):
176+
def _hydrate_data(self, data: Dict[str, List], cells: List[str]) -> None:
157177
for index, cell in enumerate(cells):
158178
# extract column name and data if column is sortable
159179
if "sortable" in self._report.table_header[index]:
@@ -163,7 +183,7 @@ def _hydrate_data(self, data, cells):
163183
data[name_match.group(1)] = data_match.group(1)
164184

165185
@pytest.hookimpl(trylast=True)
166-
def pytest_sessionstart(self, session):
186+
def pytest_sessionstart(self, session: Session) -> None:
167187
self._report.set_data("environment", self._generate_environment())
168188

169189
session.config.hook.pytest_html_report_title(report=self._report)
@@ -176,7 +196,7 @@ def pytest_sessionstart(self, session):
176196
self._generate_report()
177197

178198
@pytest.hookimpl(trylast=True)
179-
def pytest_sessionfinish(self, session):
199+
def pytest_sessionfinish(self, session: Session) -> None:
180200
session.config.hook.pytest_html_results_summary(
181201
prefix=self._report.additional_summary["prefix"],
182202
summary=self._report.additional_summary["summary"],
@@ -187,23 +207,23 @@ def pytest_sessionfinish(self, session):
187207
self._generate_report()
188208

189209
@pytest.hookimpl(trylast=True)
190-
def pytest_terminal_summary(self, terminalreporter):
210+
def pytest_terminal_summary(self, terminalreporter: TerminalReporter) -> None:
191211
terminalreporter.write_sep(
192212
"-",
193213
f"Generated html report: {self._report_path.as_uri()}",
194214
)
195215

196216
@pytest.hookimpl(trylast=True)
197-
def pytest_collectreport(self, report):
217+
def pytest_collectreport(self, report: CollectReport) -> None:
198218
if report.failed:
199219
self._process_report(report, 0)
200220

201221
@pytest.hookimpl(trylast=True)
202-
def pytest_collection_finish(self, session):
222+
def pytest_collection_finish(self, session: Session) -> None:
203223
self._report.collected_items = len(session.items)
204224

205225
@pytest.hookimpl(trylast=True)
206-
def pytest_runtest_logreport(self, report):
226+
def pytest_runtest_logreport(self, report: TestReport) -> None:
207227
if hasattr(report, "duration_formatter"):
208228
warnings.warn(
209229
"'duration_formatter' has been removed and no longer has any effect!"
@@ -247,7 +267,7 @@ def pytest_runtest_logreport(self, report):
247267
if self._config.getini("generate_report_on_test"):
248268
self._generate_report()
249269

250-
def _process_report(self, report, duration):
270+
def _process_report(self, report: TestReport, duration: int) -> None:
251271
outcome = _process_outcome(report)
252272
try:
253273
# hook returns as list for some reason
@@ -291,9 +311,9 @@ def _process_report(self, report, duration):
291311
self._report.add_test(data, report, outcome, processed_logs)
292312

293313

294-
def _format_duration(duration):
314+
def _format_duration(duration: float) -> str:
295315
if duration < 1:
296-
return "{} ms".format(round(duration * 1000))
316+
return f"{round(duration * 1000)} ms"
297317

298318
hours = math.floor(duration / 3600)
299319
remaining_seconds = duration % 3600
@@ -304,13 +324,13 @@ def _format_duration(duration):
304324
return f"{hours:02d}:{minutes:02d}:{seconds:02d}"
305325

306326

307-
def _is_error(report):
327+
def _is_error(report: BaseReport) -> bool:
308328
return (
309329
report.when in ["setup", "teardown", "collect"] and report.outcome == "failed"
310330
)
311331

312332

313-
def _process_logs(report):
333+
def _process_logs(report) -> List[str]:
314334
log = []
315335
if report.longreprtext:
316336
log.append(escape(report.longreprtext) + "\n")
@@ -330,7 +350,7 @@ def _process_logs(report):
330350
return log
331351

332352

333-
def _process_outcome(report):
353+
def _process_outcome(report: TestReport) -> str:
334354
if _is_error(report):
335355
return "Error"
336356
if hasattr(report, "wasxfail"):
@@ -342,12 +362,12 @@ def _process_outcome(report):
342362
return report.outcome.capitalize()
343363

344364

345-
def _process_links(links):
365+
def _process_links(links) -> str:
346366
a_tag = '<a target="_blank" href="{content}" class="col-links__extra {format_type}">{name}</a>'
347367
return "".join([a_tag.format_map(link) for link in links])
348368

349369

350-
def _fix_py(cells):
370+
def _fix_py(cells: List[str]) -> List[str]:
351371
# backwards-compat
352372
new_cells = []
353373
for html in cells:

0 commit comments

Comments
 (0)