Skip to content

Instantly share code, notes, and snippets.

@sharkdp
Created April 9, 2025 15:19
Show Gist options
  • Save sharkdp/41cf6f276b57903e455f4b488d4860ce to your computer and use it in GitHub Desktop.
Save sharkdp/41cf6f276b57903e455f4b488d4860ce to your computer and use it in GitHub Desktop.
# /// script
# requires-python = ">=3.13"
# dependencies = []
# ///
import re
import sys
from collections import defaultdict
from dataclasses import dataclass
from pathlib import Path
@dataclass
class Diagnostic:
level: str
lint_name: str
path: str
line: int
column: int
message: str
def parse_diagnostic_message(line: str) -> Diagnostic | None:
pattern = (
r"^(?P<level>error|warning)\[lint:(?P<lint_name>.+?)\] "
r"(?P<path>.+?):(?P<line>\d+):(?P<column>\d+): "
r"(?P<message>.+)$"
)
if match := re.match(pattern, line):
return Diagnostic(
level=match.group("level"),
lint_name=match.group("lint_name"),
path=match.group("path"),
line=int(match.group("line")),
column=int(match.group("column")),
message=match.group("message"),
)
return None
def parse_diagnostics(content: str) -> list[Diagnostic]:
messages = []
for line in content.splitlines():
line = line.strip()
if not line:
continue
if message := parse_diagnostic_message(line):
messages.append(message)
return messages
def print_statistics(messages: list[Diagnostic]) -> None:
level_stats = defaultdict(int)
lint_stats = defaultdict(int)
file_stats = defaultdict(int)
for msg in messages:
level_stats[msg.level] += 1
lint_stats[msg.lint_name] += 1
file_stats[msg.path] += 1
print("Statistics:")
print(f" Number of diagnostics: {len(messages)}")
print(f" Number of files with diagnostics: {len(file_stats)}")
print("\nDiagnostics by level:")
for level, count in level_stats.items():
print(f" {level.title()}: {count}")
print("\nDiagnostics by file (top 5):")
top_files = sorted(file_stats.items(), key=lambda x: x[1], reverse=True)[:5]
for path, count in top_files:
print(f" {path}: {count}")
print("\nDiagnostics by lint name:")
for lint_name, count in sorted(
lint_stats.items(), key=lambda x: x[1], reverse=True,
):
print(f" {lint_name}: {count}")
def main() -> None:
import argparse
parser = argparse.ArgumentParser(
description="Parse Red Knot output and show statistics."
)
parser.add_argument("path", type=Path, help="Text file with Red Knot output", nargs="?")
args = parser.parse_args()
if args.path:
if not args.path.exists():
print(f"Error: File not found: {args.path}")
sys.exit(1)
content = args.path.read_text()
else:
content = sys.stdin.read()
diagnostics = parse_diagnostics(content)
print_statistics(diagnostics)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment