# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
# For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt

"""
$ python warn_executed.py <coverage_data_file> <config_file>

Find lines that were excluded by "warn-executed" regex patterns
but were actually executed according to coverage data.

The config_file is a TOML file with "warn-executed" and "warn-not-partial"
patterns like:

    warn-executed = [
        "pragma: no cover",
        "# debug",
        "raise NotImplemented",
        ]

    warn-not-partial = [
        "if TYPE_CHECKING:",
    ]

These should be patterns that you excluded as lines or partial branches.

Warning: this program uses internal undocumented private classes from
coverage.py.  This is an unsupported proof-of-concept.

I wrote a blog post about this:
https://nedbatchelder.com/blog/202508/finding_unneeded_pragmas.html

"""

import linecache
import os
import sys
import tomllib

from coverage.parser import PythonParser
from coverage.sqldata import CoverageData
from coverage.results import Analysis


def read_warn_patterns(config_file: str) -> tuple[list[str], list[str]]:
    """Read "warn-executed" and "warn-not-partial" patterns from a TOML config file."""
    with open(config_file, "rb") as f:
        config = tomllib.load(f)

    warn_executed = []
    warn_not_partial = []

    if "warn-executed" in config:
        warn_executed.extend(config["warn-executed"])
    if "warn-not-partial" in config:
        warn_not_partial.extend(config["warn-not-partial"])

    return warn_executed, warn_not_partial


def find_executed_excluded_lines(
    source_file: str,
    coverage_data: CoverageData,
    warn_patterns: list[str],
) -> set[int]:
    """
    Find lines that match warn-executed patterns but were actually executed.

    Args:
        source_file: Path to the Python source file to analyze
        coverage_data: The coverage data object
        warn_patterns: List of regex patterns that should warn if executed

    Returns:
        Set of executed line numbers that matched any pattern
    """
    executed_lines = coverage_data.lines(source_file)
    if executed_lines is None:
        return set()

    executed_lines = set(executed_lines)

    try:
        with open(source_file, "r", encoding="utf-8") as f:
            source_text = f.read()
    except Exception:
        return set()

    parser = PythonParser(text=source_text, filename=source_file)
    parser.parse_source()

    all_executed_excluded = set()
    for pattern in warn_patterns:
        matched_lines = parser.lines_matching(pattern)
        all_executed_excluded.update(matched_lines & executed_lines)

    return all_executed_excluded


def find_not_partial_lines(
    source_file: str,
    coverage_data: CoverageData,
    warn_patterns: list[str],
) -> set[int]:
    """
    Find lines that match warn-not-partial patterns but had both code paths executed.

    Args:
        source_file: Path to the Python source file to analyze
        coverage_data: The coverage data object
        warn_patterns: List of regex patterns for lines expected to be partial

    Returns:
        Set of line numbers that matched patterns but weren't partial
    """
    if not coverage_data.has_arcs():
        return set()

    all_arcs = coverage_data.arcs(source_file)
    if all_arcs is None:
        return set()

    try:
        with open(source_file, "r", encoding="utf-8") as f:
            source_text = f.read()
    except Exception:
        return set()

    parser = PythonParser(text=source_text, filename=source_file)
    parser.parse_source()

    all_possible_arcs = set(parser.arcs())
    executed_arcs = set(all_arcs)

    # Lines with some missing arcs are partial branches
    partial_lines = set()
    for start_line in {arc[0] for arc in all_possible_arcs if arc[0] > 0}:
        possible_from_line = {arc for arc in all_possible_arcs if arc[0] == start_line}
        executed_from_line = {arc for arc in executed_arcs if arc[0] == start_line}
        if executed_from_line and possible_from_line != executed_from_line:
            partial_lines.add(start_line)

    all_not_partial = set()
    for pattern in warn_patterns:
        matched_lines = parser.lines_matching(pattern)
        not_partial = matched_lines - partial_lines
        all_not_partial.update(not_partial)

    return all_not_partial


def analyze_warnings(coverage_file: str, config_file: str) -> dict[str, set[int]]:
    """
    Find lines that match warn-executed or warn-not-partial patterns.

    Args:
        coverage_file: Path to the coverage data file (.coverage)
        config_file: Path to TOML config file with warning patterns

    Returns:
        Dictionary mapping filenames to sets of problematic line numbers
    """
    warn_executed_patterns, warn_not_partial_patterns = read_warn_patterns(config_file)

    if not warn_executed_patterns and not warn_not_partial_patterns:
        return {}

    coverage_data = CoverageData(coverage_file)
    coverage_data.read()

    measured_files = sorted(coverage_data.measured_files())

    all_results = {}
    for source_file in measured_files:
        problem_lines = set()

        if warn_executed_patterns:
            executed_excluded = find_executed_excluded_lines(
                source_file,
                coverage_data,
                warn_executed_patterns,
            )
            problem_lines.update(executed_excluded)

        if warn_not_partial_patterns:
            not_partial = find_not_partial_lines(
                source_file,
                coverage_data,
                warn_not_partial_patterns,
            )
            problem_lines.update(not_partial)

        if problem_lines:
            all_results[source_file] = problem_lines

    return all_results


def main():
    if len(sys.argv) != 3:
        print(__doc__.rstrip())
        return 1

    coverage_file, config_file = sys.argv[1:]
    results = analyze_warnings(coverage_file, config_file)

    for source_file in sorted(results.keys()):
        problem_lines = results[source_file]
        for line_num in sorted(problem_lines):
            line_text = linecache.getline(source_file, line_num).rstrip()
            print(f"{source_file}:{line_num}: {line_text}")


if __name__ == "__main__":
    sys.exit(main())
