diff options
| author | Ned Batchelder <ned@nedbatchelder.com> | 2022-12-31 19:04:31 -0500 |
|---|---|---|
| committer | Ned Batchelder <ned@nedbatchelder.com> | 2022-12-31 20:39:09 -0500 |
| commit | e3c523c98cbc9ecdd37e36da19848ca9d0aef4a3 (patch) | |
| tree | 0857c3472c5858695d26f0276e8f1c5b3512a3e2 | |
| parent | 5a72a1eb736516759201b223463f69f00979818e (diff) | |
| download | python-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.py | 7 | ||||
| -rw-r--r-- | coverage/context.py | 19 | ||||
| -rw-r--r-- | coverage/report.py | 33 | ||||
| -rw-r--r-- | coverage/version.py | 18 | ||||
| -rw-r--r-- | tox.ini | 7 |
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: @@ -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 |
