Repository: astral-sh/ruff
File: scripts/conformance.py (Python)

Code before:
    for key, group in groupby(diagnostics, key=attrgetter("key")):
        group = list(group)
        old_group = list(filter(lambda diag: diag.source == Source.OLD, group))
        new_group = list(filter(lambda diag: diag.source == Source.NEW, group))
        expected_group = list(
            filter(lambda diag: diag.source == Source.EXPECTED, group)
        )

        grouped = GroupedDiagnostics(
            key=key,
            sources={d.source for d in group},
            old=old_group,
            new=new_group,
            expected=expected_group,
        )
        grouped_diagnostics.append(grouped)

    return grouped_diagnostics


def compute_stats(
    grouped_diagnostics: list[GroupedDiagnostics],
    source: Source,
) -> Statistics:
    if source == source.EXPECTED:
        num_errors = sum(1 for g in grouped_diagnostics if source.EXPECTED in g.sources)
        return Statistics(
            true_positives=num_errors, false_positives=0, false_negatives=0
        )

    def increment(statistics: Statistics, grouped: GroupedDiagnostics) -> Statistics:
        classification = grouped.classify(source)
        if classification == Classification.TRUE_POSITIVE:
            statistics.true_positives += 1
        elif classification == Classification.FALSE_POSITIVE:
            statistics.false_positives += 1
        elif classification == Classification.FALSE_NEGATIVE:
            statistics.false_negatives += 1

        statistics.total_diagnostics += len(grouped.diagnostics_by_source(source))
        return statistics

    grouped_diagnostics = [diag for diag in grouped_diagnostics if not diag.optional]

    return reduce(increment, grouped_diagnostics, Statistics())


def render_grouped_diagnostics(
    grouped: list[GroupedDiagnostics],
    *,
    changed_only: bool = True,

Review comment (refactor):
It's a bit tricky to say what `num_errors` means in the presence of `E[tag+]` and `E?` where a single expected tag can have multiple errors and some errors are entirely optional. 

But it also seems that we never call `compute_stats` with `Source::Expected`. 

Should we remove this code and make `compute_stats` take a boolean argument instead (new_diagnostics)?

Code after:
) -> list[Diagnostic]:
    process = subprocess.run(
        [
            *ty_path,
            "check",
            f"--python-version={python_version}",
            "--output-format=gitlab",
            "--exit-zero",
            *map(str, test_files),
        ],
        capture_output=True,
        text=True,
        check=True,
        timeout=15,
    )

    if process.returncode != 0:
        print(process.stderr)
        raise RuntimeError(f"ty check failed with exit code {process.returncode}")

    return [
        Diagnostic.from_gitlab_output(dct, source=source)
        for dct in json.loads(process.stdout)
        if dct["severity"] == "major"
    ]


def group_diagnostics_by_key(
    old: list[Diagnostic],
    new: list[Diagnostic],
    expected: list[Diagnostic],
) -> list[GroupedDiagnostics]:
    # propagate tags from expected diagnostics to old and new diagnostics
    tagged_lines = {
        (d.location.path.name, d.location.positions.begin.line): d.tag
        for d in expected
        if d.tag is not None
    }

    for diag in chain(old, new):
        diag.tag = tagged_lines.get(
            (diag.location.path.name, diag.location.positions.begin.line), None
        )

    diagnostics = [
        *old,
        *new,
        *expected,
    ]

    diagnostics = sorted(diagnostics, key=attrgetter("key"))