Initial upload: CLI Explain Fix project with CI/CD workflow
This commit is contained in:
156
src/cli_explain_fix/knowledge_base.py
Normal file
156
src/cli_explain_fix/knowledge_base.py
Normal file
@@ -0,0 +1,156 @@
|
||||
"""Knowledge base module for error explanations."""
|
||||
|
||||
import re
|
||||
from dataclasses import dataclass
|
||||
from typing import Dict, List, Optional, Any
|
||||
from pathlib import Path
|
||||
|
||||
import yaml
|
||||
|
||||
|
||||
@dataclass
|
||||
class ErrorExplanation:
|
||||
"""Container for error explanation data."""
|
||||
error_type: str
|
||||
language: str
|
||||
what_happened: str
|
||||
why_happened: str
|
||||
how_to_fix: List[str]
|
||||
code_snippets: Optional[List[Dict[str, str]]] = None
|
||||
documentation_url: Optional[str] = None
|
||||
severity: str = "medium"
|
||||
|
||||
def __post_init__(self):
|
||||
if self.code_snippets is None:
|
||||
self.code_snippets = []
|
||||
|
||||
|
||||
class KnowledgeBase:
|
||||
"""Knowledge base for error explanations."""
|
||||
|
||||
base_path: Path
|
||||
|
||||
def __init__(self, base_path: Optional[str] = None):
|
||||
"""Initialize knowledge base with error definitions."""
|
||||
self._errors: Dict[str, Dict[str, Any]] = {}
|
||||
self._patterns: Dict[str, List[Dict[str, Any]]] = {}
|
||||
if base_path is None:
|
||||
self.base_path = Path(__file__).parent.parent.parent / 'knowledge_base'
|
||||
else:
|
||||
self.base_path = Path(base_path)
|
||||
self._load_knowledge_base()
|
||||
|
||||
def _load_knowledge_base(self) -> None:
|
||||
"""Load all YAML files from knowledge base directory."""
|
||||
errors_file = self.base_path / 'errors.yaml'
|
||||
patterns_file = self.base_path / 'patterns.yaml'
|
||||
|
||||
if errors_file.exists():
|
||||
try:
|
||||
with open(errors_file, 'r', encoding='utf-8') as f:
|
||||
data = yaml.safe_load(f) or {}
|
||||
if 'errors' in data:
|
||||
for error_def in data['errors']:
|
||||
key = f"{error_def.get('language', 'unknown')}_{error_def.get('error_type', 'Unknown')}"
|
||||
self._errors[key] = error_def
|
||||
except (yaml.YAMLError, OSError):
|
||||
pass
|
||||
|
||||
if patterns_file.exists():
|
||||
try:
|
||||
with open(patterns_file, 'r', encoding='utf-8') as f:
|
||||
data = yaml.safe_load(f) or {}
|
||||
if 'patterns' in data:
|
||||
self._patterns = data['patterns']
|
||||
except (yaml.YAMLError, OSError):
|
||||
pass
|
||||
|
||||
def get_explanation(self, error_type: str, language: str) -> Optional[ErrorExplanation]:
|
||||
"""Get explanation for a specific error type and language."""
|
||||
key = f"{language}_{error_type}"
|
||||
if key in self._errors:
|
||||
error_def = self._errors[key]
|
||||
return ErrorExplanation(
|
||||
error_type=error_type,
|
||||
language=language,
|
||||
what_happened=error_def.get('what_happened', 'An error occurred.'),
|
||||
why_happened=error_def.get('why_happened', 'Unknown reason.'),
|
||||
how_to_fix=error_def.get('how_to_fix', []),
|
||||
code_snippets=error_def.get('code_snippets', []),
|
||||
documentation_url=error_def.get('documentation_url'),
|
||||
severity=error_def.get('severity', 'medium'),
|
||||
)
|
||||
|
||||
generic_key = f"{language}_Generic"
|
||||
if generic_key in self._errors:
|
||||
error_def = self._errors[generic_key]
|
||||
return ErrorExplanation(
|
||||
error_type=error_type,
|
||||
language=language,
|
||||
what_happened=f"Received a {error_type} error.",
|
||||
why_happened=error_def.get('why_happened', 'The operation failed due to an error.'),
|
||||
how_to_fix=error_def.get('how_to_fix', []),
|
||||
code_snippets=error_def.get('code_snippets', []),
|
||||
documentation_url=error_def.get('documentation_url'),
|
||||
severity=error_def.get('severity', 'medium'),
|
||||
)
|
||||
|
||||
return None
|
||||
|
||||
def find_by_pattern(self, message: str, language: str) -> Optional[ErrorExplanation]:
|
||||
"""Find explanation by matching error message against patterns."""
|
||||
if language not in self._patterns:
|
||||
return None
|
||||
|
||||
for pattern_def in self._patterns[language]:
|
||||
pattern = pattern_def.get('pattern', '')
|
||||
if re.search(pattern, message, re.IGNORECASE):
|
||||
return ErrorExplanation(
|
||||
error_type=pattern_def.get('error_type', 'Unknown'),
|
||||
language=language,
|
||||
what_happened=pattern_def.get('what_happened', ''),
|
||||
why_happened=pattern_def.get('why_happened', ''),
|
||||
how_to_fix=pattern_def.get('how_to_fix', []),
|
||||
code_snippets=pattern_def.get('code_snippets', []),
|
||||
documentation_url=pattern_def.get('documentation_url'),
|
||||
severity=pattern_def.get('severity', 'medium'),
|
||||
)
|
||||
|
||||
return None
|
||||
|
||||
def list_languages(self) -> List[str]:
|
||||
"""List all supported languages."""
|
||||
languages = set()
|
||||
for key in self._errors:
|
||||
parts = key.split('_', 1)
|
||||
if len(parts) >= 1:
|
||||
languages.add(parts[0])
|
||||
return sorted(languages)
|
||||
|
||||
def list_errors(self, language: Optional[str] = None) -> List[Dict[str, str]]:
|
||||
"""List all known errors, optionally filtered by language."""
|
||||
errors = []
|
||||
for key, error_def in self._errors.items():
|
||||
if language is None or key.startswith(f"{language}_"):
|
||||
errors.append({
|
||||
'error_type': error_def.get('error_type', key),
|
||||
'language': error_def.get('language', 'unknown'),
|
||||
'description': error_def.get('what_happened', '')[:100],
|
||||
})
|
||||
return errors
|
||||
|
||||
def get_fallback_explanation(self, error_type: str, language: str) -> ErrorExplanation:
|
||||
"""Generate a fallback explanation for unknown errors."""
|
||||
return ErrorExplanation(
|
||||
error_type=error_type,
|
||||
language=language,
|
||||
what_happened=f"A {error_type} error was encountered.",
|
||||
why_happened="The specific cause of this error is not in the knowledge base.",
|
||||
how_to_fix=[
|
||||
"Check the error message for specific details about what went wrong.",
|
||||
"Search for the exact error message online.",
|
||||
f"Ensure you're using the correct syntax for {language}.",
|
||||
"Verify that all required dependencies are installed.",
|
||||
],
|
||||
severity="unknown",
|
||||
)
|
||||
Reference in New Issue
Block a user