From 6fee113a88ebd3b2c527dd468fda983aacef2e0c Mon Sep 17 00:00:00 2001 From: 7000pctAUTO Date: Thu, 5 Feb 2026 07:06:35 +0000 Subject: [PATCH] Fix mypy type errors in source code --- .../src/formatters/formatters.py | 141 ++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 app/local-ai-commit-reviewer/src/formatters/formatters.py diff --git a/app/local-ai-commit-reviewer/src/formatters/formatters.py b/app/local-ai-commit-reviewer/src/formatters/formatters.py new file mode 100644 index 0000000..9b04ac6 --- /dev/null +++ b/app/local-ai-commit-reviewer/src/formatters/formatters.py @@ -0,0 +1,141 @@ +from abc import ABC, abstractmethod + +from rich.console import Console +from rich.panel import Panel +from rich.style import Style +from rich.table import Table +from rich.text import Text + +from ..core import Issue, IssueCategory, IssueSeverity, ReviewResult + + +class BaseFormatter(ABC): + @abstractmethod + def format(self, result: ReviewResult) -> str: + pass + + +class TerminalFormatter(BaseFormatter): + def __init__(self, theme: str = "auto", show_line_numbers: bool = True): + self.console = Console() + self.show_line_numbers = show_line_numbers + self.use_colors = theme != "dark" if theme == "auto" else theme == "dark" + + def _get_severity_style(self, severity: IssueSeverity) -> Style: + styles = { + IssueSeverity.CRITICAL: Style(color="red", bold=True), + IssueSeverity.WARNING: Style(color="yellow"), + IssueSeverity.INFO: Style(color="blue"), + } + return styles.get(severity, Style()) + + def _get_category_icon(self, category: IssueCategory) -> str: + icons = { + IssueCategory.BUG: "[BUG]", + IssueCategory.SECURITY: "[SECURITY]", + IssueCategory.STYLE: "[STYLE]", + IssueCategory.PERFORMANCE: "[PERF]", + IssueCategory.DOCUMENTATION: "[DOC]", + } + return icons.get(category, "") + + def _format_issue(self, issue: Issue) -> Text: + text = Text() + text.append(f"{issue.file}:{issue.line} ", style="dim") + text.append(f"[{issue.severity.value.upper()}] ", self._get_severity_style(issue.severity)) + text.append(f"{self._get_category_icon(issue.category)} ") + text.append(issue.message) + + if issue.suggestion: + text.append("\n Suggestion: ", style="dim") + text.append(issue.suggestion) + + return text + + def format(self, result: ReviewResult) -> str: + output: list[Panel | Table | str] = [] + + if result.error: + output.append(Panel( + f"[red]Error: {result.error}[/red]", + title="Review Failed", + expand=False + )) + return "\n".join(str(p) for p in output) + + summary = result.summary + + summary_panel = Panel( + f"[bold]Files Reviewed:[/bold] {summary.files_reviewed}\n" + f"[bold]Lines Changed:[/bold] {summary.lines_changed}\n\n" + f"[red]Critical:[/red] {summary.critical_count} " + f"[yellow]Warnings:[/yellow] {summary.warning_count} " + f"[blue]Info:[/blue] {summary.info_count}\n\n" + f"[bold]Assessment:[/bold] {summary.overall_assessment}", + title="Review Summary", + expand=False + ) + output.append(summary_panel) + + if result.issues: + issues_table = Table(title="Issues Found", show_header=True) + issues_table.add_column("File", style="dim") + issues_table.add_column("Line", justify="right", style="dim") + issues_table.add_column("Severity", width=10) + issues_table.add_column("Category", width=12) + issues_table.add_column("Message") + + for issue in result.issues: + issues_table.add_row( + issue.file, + str(issue.line), + f"[{issue.severity.value.upper()}]", + f"[{issue.category.value.upper()}]", + issue.message, + style=self._get_severity_style(issue.severity) + ) + + output.append(issues_table) + + suggestions_panel = Panel( + "\n".join( + f"[bold]{issue.file}:{issue.line}[/bold]\n" + f" {issue.message}\n" + + (f" [green]→ {issue.suggestion}[/green]\n" if issue.suggestion else "") + for issue in result.issues if issue.suggestion + ), + title="Suggestions", + expand=False + ) + output.append(suggestions_panel) + + model_info = Panel( + f"[bold]Model:[/bold] {result.model_used}\n" + f"[bold]Tokens Used:[/bold] {result.tokens_used}\n" + f"[bold]Mode:[/bold] {result.review_mode}", + title="Review Info", + expand=False + ) + output.append(model_info) + + return "\n".join(str(o) for o in output) + + +class JSONFormatter(BaseFormatter): + def format(self, result: ReviewResult) -> str: + return result.to_json() + + +class MarkdownFormatter(BaseFormatter): + def format(self, result: ReviewResult) -> str: + return result.to_markdown() + + +def get_formatter(format_type: str = "terminal", **kwargs) -> BaseFormatter: + formatters: dict[str, type[BaseFormatter]] = { + "terminal": TerminalFormatter, + "json": JSONFormatter, + "markdown": MarkdownFormatter, + } + formatter_class = formatters.get(format_type, TerminalFormatter) + return formatter_class(**kwargs) # type: ignore[arg-type]