Initial upload: CLI Explain Fix project with CI/CD workflow
This commit is contained in:
131
src/cli_explain_fix/explainer.py
Normal file
131
src/cli_explain_fix/explainer.py
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
"""Explanation generation module."""
|
||||||
|
|
||||||
|
from typing import Dict, Any, Optional
|
||||||
|
|
||||||
|
from cli_explain_fix.knowledge_base import KnowledgeBase, ErrorExplanation
|
||||||
|
from cli_explain_fix.parser import ParsedError
|
||||||
|
|
||||||
|
|
||||||
|
class Explainer:
|
||||||
|
"""Generator for human-readable error explanations."""
|
||||||
|
|
||||||
|
def __init__(self, knowledge_base: Optional[KnowledgeBase] = None):
|
||||||
|
"""Initialize explainer with optional knowledge base."""
|
||||||
|
self.knowledge_base = knowledge_base or KnowledgeBase()
|
||||||
|
|
||||||
|
def explain(self, parsed_error: ParsedError, verbose: bool = False) -> Dict[str, Any]:
|
||||||
|
"""Generate a complete explanation for a parsed error."""
|
||||||
|
explanation = self.knowledge_base.get_explanation(
|
||||||
|
parsed_error.error_type,
|
||||||
|
parsed_error.language
|
||||||
|
)
|
||||||
|
|
||||||
|
if not explanation:
|
||||||
|
explanation = self.knowledge_base.find_by_pattern(
|
||||||
|
parsed_error.message,
|
||||||
|
parsed_error.language
|
||||||
|
)
|
||||||
|
|
||||||
|
if not explanation:
|
||||||
|
explanation = self.knowledge_base.get_fallback_explanation(
|
||||||
|
parsed_error.error_type,
|
||||||
|
parsed_error.language
|
||||||
|
)
|
||||||
|
|
||||||
|
result: Dict[str, Any] = {
|
||||||
|
'error_type': parsed_error.error_type,
|
||||||
|
'language': parsed_error.language,
|
||||||
|
'summary': self._generate_summary(explanation),
|
||||||
|
'what_happened': explanation.what_happened,
|
||||||
|
'why_happened': explanation.why_happened,
|
||||||
|
'how_to_fix': explanation.how_to_fix,
|
||||||
|
'severity': explanation.severity,
|
||||||
|
}
|
||||||
|
|
||||||
|
if parsed_error.file_name:
|
||||||
|
result['location'] = {
|
||||||
|
'file': parsed_error.file_name,
|
||||||
|
'line': parsed_error.line_number,
|
||||||
|
}
|
||||||
|
|
||||||
|
if parsed_error.stack_frames:
|
||||||
|
result['stack_trace'] = parsed_error.stack_frames
|
||||||
|
|
||||||
|
if explanation.code_snippets:
|
||||||
|
code_examples = self._format_code_examples(explanation.code_snippets)
|
||||||
|
result['code_examples'] = code_examples
|
||||||
|
|
||||||
|
if explanation.documentation_url:
|
||||||
|
result['documentation'] = explanation.documentation_url
|
||||||
|
|
||||||
|
if verbose:
|
||||||
|
result['raw_error'] = parsed_error.raw_input
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
def _generate_summary(self, explanation: ErrorExplanation) -> str:
|
||||||
|
"""Generate a short summary of the explanation."""
|
||||||
|
severity_icons = {
|
||||||
|
'critical': '🔴',
|
||||||
|
'high': '🟠',
|
||||||
|
'medium': '🟡',
|
||||||
|
'low': '🟢',
|
||||||
|
'unknown': '⚪',
|
||||||
|
}
|
||||||
|
icon = severity_icons.get(explanation.severity, '⚪')
|
||||||
|
|
||||||
|
return f"{icon} {explanation.error_type} in {explanation.language}"
|
||||||
|
|
||||||
|
def _format_code_examples(self, code_snippets: list) -> list:
|
||||||
|
"""Format code snippets for display."""
|
||||||
|
formatted = []
|
||||||
|
for snippet in code_snippets:
|
||||||
|
formatted.append({
|
||||||
|
'description': snippet.get('description', ''),
|
||||||
|
'code': snippet.get('code', ''),
|
||||||
|
'language': snippet.get('language', 'text'),
|
||||||
|
})
|
||||||
|
return formatted
|
||||||
|
|
||||||
|
def get_fix_steps(self, parsed_error: ParsedError) -> list:
|
||||||
|
"""Get step-by-step fix instructions."""
|
||||||
|
explanation = self.knowledge_base.get_explanation(
|
||||||
|
parsed_error.error_type,
|
||||||
|
parsed_error.language
|
||||||
|
)
|
||||||
|
|
||||||
|
if not explanation:
|
||||||
|
explanation = self.knowledge_base.get_fallback_explanation(
|
||||||
|
parsed_error.error_type,
|
||||||
|
parsed_error.language
|
||||||
|
)
|
||||||
|
|
||||||
|
return explanation.how_to_fix
|
||||||
|
|
||||||
|
def explain_simple(self, error_type: str, message: str, language: str) -> str:
|
||||||
|
"""Generate a simple text explanation."""
|
||||||
|
explanation = self.knowledge_base.get_explanation(error_type, language)
|
||||||
|
|
||||||
|
if not explanation:
|
||||||
|
explanation = self.knowledge_base.get_fallback_explanation(
|
||||||
|
error_type,
|
||||||
|
language
|
||||||
|
)
|
||||||
|
|
||||||
|
lines = [
|
||||||
|
f"Error: {error_type}",
|
||||||
|
f"Language: {language}",
|
||||||
|
"",
|
||||||
|
"What happened:",
|
||||||
|
explanation.what_happened,
|
||||||
|
"",
|
||||||
|
"Why it happened:",
|
||||||
|
explanation.why_happened,
|
||||||
|
"",
|
||||||
|
"How to fix:",
|
||||||
|
]
|
||||||
|
|
||||||
|
for i, step in enumerate(explanation.how_to_fix, 1):
|
||||||
|
lines.append(f" {i}. {step}")
|
||||||
|
|
||||||
|
return "\n".join(lines)
|
||||||
Reference in New Issue
Block a user