summaryrefslogtreecommitdiff
path: root/coverage
diff options
context:
space:
mode:
authorNed Batchelder <ned@nedbatchelder.com>2023-01-04 07:03:10 -0500
committerNed Batchelder <ned@nedbatchelder.com>2023-01-04 07:03:10 -0500
commitdbb94d570a2042409400c28ba3069dcb32a45159 (patch)
tree41caedd28b1d5cb99a76d8104566d309724eeeb7 /coverage
parentfaa62d3f3d90c15e72040479a9b237ca86bbeae1 (diff)
downloadpython-coveragepy-git-dbb94d570a2042409400c28ba3069dcb32a45159.tar.gz
mypy: summary.py, test_summary.py, tests/coveragetest.py
Diffstat (limited to 'coverage')
-rw-r--r--coverage/config.py2
-rw-r--r--coverage/control.py28
-rw-r--r--coverage/debug.py5
-rw-r--r--coverage/misc.py8
-rw-r--r--coverage/parser.py2
-rw-r--r--coverage/plugin.py2
-rw-r--r--coverage/python.py2
-rw-r--r--coverage/summary.py51
-rw-r--r--coverage/types.py7
9 files changed, 71 insertions, 36 deletions
diff --git a/coverage/config.py b/coverage/config.py
index 3e535949..04bde26f 100644
--- a/coverage/config.py
+++ b/coverage/config.py
@@ -518,7 +518,7 @@ class CoverageConfig(TConfigurable):
for k, v in self.paths.items()
)
- def debug_info(self) -> Iterable[Tuple[str, Any]]:
+ def debug_info(self) -> List[Tuple[str, Any]]:
"""Make a list of (name, value) pairs for writing debug info."""
return human_sorted_items(
(k, v) for k, v in self.__dict__.items() if not k.startswith("_")
diff --git a/coverage/control.py b/coverage/control.py
index 8ac6781e..acd89b94 100644
--- a/coverage/control.py
+++ b/coverage/control.py
@@ -122,8 +122,8 @@ class Coverage(TConfigurable):
config_file: Union[str, bool]=True,
source: Optional[List[str]]=None,
source_pkgs: Optional[List[str]]=None,
- omit: Optional[List[str]]=None,
- include: Optional[List[str]]=None,
+ omit: Optional[Union[str, List[str]]]=None,
+ include: Optional[Union[str, List[str]]]=None,
debug: Optional[List[str]]=None,
concurrency: Optional[Union[str, List[str]]]=None,
check_preimported: bool=False,
@@ -959,8 +959,8 @@ class Coverage(TConfigurable):
show_missing: Optional[bool]=None,
ignore_errors: Optional[bool]=None,
file: Optional[IO[str]]=None,
- omit: Optional[List[str]]=None,
- include: Optional[List[str]]=None,
+ omit: Optional[Union[str, List[str]]]=None,
+ include: Optional[Union[str, List[str]]]=None,
skip_covered: Optional[bool]=None,
contexts: Optional[List[str]]=None,
skip_empty: Optional[bool]=None,
@@ -1040,8 +1040,8 @@ class Coverage(TConfigurable):
morfs: Optional[Iterable[TMorf]]=None,
directory: Optional[str]=None,
ignore_errors: Optional[bool]=None,
- omit: Optional[List[str]]=None,
- include: Optional[List[str]]=None,
+ omit: Optional[Union[str, List[str]]]=None,
+ include: Optional[Union[str, List[str]]]=None,
contexts: Optional[List[str]]=None,
) -> None:
"""Annotate a list of modules.
@@ -1079,8 +1079,8 @@ class Coverage(TConfigurable):
morfs: Optional[Iterable[TMorf]]=None,
directory: Optional[str]=None,
ignore_errors: Optional[bool]=None,
- omit: Optional[List[str]]=None,
- include: Optional[List[str]]=None,
+ omit: Optional[Union[str, List[str]]]=None,
+ include: Optional[Union[str, List[str]]]=None,
extra_css: Optional[str]=None,
title: Optional[str]=None,
skip_covered: Optional[bool]=None,
@@ -1137,8 +1137,8 @@ class Coverage(TConfigurable):
morfs: Optional[Iterable[TMorf]]=None,
outfile: Optional[str]=None,
ignore_errors: Optional[bool]=None,
- omit: Optional[List[str]]=None,
- include: Optional[List[str]]=None,
+ omit: Optional[Union[str, List[str]]]=None,
+ include: Optional[Union[str, List[str]]]=None,
contexts: Optional[List[str]]=None,
skip_empty: Optional[bool]=None,
) -> float:
@@ -1171,8 +1171,8 @@ class Coverage(TConfigurable):
morfs: Optional[Iterable[TMorf]]=None,
outfile: Optional[str]=None,
ignore_errors: Optional[bool]=None,
- omit: Optional[List[str]]=None,
- include: Optional[List[str]]=None,
+ omit: Optional[Union[str, List[str]]]=None,
+ include: Optional[Union[str, List[str]]]=None,
contexts: Optional[List[str]]=None,
pretty_print: Optional[bool]=None,
show_contexts: Optional[bool]=None,
@@ -1209,8 +1209,8 @@ class Coverage(TConfigurable):
morfs: Optional[Iterable[TMorf]]=None,
outfile: Optional[str]=None,
ignore_errors: Optional[bool]=None,
- omit: Optional[List[str]]=None,
- include: Optional[List[str]]=None,
+ omit: Optional[Union[str, List[str]]]=None,
+ include: Optional[Union[str, List[str]]]=None,
contexts: Optional[List[str]]=None,
) -> float:
"""Generate an LCOV report of coverage results.
diff --git a/coverage/debug.py b/coverage/debug.py
index 82de3c29..a3d1dfa8 100644
--- a/coverage/debug.py
+++ b/coverage/debug.py
@@ -23,6 +23,7 @@ from typing import (
)
from coverage.misc import isolate_module
+from coverage.types import TWritable
os = isolate_module(os)
@@ -184,7 +185,7 @@ def short_stack(limit: Optional[int]=None, skip: int=0) -> str:
def dump_stack_frames(
limit: Optional[int]=None,
- out: Optional[IO[str]]=None,
+ out: Optional[TWritable]=None,
skip: int=0
) -> None:
"""Print a summary of the stack to stdout, or someplace else."""
@@ -371,7 +372,7 @@ class DebugOutputFile: # pragma: debugging
self.outfile.flush()
-def log(msg, stack=False): # pragma: debugging
+def log(msg: str, stack: bool=False) -> None: # pragma: debugging
"""Write a log message as forcefully as possible."""
out = DebugOutputFile.get_one(interim=True)
out.write(msg+"\n")
diff --git a/coverage/misc.py b/coverage/misc.py
index a2ac2fed..9b42d841 100644
--- a/coverage/misc.py
+++ b/coverage/misc.py
@@ -22,7 +22,7 @@ import types
from types import ModuleType
from typing import (
Any, Callable, Dict, Generator, IO, Iterable, List, Mapping, Optional,
- Tuple, TypeVar, Union,
+ Sequence, Tuple, TypeVar, Union,
)
from coverage import env
@@ -361,10 +361,12 @@ def human_sorted(strings: Iterable[str]) -> List[str]:
"""
return sorted(strings, key=_human_key)
+SortableItem = TypeVar("SortableItem", bound=Sequence[Any])
+
def human_sorted_items(
- items: Iterable[Tuple[str, Any]],
+ items: Iterable[SortableItem],
reverse: bool=False,
-) -> List[Tuple[str, Any]]:
+) -> List[SortableItem]:
"""Sort (string, ...) items the way humans expect.
The elements of `items` can be any tuple/list. They'll be sorted by the
diff --git a/coverage/parser.py b/coverage/parser.py
index 2a8d0a50..cb4e6474 100644
--- a/coverage/parser.py
+++ b/coverage/parser.py
@@ -328,7 +328,7 @@ class PythonParser:
self,
start: TLineNo,
end: TLineNo,
- executed_arcs: Optional[Set[TArc]]=None,
+ executed_arcs: Optional[Iterable[TArc]]=None,
) -> str:
"""Provide an English sentence describing a missing arc."""
if self._missing_arc_fragments is None:
diff --git a/coverage/plugin.py b/coverage/plugin.py
index ccc33337..da91aac4 100644
--- a/coverage/plugin.py
+++ b/coverage/plugin.py
@@ -496,7 +496,7 @@ class FileReporter(CoveragePluginBase):
self,
start: TLineNo,
end: TLineNo,
- executed_arcs: Optional[Set[TArc]]=None, # pylint: disable=unused-argument
+ executed_arcs: Optional[Iterable[TArc]]=None, # pylint: disable=unused-argument
) -> str:
"""Provide an English sentence describing a missing arc.
diff --git a/coverage/python.py b/coverage/python.py
index 2d2faa14..c25a03fd 100644
--- a/coverage/python.py
+++ b/coverage/python.py
@@ -224,7 +224,7 @@ class PythonFileReporter(FileReporter):
self,
start: TLineNo,
end: TLineNo,
- executed_arcs: Optional[Set[TArc]]=None,
+ executed_arcs: Optional[Iterable[TArc]]=None,
) -> str:
return self.parser.missing_arc_description(start, end, executed_arcs)
diff --git a/coverage/summary.py b/coverage/summary.py
index 3f3fd688..287e7593 100644
--- a/coverage/summary.py
+++ b/coverage/summary.py
@@ -3,40 +3,56 @@
"""Summary reporting"""
+from __future__ import annotations
+
import sys
+from typing import Any, IO, Iterable, List, Optional, Tuple, TYPE_CHECKING
+
from coverage.exceptions import ConfigError, NoDataError
from coverage.misc import human_sorted_items
+from coverage.plugin import FileReporter
from coverage.report import get_analysis_to_report
-from coverage.results import Numbers
+from coverage.results import Analysis, Numbers
+from coverage.types import TMorf
+
+if TYPE_CHECKING:
+ from coverage import Coverage
class SummaryReporter:
"""A reporter for writing the summary report."""
- def __init__(self, coverage):
+ def __init__(self, coverage: Coverage) -> None:
self.coverage = coverage
self.config = self.coverage.config
self.branches = coverage.get_data().has_arcs()
- self.outfile = None
+ self.outfile: Optional[IO[str]] = None
self.output_format = self.config.format or "text"
if self.output_format not in {"text", "markdown", "total"}:
raise ConfigError(f"Unknown report format choice: {self.output_format!r}")
- self.fr_analysis = []
+ self.fr_analysis: List[Tuple[FileReporter, Analysis]] = []
self.skipped_count = 0
self.empty_count = 0
self.total = Numbers(precision=self.config.precision)
- def write(self, line):
+ def write(self, line: str) -> None:
"""Write a line to the output, adding a newline."""
+ assert self.outfile is not None
self.outfile.write(line.rstrip())
self.outfile.write("\n")
- def write_items(self, items):
+ def write_items(self, items: Iterable[str]) -> None:
"""Write a list of strings, joined together."""
self.write("".join(items))
- def _report_text(self, header, lines_values, total_line, end_lines):
+ def _report_text(
+ self,
+ header: List[str],
+ lines_values: List[List[Any]],
+ total_line: List[Any],
+ end_lines: List[str],
+ ) -> None:
"""Internal method that prints report data in text format.
`header` is a list with captions.
@@ -91,7 +107,13 @@ class SummaryReporter:
for end_line in end_lines:
self.write(end_line)
- def _report_markdown(self, header, lines_values, total_line, end_lines):
+ def _report_markdown(
+ self,
+ header: List[str],
+ lines_values: List[List[Any]],
+ total_line: List[Any],
+ end_lines: List[str],
+ ) -> None:
"""Internal method that prints report data in markdown format.
`header` is a list with captions.
@@ -134,7 +156,7 @@ class SummaryReporter:
# Write the TOTAL line
formats.update(dict(Name="|{:>{name_len}} |", Cover="{:>{n}} |"))
- total_line_items = []
+ total_line_items: List[str] = []
for item, value in zip(header, total_line):
if value == "":
insert = value
@@ -147,7 +169,7 @@ class SummaryReporter:
for end_line in end_lines:
self.write(end_line)
- def report(self, morfs, outfile=None) -> float:
+ def report(self, morfs: Optional[Iterable[TMorf]], outfile: Optional[IO[str]]=None) -> float:
"""Writes a report summarizing coverage statistics per module.
`outfile` is a text-mode file object to write the summary to.
@@ -169,7 +191,7 @@ class SummaryReporter:
return self.total.pc_covered
- def tabular_report(self):
+ def tabular_report(self) -> None:
"""Writes tabular report formats."""
# Prepare the header line and column sorting.
header = ["Name", "Stmts", "Miss"]
@@ -212,7 +234,10 @@ class SummaryReporter:
if sort_option == "name":
lines_values = human_sorted_items(lines_values, reverse=reverse)
else:
- lines_values.sort(key=lambda line: (line[sort_idx], line[0]), reverse=reverse)
+ lines_values.sort(
+ key=lambda line: (line[sort_idx], line[0]), # type: ignore[index]
+ reverse=reverse,
+ )
# Calculate total if we had at least one file.
total_line = ["TOTAL", self.total.n_statements, self.total.n_missing]
@@ -239,7 +264,7 @@ class SummaryReporter:
formatter = self._report_text
formatter(header, lines_values, total_line, end_lines)
- def report_one_file(self, fr, analysis):
+ def report_one_file(self, fr: FileReporter, analysis: Analysis) -> None:
"""Report on just one file, the callback from report()."""
nums = analysis.numbers
self.total += nums
diff --git a/coverage/types.py b/coverage/types.py
index 54c1dfba..ed22e699 100644
--- a/coverage/types.py
+++ b/coverage/types.py
@@ -166,3 +166,10 @@ class TDebugCtl(Protocol):
def write(self, msg: str) -> None:
"""Write a line of debug output."""
+
+
+class TWritable(Protocol):
+ """Anything that can be written to."""
+
+ def write(self, msg: str) -> None:
+ """Write a message."""