@@ -114,16 +114,15 @@ def coverage_init(reg, options):
114114
115115from __future__ import annotations
116116
117+ import dataclasses
117118import functools
118119
119120from types import FrameType
120121from typing import Any , Iterable
121122
122123from coverage import files
123124from 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
129128class 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
350378class 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 :
0 commit comments