Skip to content

Commit 40a052e

Browse files
committed
docs: document CodeRegion and its plugin methods
1 parent 2ff9933 commit 40a052e

File tree

5 files changed

+67
-44
lines changed

5 files changed

+67
-44
lines changed

coverage/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
from coverage.data import CoverageData as CoverageData
2929
from coverage.exceptions import CoverageException as CoverageException
3030
from coverage.plugin import (
31+
CodeRegion as CodeRegion,
3132
CoveragePlugin as CoveragePlugin,
3233
FileReporter as FileReporter,
3334
FileTracer as FileTracer,

coverage/plugin.py

+50-5
Original file line numberDiff line numberDiff line change
@@ -114,16 +114,15 @@ def coverage_init(reg, options):
114114

115115
from __future__ import annotations
116116

117+
import dataclasses
117118
import functools
118119

119120
from types import FrameType
120121
from typing import Any, Iterable
121122

122123
from coverage import files
123124
from coverage.misc import _needs_to_implement
124-
from coverage.types import (
125-
CodeRegion, TArc, TConfigurable, TLineNo, TSourceTokenLines,
126-
)
125+
from coverage.types import TArc, TConfigurable, TLineNo, TSourceTokenLines
127126

128127

129128
class CoveragePlugin:
@@ -346,6 +345,35 @@ def line_number_range(self, frame: FrameType) -> tuple[TLineNo, TLineNo]:
346345
return lineno, lineno
347346

348347

348+
@dataclasses.dataclass
349+
class CodeRegion:
350+
"""Data for a region of code found by :meth:`FileReporter.code_regions`."""
351+
352+
#: The kind of region, like `"function"` or `"class"`. Must be one of the
353+
#: singular values returned by :meth:`FileReporter.code_region_kinds`.
354+
kind: str
355+
356+
#: The name of the region. For example, a function or class name.
357+
name: str
358+
359+
#: The line in the source file to link to when navigating to the region.
360+
#: Can be a line not mentioned in `lines`.
361+
start: int
362+
363+
#: The lines in the region. Should be lines that could be executed in the
364+
#: region. For example, a class region includes all of the lines in the
365+
#: methods of the class, but not the lines defining class attributes, since
366+
#: they are executed on import, not as part of exercising the class. The
367+
#: set can include non-executable lines like blanks and comments.
368+
lines: set[int]
369+
370+
def __lt__(self, other: CodeRegion) -> bool:
371+
"""To support sorting to make test-writing easier."""
372+
if self.name == other.name:
373+
return min(self.lines) < min(other.lines)
374+
return self.name < other.name
375+
376+
349377
@functools.total_ordering
350378
class FileReporter(CoveragePluginBase):
351379
"""Support needed for files during the analysis and reporting phases.
@@ -546,11 +574,28 @@ def source_token_lines(self) -> TSourceTokenLines:
546574
yield [("txt", line)]
547575

548576
def code_regions(self) -> Iterable[CodeRegion]:
549-
"""TODO XXX"""
577+
"""Identify regions in the source file for finer reporting than by file.
578+
579+
Returns an iterable of :class:`CodeRegion` objects. The kinds reported
580+
should be in the possibilities returned by :meth:`code_region_kinds`.
581+
582+
"""
550583
return []
551584

552585
def code_region_kinds(self) -> Iterable[tuple[str, str]]:
553-
"""TODO XXX"""
586+
"""Return the kinds of code regions this plugin can find.
587+
588+
The returned pairs are the singular and plural forms of the kinds::
589+
590+
[
591+
("function", "functions"),
592+
("class", "classes"),
593+
]
594+
595+
This will usually be hard-coded, but could also differ by the specific
596+
source file involved.
597+
598+
"""
554599
return []
555600

556601
def __eq__(self, other: Any) -> bool:

coverage/regions.py

+9-17
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
from typing import cast
1212

13-
from coverage.types import CodeRegion
13+
from coverage.plugin import CodeRegion
1414

1515

1616
@dataclasses.dataclass
@@ -91,22 +91,14 @@ def visit_ClassDef(self, node: ast.ClassDef) -> None:
9191
def code_regions(source: str) -> list[CodeRegion]:
9292
"""Find function and class regions in source code.
9393
94-
TODO: Fix this description.
95-
96-
Takes the program `source`, and returns a dict: the keys are "function" and
97-
"class". Each has a value which is a dict: the keys are fully qualified
98-
names, the values are sets of line numbers included in that region::
99-
100-
{
101-
"function": {
102-
"func1": {10, 11, 12},
103-
"func2": {20, 21, 22},
104-
"MyClass.method: {34, 35, 36},
105-
},
106-
"class": {
107-
"MyClass": {34, 35, 36},
108-
},
109-
}
94+
Analyzes the code in `source`, and returns a list of :class:`CodeRegion`
95+
objects describing functions and classes as regions of the code::
96+
97+
[
98+
CodeRegion(kind="function", name="func1", start=8, lines={10, 11, 12}),
99+
CodeRegion(kind="function", name="MyClass.method", start=30, lines={34, 35, 36}),
100+
CodeRegion(kind="class", name="MyClass", start=25, lines={34, 35, 36}),
101+
]
110102
111103
The line numbers will include comments and blank lines. Later processing
112104
will need to ignore those lines as needed.

coverage/types.py

-22
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
from __future__ import annotations
99

10-
import dataclasses
1110
import os
1211
import pathlib
1312

@@ -163,27 +162,6 @@ def get_plugin_options(self, plugin: str) -> TConfigSectionOut:
163162
TSourceTokenLines = Iterable[List[Tuple[str, str]]]
164163

165164

166-
@dataclasses.dataclass
167-
class CodeRegion:
168-
"""Data for each region found by FileReporter.code_regions.
169-
170-
`kind`: the kind of region.
171-
`name`: the description of the region.
172-
`start`: the first line of the named region.
173-
`lines`: a super-set of the executable source lines in the region.
174-
"""
175-
kind: str
176-
name: str
177-
start: int
178-
lines: set[int]
179-
180-
def __lt__(self, other: CodeRegion) -> bool:
181-
"""To support sorting to make test-writing easier."""
182-
if self.name == other.name:
183-
return min(self.lines) < min(other.lines)
184-
return self.name < other.name
185-
186-
187165
## Plugins
188166

189167
class TPlugin(Protocol):

doc/api_plugin.rst

+7
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,10 @@ The FileReporter class
3232
.. autoclass:: FileReporter
3333
:members:
3434
:member-order: bysource
35+
36+
The CodeRegion class
37+
--------------------
38+
39+
.. autoclass:: CodeRegion
40+
:members:
41+
:member-order: bysource

0 commit comments

Comments
 (0)