CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-interrogate

Interrogate a codebase for docstring coverage.

Pending
Overview
Eval results
Files

coverage-analysis.mddocs/

Coverage Analysis

Core functionality for analyzing docstring coverage in Python codebases. The coverage analysis engine traverses Python Abstract Syntax Trees (AST) to identify missing docstrings across modules, classes, functions, and methods.

Capabilities

Main Coverage Class

The primary class for running docstring coverage analysis on Python files and directories.

class InterrogateCoverage:
    """Main class for analyzing docstring coverage."""
    
    # Class constants
    COMMON_EXCLUDE: List[str] = [".tox", ".venv", "venv", ".git", ".hg"]
    VALID_EXT: List[str] = [".py", ".pyi"]
    
    def __init__(self, paths, conf=None, excluded=None, extensions=None):
        """
        Initialize coverage analyzer.
        
        Args:
            paths: List of file/directory paths to analyze
            conf: Configuration object with analysis options (optional)
            excluded: Tuple of files and directories to exclude (optional)
            extensions: Set of file extensions to analyze (optional)
        """
    
    def get_filenames_from_paths(self) -> List[str]:
        """
        Get all Python filenames from configured paths.
        
        Returns:
            List[str]: Python file paths to analyze
        """
    
    def get_coverage(self) -> InterrogateResults:
        """
        Analyze docstring coverage for configured paths.
        
        Returns:
            InterrogateResults: Aggregated coverage results
        """
    
    def print_results(self, results: InterrogateResults, output_file: Optional[str] = None) -> None:
        """
        Print formatted coverage results.
        
        Args:
            results: Coverage analysis results
            output_file: Optional file path for output (defaults to stdout)
        """

Results Classes

Data structures for storing and managing coverage analysis results.

class BaseInterrogateResult:
    """Base class for coverage results."""
    
    total: int          # Total number of items analyzed
    covered: int        # Number of items with docstrings
    missing: int        # Number of items missing docstrings
    perc_covered: float # Percentage coverage (0-100)

class InterrogateFileResult(BaseInterrogateResult):
    """Coverage results for a single file."""
    
    filename: str               # Path to analyzed file
    ignore_module: bool         # Whether module-level docstring was ignored
    nodes: List[CovNode]        # List of analyzed AST nodes
    
    def combine(self) -> None:
        """
        Tally results from each AST node visited.
        
        Updates the total, covered, and missing counts based on nodes.
        """

class InterrogateResults(BaseInterrogateResult):
    """Aggregated coverage results for all analyzed files."""
    
    ret_code: int                                    # Exit code based on coverage
    file_results: Dict[str, InterrogateFileResult]   # Per-file results
    
    def combine(self) -> None:
        """
        Tally results from each file.
        
        Updates the total, covered, and missing counts from all file results.
        """

AST Coverage Nodes

Data structures representing coverage information for individual code elements.

class CovNode:
    """Coverage information for an AST node."""
    
    name: str                    # Name of the code element
    path: str                    # File path containing the element
    level: int                   # Nesting level (0 = module, 1 = class/function, etc.)
    lineno: int                  # Line number in source file
    covered: bool                # Whether element has docstring
    node_type: str               # Type of AST node ("module", "class", "function", "method")
    is_nested_func: bool         # Whether function is nested inside another function
    is_nested_cls: bool          # Whether class is nested inside another class
    parent: Optional[CovNode]    # Parent node (for nested elements)

AST Visitor

The visitor class that traverses Python AST to collect docstring coverage information.

class CoverageVisitor(ast.NodeVisitor):
    """AST visitor for collecting docstring coverage data."""
    
    def __init__(self, filename: str, config: InterrogateConfig):
        """
        Initialize AST visitor.
        
        Args:
            filename: Path to file being analyzed
            config: Configuration with analysis options
        """
    
    def visit_Module(self, node: ast.Module) -> None:
        """Visit module-level node."""
    
    def visit_ClassDef(self, node: ast.ClassDef) -> None:
        """Visit class definition node."""
    
    def visit_FunctionDef(self, node: ast.FunctionDef) -> None:
        """Visit function definition node."""
    
    def visit_AsyncFunctionDef(self, node: ast.AsyncFunctionDef) -> None:
        """Visit async function definition node."""

Usage Examples

Basic Coverage Analysis

from interrogate.coverage import InterrogateCoverage
from interrogate.config import InterrogateConfig

# Configure analysis
config = InterrogateConfig(
    ignore_init_method=True,
    ignore_private=True,
    fail_under=80.0
)

# Run analysis
coverage = InterrogateCoverage(["src/myproject"], config)
results = coverage.get_coverage()

# Check results
print(f"Coverage: {results.perc_covered:.1f}%")
print(f"Files analyzed: {len(results.file_results)}")
print(f"Missing docstrings: {results.missing}")

# Print detailed results
coverage.print_results(results)

Programmatic Result Processing

from interrogate.coverage import InterrogateCoverage
from interrogate.config import InterrogateConfig

config = InterrogateConfig()
coverage = InterrogateCoverage(["src/"], config)
results = coverage.get_coverage()

# Process individual file results
for filename, file_result in results.file_results.items():
    print(f"{filename}: {file_result.perc_covered:.1f}% coverage")
    
    # Examine individual nodes
    for node in file_result.nodes:
        if not node.covered:
            print(f"  Missing docstring: {node.name} ({node.node_type}) at line {node.lineno}")

# Check if coverage meets threshold
if results.ret_code != 0:
    print(f"Coverage {results.perc_covered:.1f}% below required threshold")

Custom File Filtering

from interrogate.coverage import InterrogateCoverage
from interrogate.config import InterrogateConfig

# Create coverage analyzer
config = InterrogateConfig()
coverage = InterrogateCoverage(["src/"], config)

# Get all Python files that would be analyzed
python_files = list(coverage.get_filenames_from_paths())
print(f"Files to analyze: {len(python_files)}")

for filepath in python_files:
    print(f"  {filepath}")

Install with Tessl CLI

npx tessl i tessl/pypi-interrogate

docs

ast-visitor.md

badge-generation.md

cli-interface.md

configuration.md

coverage-analysis.md

index.md

utilities.md

tile.json