summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNed Batchelder <ned@nedbatchelder.com>2022-12-31 19:04:31 -0500
committerNed Batchelder <ned@nedbatchelder.com>2022-12-31 20:39:09 -0500
commite3c523c98cbc9ecdd37e36da19848ca9d0aef4a3 (patch)
tree0857c3472c5858695d26f0276e8f1c5b3512a3e2
parent5a72a1eb736516759201b223463f69f00979818e (diff)
downloadpython-coveragepy-git-e3c523c98cbc9ecdd37e36da19848ca9d0aef4a3.tar.gz
mypy: add __init__.py, __main__.py, bytecode.py, context.py, exceptions.py, report.py, and version.py
-rw-r--r--coverage/bytecode.py7
-rw-r--r--coverage/context.py19
-rw-r--r--coverage/report.py33
-rw-r--r--coverage/version.py18
-rw-r--r--tox.ini7
5 files changed, 66 insertions, 18 deletions
diff --git a/coverage/bytecode.py b/coverage/bytecode.py
index ceb18cf3..15bf755b 100644
--- a/coverage/bytecode.py
+++ b/coverage/bytecode.py
@@ -3,10 +3,11 @@
"""Bytecode manipulation for coverage.py"""
-import types
+from types import CodeType
+from typing import Generator
-def code_objects(code):
+def code_objects(code: CodeType) -> Generator[CodeType, None, None]:
"""Iterate over all the code objects in `code`."""
stack = [code]
while stack:
@@ -14,6 +15,6 @@ def code_objects(code):
# push its children for later returning.
code = stack.pop()
for c in code.co_consts:
- if isinstance(c, types.CodeType):
+ if isinstance(c, CodeType):
stack.append(c)
yield code
diff --git a/coverage/context.py b/coverage/context.py
index 6bb1f1ee..3b8bc10f 100644
--- a/coverage/context.py
+++ b/coverage/context.py
@@ -3,8 +3,13 @@
"""Determine contexts for coverage.py"""
+from types import FrameType
+from typing import cast, Callable, Optional, Sequence
-def combine_context_switchers(context_switchers):
+
+def combine_context_switchers(
+ context_switchers: Sequence[Callable[[FrameType], Optional[str]]],
+) -> Optional[Callable[[FrameType], Optional[str]]]:
"""Create a single context switcher from multiple switchers.
`context_switchers` is a list of functions that take a frame as an
@@ -23,7 +28,7 @@ def combine_context_switchers(context_switchers):
if len(context_switchers) == 1:
return context_switchers[0]
- def should_start_context(frame):
+ def should_start_context(frame: FrameType) -> Optional[str]:
"""The combiner for multiple context switchers."""
for switcher in context_switchers:
new_context = switcher(frame)
@@ -34,7 +39,7 @@ def combine_context_switchers(context_switchers):
return should_start_context
-def should_start_context_test_function(frame):
+def should_start_context_test_function(frame: FrameType) -> Optional[str]:
"""Is this frame calling a test_* function?"""
co_name = frame.f_code.co_name
if co_name.startswith("test") or co_name == "runTest":
@@ -42,7 +47,7 @@ def should_start_context_test_function(frame):
return None
-def qualname_from_frame(frame):
+def qualname_from_frame(frame: FrameType) -> Optional[str]:
"""Get a qualified name for the code running in `frame`."""
co = frame.f_code
fname = co.co_name
@@ -55,11 +60,11 @@ def qualname_from_frame(frame):
func = frame.f_globals.get(fname)
if func is None:
return None
- return func.__module__ + "." + fname
+ return cast(str, func.__module__ + "." + fname)
func = getattr(method, "__func__", None)
if func is None:
cls = self.__class__
- return cls.__module__ + "." + cls.__name__ + "." + fname
+ return cast(str, cls.__module__ + "." + cls.__name__ + "." + fname)
- return func.__module__ + "." + func.__qualname__
+ return cast(str, func.__module__ + "." + func.__qualname__)
diff --git a/coverage/report.py b/coverage/report.py
index b44f9c8e..549ab307 100644
--- a/coverage/report.py
+++ b/coverage/report.py
@@ -3,14 +3,38 @@
"""Reporter foundation for coverage.py."""
+from __future__ import annotations
+
import sys
+from typing import Callable, Iterable, Iterator, IO, Optional, Tuple, TYPE_CHECKING
+
from coverage.exceptions import CoverageException, NoDataError, NotPython
from coverage.files import prep_patterns, GlobMatcher
from coverage.misc import ensure_dir_for_file, file_be_gone
+from coverage.plugin import FileReporter
+from coverage.results import Analysis
+from coverage.types import Protocol, TMorf
+
+if TYPE_CHECKING:
+ from coverage import Coverage
+
+
+class Reporter(Protocol):
+ """What we expect of reporters."""
+
+ report_type: str
+
+ def report(self, morfs: Optional[Iterable[TMorf]], outfile: IO[str]) -> float:
+ """Generate a report of `morfs`, written to `outfile`."""
-def render_report(output_path, reporter, morfs, msgfn) -> float:
+def render_report(
+ output_path: str,
+ reporter: Reporter,
+ morfs: Optional[Iterable[TMorf]],
+ msgfn: Callable[[str], None],
+) -> float:
"""Run a one-file report generator, managing the output file.
This function ensures the output file is ready to be written to. Then writes
@@ -45,7 +69,10 @@ def render_report(output_path, reporter, morfs, msgfn) -> float:
msgfn(f"Wrote {reporter.report_type} to {output_path}")
-def get_analysis_to_report(coverage, morfs):
+def get_analysis_to_report(
+ coverage: Coverage,
+ morfs: Iterable[TMorf]
+) -> Iterator[Tuple[FileReporter, Analysis]]:
"""Get the files to report on.
For each morf in `morfs`, if it should be reported on (based on the omit
@@ -75,7 +102,7 @@ def get_analysis_to_report(coverage, morfs):
# explicitly suppress those errors.
# NotPython is only raised by PythonFileReporter, which has a
# should_be_python() method.
- if fr.should_be_python():
+ if fr.should_be_python(): # type: ignore[attr-defined]
if config.ignore_errors:
msg = f"Couldn't parse Python file '{fr.filename}'"
coverage._warn(msg, slug="couldnt-parse")
diff --git a/coverage/version.py b/coverage/version.py
index dbddba1d..6fd9ec53 100644
--- a/coverage/version.py
+++ b/coverage/version.py
@@ -10,7 +10,14 @@ version_info = (7, 0, 2, "alpha", 0)
_dev = 1
-def _make_version(major, minor, micro, releaselevel="final", serial=0, dev=0):
+def _make_version(
+ major: int,
+ minor: int,
+ micro: int,
+ releaselevel: str="final",
+ serial: int=0,
+ dev: int=0,
+) -> str:
"""Create a readable version string from version_info tuple components."""
assert releaselevel in ['alpha', 'beta', 'candidate', 'final']
version = "%d.%d.%d" % (major, minor, micro)
@@ -22,7 +29,14 @@ def _make_version(major, minor, micro, releaselevel="final", serial=0, dev=0):
return version
-def _make_url(major, minor, micro, releaselevel, serial=0, dev=0):
+def _make_url(
+ major: int,
+ minor: int,
+ micro: int,
+ releaselevel: str,
+ serial: int=0,
+ dev: int=0,
+) -> str:
"""Make the URL people should start at for this version of coverage.py."""
url = "https://coverage.readthedocs.io"
if releaselevel != "final" or dev != 0:
diff --git a/tox.ini b/tox.ini
index 67464c00..8d9c9891 100644
--- a/tox.ini
+++ b/tox.ini
@@ -95,12 +95,13 @@ deps =
setenv =
{[testenv]setenv}
- C_AE=coverage/config.py coverage/control.py coverage/data.py coverage/disposition.py
+ C__B=coverage/__init__.py coverage/__main__.py coverage/bytecode.py
+ C_CE=coverage/config.py coverage/context.py coverage/control.py coverage/data.py coverage/disposition.py coverage/exceptions.py
C_FN=coverage/files.py coverage/inorout.py coverage/multiproc.py coverage/numbits.py
C_OP=coverage/parser.py coverage/phystokens.py coverage/plugin.py coverage/python.py
- C_QZ=coverage/results.py coverage/sqldata.py coverage/tomlconfig.py coverage/types.py
+ C_QZ=coverage/report.py coverage/results.py coverage/sqldata.py coverage/tomlconfig.py coverage/types.py coverage/version.py
T_AN=tests/test_api.py tests/goldtest.py tests/helpers.py tests/test_html.py
- TYPEABLE={env:C_AE} {env:C_FN} {env:C_OP} {env:C_QZ} {env:T_AN}
+ TYPEABLE={env:C__B} {env:C_CE} {env:C_FN} {env:C_OP} {env:C_QZ} {env:T_AN}
commands =
# PYVERSIONS