From 9b328cb98fa6ea6b619cca84b6953db29b88c435 Mon Sep 17 00:00:00 2001 From: shrutu0929 Date: Wed, 11 Mar 2026 13:37:24 +0530 Subject: [PATCH 1/4] Update analyzers and add flake8 checks --- .flake8 | 3 ++ all_flake8_errors.txt | Bin 0 -> 180130 bytes flake8_errors.txt | Bin 0 -> 7996 bytes flake8_errors_temp.txt | Bin 0 -> 7168 bytes flake8_errors_utf8.txt | 39 ++++++++++++++++++ refactron/analyzers/code_smell_analyzer.py | 35 +++++++++++++++- refactron/core/config.py | 4 ++ tests/test_analyzers.py | 45 +++++++++++++++++++++ 8 files changed, 125 insertions(+), 1 deletion(-) create mode 100644 .flake8 create mode 100644 all_flake8_errors.txt create mode 100644 flake8_errors.txt create mode 100644 flake8_errors_temp.txt create mode 100644 flake8_errors_utf8.txt diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..87afe54 --- /dev/null +++ b/.flake8 @@ -0,0 +1,3 @@ +[flake8] +max-line-length = 100 +extend-ignore = E203, W503 diff --git a/all_flake8_errors.txt b/all_flake8_errors.txt new file mode 100644 index 0000000000000000000000000000000000000000..51801fa10646d1287a4485c73bfa76fb1a528ebb GIT binary patch literal 180130 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 literal 0 HcmV?d00001 diff --git a/flake8_errors_temp.txt b/flake8_errors_temp.txt new file mode 100644 index 0000000000000000000000000000000000000000..9181c1715322ef9eed73901b9b77f3d8a76c1e38 GIT binary patch literal 7168 zcmdT|%TB{E5S%j-|G*J0(Aas{9Juiv6$<4cr7a4*z{dl#<;aDMghr@}Yda55r?a!` ze16Q>-~o3Salni{cDUkb$78}9-g$P$E9XX@yXR=l(U#v6KkFY?UgCv!U8BXowqV8f z47cdmYuKCc%x7=dJMek?<4mmi$lf`xk85st45(~JJaL7YN1*#ga)DEvaPBWqcU)gV zovo;QiR)_Sy63;Woa>5Y<$9p9m!mG!zf;$R(X<@3o9pK284B)VWjknDk9E0vXB-%0cnZ#|gkCYrw8I>}PriEQQd z!B&h*@BT88H^oofbyY;Awx4(VcQB{;x7$yugxkHp%*^wOPAdJ==_ldd+FLg7{xXv{ z%}=~}CvYo#$9r 79 characters) +refactron/analyzers/code_smell_analyzer.py:51:80: E501 line too long (83 > 79 characters) +refactron/analyzers/code_smell_analyzer.py:67:80: E501 line too long (91 > 79 characters) +refactron/analyzers/code_smell_analyzer.py:68:80: E501 line too long (92 > 79 characters) +refactron/analyzers/code_smell_analyzer.py:74:80: E501 line too long (85 > 79 characters) +refactron/analyzers/code_smell_analyzer.py:89:80: E501 line too long (92 > 79 characters) +refactron/analyzers/code_smell_analyzer.py:101:80: E501 line too long (98 > 79 characters) +refactron/analyzers/code_smell_analyzer.py:105:80: E501 line too long (100 > 79 characters) +refactron/analyzers/code_smell_analyzer.py:128:80: E501 line too long (81 > 79 characters) +refactron/analyzers/code_smell_analyzer.py:146:80: E501 line too long (92 > 79 characters) +refactron/analyzers/code_smell_analyzer.py:149:80: E501 line too long (94 > 79 characters) +refactron/analyzers/code_smell_analyzer.py:158:80: E501 line too long (87 > 79 characters) +refactron/analyzers/code_smell_analyzer.py:177:80: E501 line too long (85 > 79 characters) +refactron/analyzers/code_smell_analyzer.py:182:80: E501 line too long (91 > 79 characters) +refactron/analyzers/code_smell_analyzer.py:186:80: E501 line too long (92 > 79 characters) +refactron/analyzers/code_smell_analyzer.py:197:80: E501 line too long (86 > 79 characters) +refactron/analyzers/code_smell_analyzer.py:203:80: E501 line too long (87 > 79 characters) +refactron/analyzers/code_smell_analyzer.py:211:80: E501 line too long (82 > 79 characters) +refactron/analyzers/code_smell_analyzer.py:212:80: E501 line too long (92 > 79 characters) +refactron/analyzers/code_smell_analyzer.py:220:80: E501 line too long (91 > 79 characters) +refactron/analyzers/code_smell_analyzer.py:225:80: E501 line too long (87 > 79 characters) +refactron/analyzers/code_smell_analyzer.py:227:80: E501 line too long (80 > 79 characters) +refactron/analyzers/code_smell_analyzer.py:232:80: E501 line too long (91 > 79 characters) +refactron/analyzers/code_smell_analyzer.py:236:80: E501 line too long (86 > 79 characters) +refactron/analyzers/code_smell_analyzer.py:240:80: E501 line too long (95 > 79 characters) +refactron/analyzers/code_smell_analyzer.py:260:80: E501 line too long (85 > 79 characters) +refactron/analyzers/code_smell_analyzer.py:274:80: E501 line too long (82 > 79 characters) +refactron/analyzers/code_smell_analyzer.py:285:80: E501 line too long (90 > 79 characters) +refactron/analyzers/code_smell_analyzer.py:295:80: E501 line too long (81 > 79 characters) +refactron/analyzers/code_smell_analyzer.py:314:80: E501 line too long (93 > 79 characters) +refactron/analyzers/code_smell_analyzer.py:328:80: E501 line too long (94 > 79 characters) +refactron/analyzers/code_smell_analyzer.py:330:80: E501 line too long (81 > 79 characters) +refactron/analyzers/code_smell_analyzer.py:338:80: E501 line too long (80 > 79 characters) +refactron/analyzers/code_smell_analyzer.py:340:80: E501 line too long (87 > 79 characters) +refactron/analyzers/code_smell_analyzer.py:354:80: E501 line too long (95 > 79 characters) +refactron/analyzers/code_smell_analyzer.py:380:80: E501 line too long (87 > 79 characters) +refactron/analyzers/code_smell_analyzer.py:386:80: E501 line too long (93 > 79 characters) +refactron/analyzers/code_smell_analyzer.py:387:80: E501 line too long (84 > 79 characters) +refactron/analyzers/code_smell_analyzer.py:390:80: E501 line too long (93 > 79 characters) \ No newline at end of file diff --git a/refactron/analyzers/code_smell_analyzer.py b/refactron/analyzers/code_smell_analyzer.py index a0c83a0..2a88bfd 100644 --- a/refactron/analyzers/code_smell_analyzer.py +++ b/refactron/analyzers/code_smell_analyzer.py @@ -3,15 +3,25 @@ import ast import copy from pathlib import Path -from typing import Dict, List, Set +from typing import Dict, List, Optional, Set from refactron.analyzers.base_analyzer import BaseAnalyzer +from refactron.core.config import RefactronConfig from refactron.core.models import CodeIssue, IssueCategory, IssueLevel +from refactron.llm.orchestrator import LLMOrchestrator class CodeSmellAnalyzer(BaseAnalyzer): """Detects common code smells and anti-patterns.""" + def __init__( + self, + config: RefactronConfig, + orchestrator: Optional[LLMOrchestrator] = None, + ): + super().__init__(config) + self.orchestrator = orchestrator + @property def name(self) -> str: return "code_smells" @@ -51,6 +61,29 @@ def analyze(self, file_path: Path, source_code: str) -> List[CodeIssue]: ) issues.append(issue) + # AI Triage: Filter out safe/intentional smells + if self.config.enable_ai_triage and self.orchestrator and issues: + # Batch evaluate all issues + # evaluate_issues_batch returns Dict[str, float] mapping issue_id to confidence + confidence_scores = self.orchestrator.evaluate_issues_batch(issues, source_code) + + # Filter issues with a confidence < 0.3 + # (meaning LLM thinks it might be a false positive/safe) + final_issues = [] + for i, issue in enumerate(issues): + # evaluate_issues_batch defaults to f"issue_{i}" if rule_id is absent + issue_id = getattr(issue, "rule_id", None) or f"issue_{i}" + + confidence = confidence_scores.get(issue_id, 1.0) + + # Optional: Attach the confidence score to the issue metadata + # for reporting/debugging + issue.metadata["validation_confidence"] = confidence + + if confidence >= 0.3: + final_issues.append(issue) + issues = final_issues + return issues def _check_too_many_parameters(self, tree: ast.AST, file_path: Path) -> List[CodeIssue]: diff --git a/refactron/core/config.py b/refactron/core/config.py index 4f0c830..e83d811 100644 --- a/refactron/core/config.py +++ b/refactron/core/config.py @@ -130,6 +130,9 @@ class RefactronConfig: pattern_learning_enabled: bool = True # Enable learning from feedback pattern_ranking_enabled: bool = True # Enable ranking based on learned patterns + # AI Triage settings + enable_ai_triage: bool = False # Use LLM to filter false positive code smells + @classmethod def from_file( cls, @@ -243,6 +246,7 @@ def to_file(self, config_path: Path) -> None: ), "pattern_learning_enabled": self.pattern_learning_enabled, "pattern_ranking_enabled": self.pattern_ranking_enabled, + "enable_ai_triage": self.enable_ai_triage, } try: diff --git a/tests/test_analyzers.py b/tests/test_analyzers.py index ed6109d..43459da 100644 --- a/tests/test_analyzers.py +++ b/tests/test_analyzers.py @@ -1,10 +1,12 @@ """Tests for analyzers.""" from pathlib import Path +from unittest.mock import MagicMock from refactron.analyzers.code_smell_analyzer import CodeSmellAnalyzer from refactron.analyzers.complexity_analyzer import ComplexityAnalyzer from refactron.core.config import RefactronConfig +from refactron.llm.orchestrator import LLMOrchestrator def test_complexity_analyzer() -> None: @@ -55,6 +57,49 @@ def method_without_docstring(self): assert analyzer.name == "code_smells" +def test_code_smell_ai_triage_filtering() -> None: + """Test that CodeSmellAnalyzer filters issues based on AI triage validation.""" + config = RefactronConfig(enable_ai_triage=True) + + # Mock the LLMOrchestrator + mock_orchestrator = MagicMock(spec=LLMOrchestrator) + + # Create the analyzer with the mocked orchestrator + analyzer = CodeSmellAnalyzer(config, orchestrator=mock_orchestrator) + + code = """ +def deeply_nested(): + if True: + if True: + if True: + if True: + if True: + pass +""" + + # We expect 2 issues: deep nesting (S002) and missing docstring (S005). + # The mock will return S002 with low confidence (0.2) + # and ignore S005 or give it high confidence (0.9). + mock_orchestrator.evaluate_issues_batch.return_value = {"S002": 0.2, "S005": 0.9} + + issues = analyzer.analyze(Path("test.py"), code) + + # The S002 issue should be filtered out. S005 should remain. + assert len(issues) == 1 + assert issues[0].rule_id == "S005" + mock_orchestrator.evaluate_issues_batch.assert_called_once() + + # Test case 2: High confidence for both + mock_orchestrator.evaluate_issues_batch.return_value = {"S002": 0.9, "S005": 0.9} + + issues = analyzer.analyze(Path("test.py"), code) + + # Neither should be filtered out + assert len(issues) == 2 + assert any(i.rule_id == "S002" for i in issues) + assert any(i.rule_id == "S005" for i in issues) + + def test_analyzer_handles_syntax_errors() -> None: """Test that analyzers handle syntax errors gracefully.""" config = RefactronConfig() From 4e3ca22997c5e3f321cdaaa1a1c2f614c7cf8891 Mon Sep 17 00:00:00 2001 From: shrutu0929 Date: Wed, 11 Mar 2026 19:22:39 +0530 Subject: [PATCH 2/4] chore: resolve all flake8 and mypy errors reported by pre-commit --- refactron/analyzers/complexity_analyzer.py | 4 +- refactron/cli.py | 8 ++-- refactron/core/config.py | 2 +- refactron/core/config_loader.py | 2 +- refactron/core/memory_profiler.py | 2 +- refactron/core/repositories.py | 10 +++-- refactron/core/workspace.py | 3 +- refactron/llm/backend_client.py | 9 ++-- refactron/llm/client.py | 2 +- refactron/llm/models.py | 4 +- refactron/llm/orchestrator.py | 20 ++++++++- refactron/llm/safety.py | 6 +-- refactron/rag/indexer.py | 24 +++++----- refactron/rag/parser.py | 52 +++++++++++++++------- refactron/rag/retriever.py | 5 ++- scripts/analyze_feedback_data.py | 26 +++++------ tests/test_analyzers.py | 3 +- tests/test_backend_client.py | 3 +- tests/test_config_loader_edge_cases.py | 2 +- tests/test_config_management.py | 2 +- tests/test_llm_orchestrator.py | 3 +- tests/test_patterns_integration.py | 8 +--- tests/test_rag_indexer.py | 3 +- 23 files changed, 119 insertions(+), 84 deletions(-) diff --git a/refactron/analyzers/complexity_analyzer.py b/refactron/analyzers/complexity_analyzer.py index 0d8969c..c413bc1 100644 --- a/refactron/analyzers/complexity_analyzer.py +++ b/refactron/analyzers/complexity_analyzer.py @@ -4,8 +4,8 @@ from pathlib import Path from typing import List, Union -from radon.complexity import cc_visit -from radon.metrics import mi_visit +from radon.complexity import cc_visit # type: ignore +from radon.metrics import mi_visit # type: ignore from refactron.analyzers.base_analyzer import BaseAnalyzer from refactron.core.models import CodeIssue, IssueCategory, IssueLevel diff --git a/refactron/cli.py b/refactron/cli.py index 3b2c725..6cc2ff1 100644 --- a/refactron/cli.py +++ b/refactron/cli.py @@ -12,7 +12,7 @@ import click import requests # type: ignore -import yaml +import yaml # type: ignore from rich import box from rich.align import Align from rich.console import Console @@ -1146,7 +1146,7 @@ def _interactive_file_selector(workspace_path: Path) -> Path: console.print( f"\n[success]āœ“ Selected: {selected_path.relative_to(workspace_path)}[/success]\n" ) - return selected_path + return Path(selected_path) except (KeyboardInterrupt, EOFError): console.print("\n[yellow]Selection cancelled.[/yellow]") @@ -3253,7 +3253,7 @@ def patterns_profile(project_path: str, config_path: Optional[str]) -> None: @click.option("--line", type=int, help="Specific line number to fix") @click.option("--interactive/--no-interactive", default=True, help="Use interactive mode") @click.option("--apply/--no-apply", default=False, help="Apply the suggested changes to the file") -def suggest(target: Optional[str], line: Optional[int], interactive: bool, apply: bool): +def suggest(target: Optional[str], line: Optional[int], interactive: bool, apply: bool) -> None: """ Generate AI-powered refactoring suggestions. @@ -3413,7 +3413,7 @@ def suggest(target: Optional[str], line: Optional[int], interactive: bool, apply "--apply/--no-apply", default=False, help="Apply the documentation changes to the file" ) @click.option("--interactive/--no-interactive", default=True, help="Use interactive mode for apply") -def document(target: str, apply: bool, interactive: bool): +def document(target: str, apply: bool, interactive: bool) -> None: """ Generate Google-style docstrings for a Python file. diff --git a/refactron/core/config.py b/refactron/core/config.py index e83d811..cc2befa 100644 --- a/refactron/core/config.py +++ b/refactron/core/config.py @@ -4,7 +4,7 @@ from pathlib import Path from typing import Any, Dict, List, Optional -import yaml +import yaml # type: ignore from refactron.core.config_loader import ConfigLoader from refactron.core.config_validator import ConfigValidator diff --git a/refactron/core/config_loader.py b/refactron/core/config_loader.py index eb93c56..ff93b9a 100644 --- a/refactron/core/config_loader.py +++ b/refactron/core/config_loader.py @@ -4,7 +4,7 @@ from pathlib import Path from typing import Any, Dict, Optional -import yaml +import yaml # type: ignore from refactron.core.config_validator import ConfigValidator from refactron.core.exceptions import ConfigError diff --git a/refactron/core/memory_profiler.py b/refactron/core/memory_profiler.py index 1440ce8..f8b1eb4 100644 --- a/refactron/core/memory_profiler.py +++ b/refactron/core/memory_profiler.py @@ -59,7 +59,7 @@ def __init__( # Try to import psutil for accurate memory tracking self._psutil_available = False try: - import psutil + import psutil # type: ignore self._psutil = psutil self._process = psutil.Process(os.getpid()) diff --git a/refactron/core/repositories.py b/refactron/core/repositories.py index 3cf1ac4..47f16b8 100644 --- a/refactron/core/repositories.py +++ b/refactron/core/repositories.py @@ -76,7 +76,6 @@ def list_repositories(api_base_url: str, timeout_seconds: int = 10) -> List[Repo if creds.expires_at: try: # Parse the expiration time - from datetime import datetime if isinstance(creds.expires_at, str): # Remove timezone info for comparison @@ -122,8 +121,10 @@ def list_repositories(api_base_url: str, timeout_seconds: int = 10) -> List[Repo ) if not isinstance(repositories_data, list): raise RuntimeError( - f"Unexpected API response format. Expected list or dict with 'repositories' key. " - f"Got: {type(data)} with keys: {list(data.keys()) if isinstance(data, dict) else 'N/A'}" + "Unexpected API response format. " + "Expected list or dict with 'repositories' key. " + f"Got: {type(data)} with keys: " + f"{list(data.keys()) if isinstance(data, dict) else 'N/A'}" ) else: raise RuntimeError(f"Unexpected API response type: {type(data)}") @@ -151,7 +152,8 @@ def list_repositories(api_base_url: str, timeout_seconds: int = 10) -> List[Repo ) elif e.code == 403: raise RuntimeError( - "GitHub access denied. Please reconnect your GitHub account on the Refactron website." + "GitHub access denied. " + "Please reconnect your GitHub account on the Refactron website." ) elif e.code == 404: raise RuntimeError( diff --git a/refactron/core/workspace.py b/refactron/core/workspace.py index 03b56d6..db5d948 100644 --- a/refactron/core/workspace.py +++ b/refactron/core/workspace.py @@ -121,7 +121,8 @@ def get_workspace(self, repo_name: str) -> Optional[WorkspaceMapping]: # Try matching by short name (repo name without user) repo_name_lower = repo_name.lower() for full_name, workspace_data in workspaces.items(): - # Extract short name from full name (e.g., "volumeofsphere" from "omsherikar/volumeofsphere") + # Extract short name from full name + # (e.g., "volumeofsphere" from "omsherikar/volumeofsphere") short_name = full_name.split("/")[-1].lower() if short_name == repo_name_lower: return WorkspaceMapping.from_dict(workspace_data) diff --git a/refactron/llm/backend_client.py b/refactron/llm/backend_client.py index 8687bdd..62ea661 100644 --- a/refactron/llm/backend_client.py +++ b/refactron/llm/backend_client.py @@ -2,10 +2,9 @@ from __future__ import annotations -import os -from typing import Any, Dict, Optional +from typing import Optional -import requests +import requests # type: ignore from refactron.core.credentials import load_credentials @@ -94,7 +93,7 @@ def generate( raise RuntimeError(f"Backend LLM proxy error ({response.status_code}): {error_msg}") data = response.json() - return data["content"] + return str(data["content"]) except requests.exceptions.RequestException as e: raise RuntimeError(f"Failed to connect to Refactron backend: {e}") @@ -114,6 +113,6 @@ def check_health(self) -> bool: f"{self.backend_url}/api/llm/health", timeout=10, ) - return response.status_code == 200 + return bool(response.status_code == 200) except Exception: return False diff --git a/refactron/llm/client.py b/refactron/llm/client.py index bc3a576..2aa528a 100644 --- a/refactron/llm/client.py +++ b/refactron/llm/client.py @@ -79,7 +79,7 @@ def generate( max_tokens=max_tokens or self.max_tokens, ) - return response.choices[0].message.content + return str(response.choices[0].message.content or "") def check_health(self) -> bool: """Check if the Groq API is accessible. diff --git a/refactron/llm/models.py b/refactron/llm/models.py index 82ff83f..5b6e4fe 100644 --- a/refactron/llm/models.py +++ b/refactron/llm/models.py @@ -4,7 +4,7 @@ import uuid from dataclasses import dataclass, field from enum import Enum -from typing import Any, Dict, List, Optional +from typing import List, Optional from refactron.core.models import CodeIssue @@ -58,7 +58,7 @@ class RefactoringSuggestion: suggestion_id: str = field(default_factory=lambda: str(uuid.uuid4())) timestamp: float = field(default_factory=time.time) - def __post_init__(self): + def __post_init__(self) -> None: if self.safety_result is None: # Default empty safety result self.safety_result = SafetyCheckResult( diff --git a/refactron/llm/orchestrator.py b/refactron/llm/orchestrator.py index f4da49d..1fe5ebc 100644 --- a/refactron/llm/orchestrator.py +++ b/refactron/llm/orchestrator.py @@ -5,7 +5,7 @@ import os import re from pathlib import Path -from typing import List, Optional, Union +from typing import Dict, List, Optional, Union from refactron.core.models import CodeIssue, IssueCategory, IssueLevel from refactron.llm.backend_client import BackendLLMClient @@ -246,6 +246,24 @@ def generate_documentation( status=SuggestionStatus.FAILED, ) + def evaluate_issues_batch(self, issues: List[CodeIssue], source_code: str) -> Dict[str, float]: + """Batch evaluate confidence for multiple issues. + + Args: + issues: List of issues to evaluate. + source_code: The source code context. + + Returns: + A dictionary mapping issue rule_ids (or fallback IDs) to a confidence score. + """ + # Default implementation returns 1.0 (high confidence) for all issues + # Can be enhanced to actually call the LLM for batch triage + scores = {} + for i, issue in enumerate(issues): + issue_id = getattr(issue, "rule_id", None) or f"issue_{i}" + scores[issue_id] = 1.0 + return scores + def _clean_json_response(self, text: str) -> str: """Clean LLM response to extract JSON.""" text = text.strip() diff --git a/refactron/llm/safety.py b/refactron/llm/safety.py index a3b1543..3b4e7c5 100644 --- a/refactron/llm/safety.py +++ b/refactron/llm/safety.py @@ -1,7 +1,7 @@ """Safety gate for validating LLM-generated code.""" import ast -from typing import List, Optional +from typing import List, Set from refactron.llm.models import RefactoringSuggestion, SafetyCheckResult @@ -90,8 +90,8 @@ def _check_dangerous_imports(self, proposed_code: str, original_code: str) -> Li """Check for potentially dangerous imports that are NEW.""" dangerous_modules = ["subprocess", "os", "shutil", "sys"] - def get_imports(code): - imports = set() + def get_imports(code: str) -> Set[str]: + imports: Set[str] = set() try: tree = ast.parse(code) for node in ast.walk(tree): diff --git a/refactron/rag/indexer.py b/refactron/rag/indexer.py index 4d62fec..66df3f1 100644 --- a/refactron/rag/indexer.py +++ b/refactron/rag/indexer.py @@ -5,12 +5,12 @@ import json from dataclasses import dataclass from pathlib import Path -from typing import List, Optional +from typing import Dict, List, Optional, cast try: import chromadb from chromadb.config import Settings - from sentence_transformers import SentenceTransformer + from sentence_transformers import SentenceTransformer # type: ignore CHROMA_AVAILABLE = True except ImportError: @@ -20,7 +20,7 @@ CHROMA_AVAILABLE = False from refactron.rag.chunker import CodeChunk -from refactron.rag.parser import CodeParser, ParsedFile +from refactron.rag.parser import CodeParser # Import for type hints try: @@ -60,7 +60,8 @@ def __init__( """ if not CHROMA_AVAILABLE: raise RuntimeError( - "ChromaDB is not available. Install with: pip install chromadb sentence-transformers" + "ChromaDB is not available. Install with: " + "pip install chromadb sentence-transformers" ) self.workspace_path = Path(workspace_path) @@ -68,7 +69,6 @@ def __init__( self.index_path.mkdir(exist_ok=True) # Initialize LLM client for summarization - from refactron.llm.client import GroqClient self.llm_client = llm_client @@ -125,7 +125,7 @@ def index_repository( ] total_chunks = 0 - chunk_type_counts = {} + chunk_type_counts: Dict[str, int] = {} # Index each file for py_file in python_files: @@ -181,7 +181,8 @@ def _index_file(self, file_path: Path, summarize: bool = False) -> List[CodeChun try: summary = self._summarize_chunk(chunk) if summary: - # Prepend summary to content for embedding (makes it searchable by plain English) + # Prepend summary to content for embedding + # (makes it searchable by plain English) chunk.content = f"Summary: {summary}\n\n{chunk.content}" chunk.metadata["ai_summary"] = summary except Exception as e: @@ -207,7 +208,10 @@ def _summarize_chunk(self, chunk: CodeChunk) -> Optional[str]: try: summary = self.llm_client.generate( prompt=prompt, - system="You are a senior software architect. Provide a concise, semantic summary of code purpose.", + system=( + "You are a senior software architect. " + "Provide a concise, semantic summary of code purpose." + ), max_tokens=100, ) return summary.strip() @@ -277,11 +281,11 @@ def _save_metadata(self, metadata: dict) -> None: with open(metadata_file, "w") as f: json.dump(metadata, f, indent=2) - def _load_metadata(self) -> dict: + def _load_metadata(self) -> Dict: """Load index metadata.""" metadata_file = self.index_path / "metadata.json" if not metadata_file.exists(): return {} with open(metadata_file, "r") as f: - return json.load(f) + return cast(Dict, json.load(f)) diff --git a/refactron/rag/parser.py b/refactron/rag/parser.py index d48f49b..95d6864 100644 --- a/refactron/rag/parser.py +++ b/refactron/rag/parser.py @@ -4,7 +4,7 @@ from dataclasses import dataclass from pathlib import Path -from typing import Any, Dict, List, Optional, Tuple +from typing import List, Optional, Tuple try: import tree_sitter_python as tspython @@ -51,32 +51,52 @@ class ParsedFile: class CodeParser: """AST-aware code parser using tree-sitter.""" - def __init__(self): + def __init__(self) -> None: """Initialize the parser.""" if not TREE_SITTER_AVAILABLE: raise RuntimeError( - "tree-sitter is not available. Install with: pip install tree-sitter tree-sitter-python" + "tree-sitter is not available. Install with: " + "pip install tree-sitter tree-sitter-python" ) # Initialize Python language - handle different tree-sitter API versions - lang = tspython.language() + lang_data = tspython.language() - # In some versions, tspython.language() already returns a Language object - if isinstance(lang, Language): - PY_LANGUAGE = lang + # Try to get a proper Language object + py_language = None + if isinstance(lang_data, Language): + py_language = lang_data else: # Try newer API first (single argument) try: - PY_LANGUAGE = Language(lang) - except TypeError: + py_language = Language(lang_data) + except (TypeError, ValueError): # Try older API (needs name) try: - PY_LANGUAGE = Language(lang, "python") - except TypeError: - # Last resort: try as keyword - PY_LANGUAGE = Language(lang, name="python") - - self.parser = Parser(PY_LANGUAGE) + py_language = Language(lang_data, "python") + except (TypeError, ValueError): + try: + py_language = Language(lang_data, name="python") + except (TypeError, ValueError): + # Fallback to using the raw data if it can be used directly + py_language = lang_data + + # Initialize Parser - handle different tree-sitter API versions + try: + self.parser = Parser(py_language) + except Exception: + # Older API might not take it in constructor + self.parser = Parser() + try: + self.parser.set_language(py_language) + except Exception: + # If everything fails, it might be due to a mismatch between + # tree-sitter-python and tree-sitter versions. + # There's not much more we can do here but raise with context. + raise RuntimeError( + "Failed to initialize tree-sitter parser with language " + f"data of type {type(lang_data)}" + ) def parse_file(self, file_path: Path) -> ParsedFile: """Parse a Python file. @@ -256,7 +276,7 @@ def _extract_class_docstring(self, node: Node, source: bytes) -> Optional[str]: def _extract_parameters(self, node: Node, source: bytes) -> List[str]: """Extract function parameters.""" - params = [] + params: List[str] = [] params_node = node.child_by_field_name("parameters") if not params_node: return params diff --git a/refactron/rag/retriever.py b/refactron/rag/retriever.py index 2a71d1b..a68d1fe 100644 --- a/refactron/rag/retriever.py +++ b/refactron/rag/retriever.py @@ -9,7 +9,7 @@ try: import chromadb from chromadb.config import Settings - from sentence_transformers import SentenceTransformer + from sentence_transformers import SentenceTransformer # type: ignore CHROMA_AVAILABLE = True except ImportError: @@ -50,7 +50,8 @@ def __init__( """ if not CHROMA_AVAILABLE: raise RuntimeError( - "ChromaDB is not available. Install with: pip install chromadb sentence-transformers" + "ChromaDB is not available. Install with: " + "pip install chromadb sentence-transformers" ) self.workspace_path = Path(workspace_path) diff --git a/scripts/analyze_feedback_data.py b/scripts/analyze_feedback_data.py index 1093573..a9e3e5f 100644 --- a/scripts/analyze_feedback_data.py +++ b/scripts/analyze_feedback_data.py @@ -12,14 +12,12 @@ import sys from collections import Counter from pathlib import Path - -# Add parent directory to path for imports -sys.path.insert(0, str(Path(__file__).parent.parent)) +from typing import Dict, Optional from refactron.patterns.storage import PatternStorage -def analyze_feedback(): +def analyze_feedback() -> Optional[Dict]: """Analyze all available feedback data.""" # Find all pattern storage directories @@ -52,23 +50,23 @@ def analyze_feedback(): return None print(f"\n{'='*60}") - print(f"AGGREGATE STATISTICS") + print("AGGREGATE STATISTICS") print(f"{'='*60}\n") - print(f"šŸ“Š Total Records:") + print("šŸ“Š Total Records:") print(f" Feedback: {len(all_feedback)}") print(f" Patterns: {len(all_patterns)}") # Action distribution actions = Counter(f.action for f in all_feedback) - print(f"\nāœ… Action Distribution:") + print("\nāœ… Action Distribution:") for action, count in actions.most_common(): pct = count / len(all_feedback) * 100 print(f" {action:12s}: {count:4d} ({pct:5.1f}%)") # Operation types operation_types = Counter(f.operation_type for f in all_feedback) - print(f"\nšŸ”§ Operation Types:") + print("\nšŸ”§ Operation Types:") for op_type, count in operation_types.most_common(5): pct = count / len(all_feedback) * 100 print(f" {op_type:20s}: {count:4d} ({pct:5.1f}%)") @@ -79,24 +77,24 @@ def analyze_feedback(): ) with_reason = sum(1 for f in all_feedback if hasattr(f, "reason") and f.reason) - print(f"\nšŸ“‹ Data Quality:") + print("\nšŸ“‹ Data Quality:") print(f" With pattern hash: {with_patterns:4d} ({with_patterns/len(all_feedback)*100:5.1f}%)") print(f" With reason: {with_reason:4d} ({with_reason/len(all_feedback)*100:5.1f}%)") # ML readiness quality_score = with_patterns / len(all_feedback) if all_feedback else 0 - print(f"\nšŸŽÆ ML Readiness:") + print("\nšŸŽÆ ML Readiness:") print(f" Quality Score: {quality_score:.2%}") if len(all_feedback) < 50: - print(f" Status: āŒ INSUFFICIENT DATA") + print(" Status: āŒ INSUFFICIENT DATA") print(f" Need: {50 - len(all_feedback)} more feedback records") elif quality_score < 0.7: - print(f" Status: āš ļø LOW QUALITY") - print(f" Many records missing pattern hashes") + print(" Status: āš ļø LOW QUALITY") + print(" Many records missing pattern hashes") else: - print(f" Status: āœ… READY FOR TRAINING") + print(" Status: āœ… READY FOR TRAINING") # Save detailed report report = { diff --git a/tests/test_analyzers.py b/tests/test_analyzers.py index 43459da..7434a5f 100644 --- a/tests/test_analyzers.py +++ b/tests/test_analyzers.py @@ -6,7 +6,6 @@ from refactron.analyzers.code_smell_analyzer import CodeSmellAnalyzer from refactron.analyzers.complexity_analyzer import ComplexityAnalyzer from refactron.core.config import RefactronConfig -from refactron.llm.orchestrator import LLMOrchestrator def test_complexity_analyzer() -> None: @@ -62,7 +61,7 @@ def test_code_smell_ai_triage_filtering() -> None: config = RefactronConfig(enable_ai_triage=True) # Mock the LLMOrchestrator - mock_orchestrator = MagicMock(spec=LLMOrchestrator) + mock_orchestrator = MagicMock() # Create the analyzer with the mocked orchestrator analyzer = CodeSmellAnalyzer(config, orchestrator=mock_orchestrator) diff --git a/tests/test_backend_client.py b/tests/test_backend_client.py index fe0399e..c3b6fdd 100644 --- a/tests/test_backend_client.py +++ b/tests/test_backend_client.py @@ -3,7 +3,6 @@ from unittest.mock import MagicMock, patch import pytest -import requests from refactron.llm.backend_client import BackendLLMClient @@ -56,7 +55,7 @@ def test_backend_client_error_handling(mock_post, mock_credentials): client = BackendLLMClient() with pytest.raises( - RuntimeError, match="Backend LLM proxy error \(500\): Internal Server Error" + RuntimeError, match=r"Backend LLM proxy error \(500\): Internal Server Error" ): client.generate(prompt="Refactor this") diff --git a/tests/test_config_loader_edge_cases.py b/tests/test_config_loader_edge_cases.py index a52d983..c1df6c4 100644 --- a/tests/test_config_loader_edge_cases.py +++ b/tests/test_config_loader_edge_cases.py @@ -4,7 +4,7 @@ from pathlib import Path import pytest -import yaml +import yaml # type: ignore from refactron.core.config_loader import ConfigLoader from refactron.core.exceptions import ConfigError diff --git a/tests/test_config_management.py b/tests/test_config_management.py index be0ad44..4fec4b6 100644 --- a/tests/test_config_management.py +++ b/tests/test_config_management.py @@ -4,7 +4,7 @@ from pathlib import Path import pytest -import yaml +import yaml # type: ignore from refactron.core.config import RefactronConfig from refactron.core.config_loader import ConfigLoader diff --git a/tests/test_llm_orchestrator.py b/tests/test_llm_orchestrator.py index 27b1e88..cb95413 100644 --- a/tests/test_llm_orchestrator.py +++ b/tests/test_llm_orchestrator.py @@ -1,13 +1,12 @@ """Tests for LLM Orchestrator.""" -import json from pathlib import Path from unittest.mock import MagicMock, Mock import pytest from refactron.core.models import CodeIssue, IssueCategory, IssueLevel -from refactron.llm.models import RefactoringSuggestion, SuggestionStatus +from refactron.llm.models import SuggestionStatus from refactron.llm.orchestrator import LLMOrchestrator from refactron.rag.retriever import RetrievedContext diff --git a/tests/test_patterns_integration.py b/tests/test_patterns_integration.py index de724b4..3bd5500 100644 --- a/tests/test_patterns_integration.py +++ b/tests/test_patterns_integration.py @@ -257,12 +257,8 @@ def func2(): # Patterns should be stored in separate directories assert storage1_dir.exists() or storage2_dir.exists() - # Verify actual pattern isolation: patterns from project1 should not be in project2 - # and vice versa (they use different storage directories) - pattern_hashes1 = {p.pattern_hash for p in patterns1.values()} - pattern_hashes2 = {p.pattern_hash for p in patterns2.values()} - - # Verify the key property: storage directories are different (isolation works) + # Verify actual pattern isolation + assert refactron1.pattern_storage.storage_dir != refactron2.pattern_storage.storage_dir # Note: Anonymized fingerprinting may make structurally similar code have same hash # which is correct behavior - the test should check storage isolation assert refactron1.pattern_storage.storage_dir != refactron2.pattern_storage.storage_dir diff --git a/tests/test_rag_indexer.py b/tests/test_rag_indexer.py index 7305fe6..d9820ff 100644 --- a/tests/test_rag_indexer.py +++ b/tests/test_rag_indexer.py @@ -1,9 +1,8 @@ """Tests for the RAG indexer module.""" -import sys import tempfile from pathlib import Path -from unittest.mock import MagicMock, Mock, create_autospec, patch +from unittest.mock import MagicMock, Mock, patch import pytest From ab375e25ac2cd1a4727b47183dc369b08f5691f6 Mon Sep 17 00:00:00 2001 From: shrutu0929 Date: Wed, 11 Mar 2026 19:50:29 +0530 Subject: [PATCH 3/4] chore: apply formatting fixes and update auto-label workflow permissions --- .github/workflows/auto-label.yml | 9 +++-- all_flake8_errors.txt | Bin 180130 -> 0 bytes coverage.json | 1 + docs/advanced/ci-cd.mdx | 12 +++--- docs/advanced/monitoring.mdx | 8 ++-- docs/advanced/performance.mdx | 10 ++--- docs/api-reference/refactron-class.mdx | 4 +- docs/docs.json | 2 +- docs/essentials/authentication.mdx | 10 ++--- docs/essentials/configuration.mdx | 16 ++++---- docs/essentials/installation.mdx | 8 ++-- docs/guides/ai-features.mdx | 32 ++++++++-------- docs/guides/code-analysis.mdx | 28 +++++++------- docs/guides/pattern-learning.mdx | 16 ++++---- docs/guides/refactoring.mdx | 50 ++++++++++++------------- docs/introduction.mdx | 10 ++--- docs/quickstart.mdx | 22 +++++------ docs/resources/faq.mdx | 38 +++++++++---------- documentation/docs/CLI_REFERENCE.md | 49 ++++++++++++------------ documentation/docs/api/analyzers.md | 1 - documentation/docs/api/autofix.md | 1 - documentation/docs/api/cicd.md | 1 - documentation/docs/api/core.md | 1 - documentation/docs/api/llm.md | 1 - documentation/docs/api/patterns.md | 1 - documentation/docs/api/rag.md | 1 - documentation/docs/api/refactorers.md | 1 - flake8_errors.txt | Bin 7996 -> 0 bytes flake8_errors_temp.txt | Bin 7168 -> 0 bytes flake8_errors_utf8.txt | 39 ------------------- 30 files changed, 164 insertions(+), 208 deletions(-) delete mode 100644 all_flake8_errors.txt create mode 100644 coverage.json delete mode 100644 flake8_errors.txt delete mode 100644 flake8_errors_temp.txt delete mode 100644 flake8_errors_utf8.txt diff --git a/.github/workflows/auto-label.yml b/.github/workflows/auto-label.yml index 4dcaf4e..94caedb 100644 --- a/.github/workflows/auto-label.yml +++ b/.github/workflows/auto-label.yml @@ -4,13 +4,14 @@ name: Auto-label Bot on: issues: types: [opened, edited] - pull_request: + pull_request_target: types: [opened, edited, synchronize] +# Default permissions for the workflow permissions: + contents: read issues: write pull-requests: write - contents: read jobs: label-issues: @@ -20,6 +21,7 @@ jobs: - name: Auto-label issues uses: actions/github-script@v8 with: + github-token: ${{ secrets.GITHUB_TOKEN }} script: | const { owner, repo, number } = context.issue; const issue = context.payload.issue; @@ -116,7 +118,7 @@ jobs: } label-pull-requests: - if: github.event_name == 'pull_request' + if: github.event_name == 'pull_request_target' runs-on: ubuntu-latest steps: - name: Checkout code @@ -127,6 +129,7 @@ jobs: - name: Auto-label PRs uses: actions/github-script@v8 with: + github-token: ${{ secrets.GITHUB_TOKEN }} script: | const { owner, repo, number } = context.issue; const pr = context.payload.pull_request; diff --git a/all_flake8_errors.txt b/all_flake8_errors.txt deleted file mode 100644 index 51801fa10646d1287a4485c73bfa76fb1a528ebb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 180130 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 - + Fail builds based on severity: ```yaml @@ -142,7 +142,7 @@ repos: max_error_issues: 10 ``` - + Speed up CI runs by caching pip packages: ```yaml @@ -153,7 +153,7 @@ repos: key: ${{ runner.os }}-pip-refactron ``` - + Create HTML reports and save as artifacts: ```bash diff --git a/docs/advanced/monitoring.mdx b/docs/advanced/monitoring.mdx index 9a0441d..0a63072 100644 --- a/docs/advanced/monitoring.mdx +++ b/docs/advanced/monitoring.mdx @@ -8,7 +8,7 @@ description: 'Production monitoring and telemetry' Refactron includes comprehensive logging and monitoring capabilities for production environments: - **Structured Logging** - JSON-formatted logs for CI/CD -- **Metrics Collection** - Track analysis time and success rates +- **Metrics Collection** - Track analysis time and success rates - **Prometheus Integration** - Expose metrics via HTTP endpoint - **Opt-in Telemetry** - Anonymous usage analytics @@ -187,15 +187,15 @@ prometheus_port: 9090 JSON format integrates easily with log aggregation systems - + Track performance and identify bottlenecks - + Visualize Refactron metrics over time - + Respect user privacy with opt-in telemetry diff --git a/docs/advanced/performance.mdx b/docs/advanced/performance.mdx index 9734477..cc28219 100644 --- a/docs/advanced/performance.mdx +++ b/docs/advanced/performance.mdx @@ -36,12 +36,12 @@ Cache parsed Abstract Syntax Trees to avoid re-parsing. - Reduces CPU usage - Especially effective for large files - + ```python from refactron import Refactron from refactron.core.config import RefactronConfig - + config = RefactronConfig( enable_ast_cache=True, max_ast_cache_size_mb=100 @@ -49,7 +49,7 @@ Cache parsed Abstract Syntax Trees to avoid re-parsing. refactron = Refactron(config) ``` - + ```python stats = refactron.get_performance_stats() @@ -156,13 +156,13 @@ refactron.clear_caches() print(f"Hit rate: {stats['ast_cache']['hit_rate']}%") ``` - + - Reduce cache size: `max_ast_cache_size_mb: 50` - Lower parallel workers: `max_parallel_workers: 2` - Clear caches periodically: `refactron.clear_caches()` - + Disable for small codebases: ```yaml diff --git a/docs/api-reference/refactron-class.mdx b/docs/api-reference/refactron-class.mdx index 40c9f7d..a93705f 100644 --- a/docs/api-reference/refactron-class.mdx +++ b/docs/api-reference/refactron-class.mdx @@ -80,7 +80,7 @@ def refactor( Specific refactoring types to apply. None = all types. - + Available types: - `extract_constant` - `add_docstring` @@ -316,7 +316,7 @@ for op in result.operations: print(f" File: {op.file_path}:{op.line_number}") print(f" Risk: {op.risk_score}") print(f" Description: {op.description}") - + # Record feedback refactron.record_feedback( operation_id=op.operation_id, diff --git a/docs/docs.json b/docs/docs.json index ae238f7..cdf306b 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -93,4 +93,4 @@ "vscode" ] } -} \ No newline at end of file +} diff --git a/docs/essentials/authentication.mdx b/docs/essentials/authentication.mdx index ddb6cd9..4f7e397 100644 --- a/docs/essentials/authentication.mdx +++ b/docs/essentials/authentication.mdx @@ -84,17 +84,17 @@ Features that require authentication: refactron repo connect my-repo ``` - + Enhanced AI-powered refactoring with cloud LLM models - + ```bash refactron metrics ``` - + Share learned patterns across your team @@ -120,7 +120,7 @@ Cloud features gracefully degrade when offline. 2. Paste it into your browser manually 3. Complete the authentication - + If you see "Token expired" errors: ```bash @@ -128,7 +128,7 @@ Cloud features gracefully degrade when offline. refactron login ``` - + Verify the API key is set correctly: ```bash diff --git a/docs/essentials/configuration.mdx b/docs/essentials/configuration.mdx index 335614a..c3d3abe 100644 --- a/docs/essentials/configuration.mdx +++ b/docs/essentials/configuration.mdx @@ -67,23 +67,23 @@ pattern_storage_dir: null # null = auto-detect Detects security vulnerabilities like SQL injection, code injection, hardcoded secrets, and SSRF - + Identifies magic numbers, long functions, excessive parameters, and deep nesting - + Measures cyclomatic complexity, maintainability index, and nested loops - + Checks for missing or incomplete type annotations - + Finds unused functions and unreachable code - + Analyzes circular imports and wildcard imports @@ -95,15 +95,15 @@ pattern_storage_dir: null # null = auto-detect Extract magic numbers into named constants - + Add missing docstrings to functions and classes - + Simplify complex conditional statements - + Reduce function parameter count using dataclasses or dictionaries diff --git a/docs/essentials/installation.mdx b/docs/essentials/installation.mdx index 0ec2f0e..7fe801e 100644 --- a/docs/essentials/installation.mdx +++ b/docs/essentials/installation.mdx @@ -6,7 +6,7 @@ description: 'How to install and set up Refactron' ## Requirements - **Python Version**: 3.8 or higher + **Python Version**: 3.8 or higher **Supported Platforms**: macOS, Linux, Windows @@ -71,7 +71,7 @@ Refactron automatically installs these dependencies: - **radon** - Complexity metrics - **astroid** - AST analysis - + - **chromadb** - Vector database for RAG - **tree-sitter** - Code parsing @@ -90,7 +90,7 @@ Refactron automatically installs these dependencies: pip install --user refactron ``` - + Ensure you're using Python 3.8+: ```bash @@ -101,7 +101,7 @@ Refactron automatically installs these dependencies: python3.10 -m pip install refactron ``` - + On macOS, you may need to install certificates: ```bash diff --git a/docs/guides/ai-features.mdx b/docs/guides/ai-features.mdx index 16466e6..dd843a2 100644 --- a/docs/guides/ai-features.mdx +++ b/docs/guides/ai-features.mdx @@ -120,19 +120,19 @@ refactron refactor myfile.py --ai --apply Refactron analyzes your code for issues - + RAG system retrieves relevant code chunks from your project - + LLM generates refactoring suggestions with project context - + Safety gate validates syntax and checks for issues - + Suggestions presented with explanations and risk scores @@ -158,10 +158,10 @@ AI-powered refactoring suggests: # AI-suggested refactoring def process_users(users): """Process and filter users based on eligibility criteria. - + Args: users: List of user objects to process - + Returns: List of eligible users (adult, active, verified) """ @@ -202,21 +202,21 @@ refactron suggest myfile.py --line 42 --apply Fast, cloud-based LLM provider with free tier - + **Models:** - `llama3-70b-8192` - Best quality - `llama3-8b-8192` - Faster, good quality - `mixtral-8x7b-32768` - Long context window - + **Setup:** ```bash export GROQ_API_KEY='your-key' ``` - + Bring your own LLM provider - + Configure in `.refactron.yaml`: ```yaml llm: @@ -301,19 +301,19 @@ refactron feedback --action rejected --reason "Breaks API contrac Re-run `refactron rag index` after significant code changes for accurate context - + Models like Llama 3 70B provide better refactoring logic than smaller models - + Use `--preview` to review AI-generated code before applying - + Record feedback to improve AI suggestions over time - + Run your test suite after applying AI refactorings @@ -329,14 +329,14 @@ refactron feedback --action rejected --reason "Breaks API contrac ``` Export it in your shell profile for persistence - + Create index first: ```bash refactron rag index ``` - + - Use smaller models (llama3-8b-8192) - Reduce `max_tokens` diff --git a/docs/guides/code-analysis.mdx b/docs/guides/code-analysis.mdx index 9a8de3a..9515e29 100644 --- a/docs/guides/code-analysis.mdx +++ b/docs/guides/code-analysis.mdx @@ -49,7 +49,7 @@ for issue in analysis.issues: - **Code Injection**: Use of `eval()` and `exec()` - **Hardcoded Secrets**: API keys, passwords in code - **SSRF Vulnerabilities**: Unsafe URL handling - + ```python # āŒ Security issue detected query = f"SELECT * FROM users WHERE id = {user_id}" # SQL injection @@ -57,14 +57,14 @@ for issue in analysis.issues: API_KEY = "hardcoded-secret-123" # Hardcoded secret ``` - + Identifies code smells and maintainability issues: - **Magic Numbers**: Unexplained numeric constants - **Long Functions**: Functions exceeding length threshold - **Excessive Parameters**: Too many function parameters - **Deep Nesting**: Complex nested control structures - + ```python # āŒ Code quality issues def process(a, b, c, d, e, f, g): # Too many parameters @@ -75,14 +75,14 @@ for issue in analysis.issues: return 42 # Magic number ``` - + Measures code complexity: - **Cyclomatic Complexity**: Control flow complexity - **Cognitive Complexity**: Human readability complexity - **Maintainability Index**: Overall maintainability score - **Nested Loops**: Performance-impacting nested iterations - + ```python # āŒ High complexity def complex_function(data): @@ -94,51 +94,51 @@ for issue in analysis.issues: process(val) ``` - + Checks type annotation coverage: - Missing function type hints - Incomplete parameter annotations - Missing return type annotations - + ```python # āŒ Missing type hints def calculate(x, y): # No type hints return x + y - + # āœ… Properly typed def calculate(x: int, y: int) -> int: return x + y ``` - + Finds unused and unreachable code: - Unused variables - Unused functions - Unreachable code blocks - + ```python # āŒ Dead code def process(): result = expensive_calculation() # Unused variable return None - + def unused_function(): # Never called pass - + def example(): return True print("Never executed") # Unreachable ``` - + Analyzes import patterns: - Circular imports - Wildcard imports - Deprecated modules - + ```python # āŒ Dependency issues from module_a import * # Wildcard import diff --git a/docs/guides/pattern-learning.mdx b/docs/guides/pattern-learning.mdx index 3022ede..b468c48 100644 --- a/docs/guides/pattern-learning.mdx +++ b/docs/guides/pattern-learning.mdx @@ -13,11 +13,11 @@ Refactron's Pattern Learning System learns from your refactoring decisions, buil When Refactron suggests a refactoring, it creates a unique "fingerprint" of the code pattern - + You provide feedback: **accepted**, **rejected**, or **ignored** - + Refactron tracks: - Acceptance rates for each pattern @@ -25,7 +25,7 @@ Refactron's Pattern Learning System learns from your refactoring decisions, buil - Code metrics improvements - Project-specific preferences - + Future suggestions ranked based on historical acceptance rates and patterns @@ -237,7 +237,7 @@ pattern_storage_dir: /custom/path/patterns - **Reject** inappropriate suggestions - **Ignore** if unsure - + For large projects, use automated tuning: ```bash @@ -245,14 +245,14 @@ pattern_storage_dir: /custom/path/patterns refactron patterns tune --auto ``` - + Periodically check pattern performance: ```bash refactron patterns analyze ``` - + In CI/CD environments, use consistent storage: ```yaml @@ -321,14 +321,14 @@ Pattern learning integrates with [AI Features](/guides/ai-features): 2. Verify storage directory is writable 3. Check logs: `refactron refactor --log-level DEBUG` - + **Solutions:** 1. Check `pattern_ranking_enabled` is `true` 2. Ensure patterns have been learned (provide feedback first) 3. Verify sufficient pattern history exists - + **Solutions:** 1. Check directory permissions diff --git a/docs/guides/refactoring.mdx b/docs/guides/refactoring.mdx index ac55e22..ac167f9 100644 --- a/docs/guides/refactoring.mdx +++ b/docs/guides/refactoring.mdx @@ -34,67 +34,67 @@ refactron refactor myfile.py Replaces magic numbers with named constants - + ```python # Before def calculate_tax(amount): return amount * 0.18 - + # After TAX_RATE = 0.18 - + def calculate_tax(amount): return amount * TAX_RATE ``` - + Adds missing docstrings to functions and classes - + ```python # Before def calculate_total(items): return sum(item.price for item in items) - + # After def calculate_total(items): """Calculate total price for list of items. - + Args: items: List of items with price attribute - + Returns: Total sum of item prices """ return sum(item.price for item in items) ``` - + Refactors complex conditional expressions - + ```python # Before if not (x < 10 or x > 20): process() - + # After if 10 <= x <= 20: process() ``` - + Reduces function parameters using dataclasses or dicts - + ```python # Before def create_user(name, email, age, city, country): pass - + # After from dataclasses import dataclass - + @dataclass class UserData: name: str @@ -102,7 +102,7 @@ refactron refactor myfile.py age: int city: str country: str - + def create_user(user: UserData): pass ``` @@ -226,29 +226,29 @@ file_ops.rollback_all() refactron analyze myproject/ ``` - + Preview refactoring suggestions ```bash refactron refactor myproject/ --preview ``` - + Review the diff output and risk scores - + Apply refactorings you want to keep ```bash refactron refactor myproject/ --type extract_constant ``` - + Run your tests to ensure nothing broke - + Rollback if something went wrong ```bash @@ -299,19 +299,19 @@ refactron feedback --action accepted Use `--preview` to see changes before applying them - + Commit your code before refactoring for easy rollback - + Run your test suite after applying refactorings - + Begin with safe refactorings, then gradually increase risk tolerance - + Refactor small portions at a time rather than entire codebase diff --git a/docs/introduction.mdx b/docs/introduction.mdx index 4d4ec7e..572b253 100644 --- a/docs/introduction.mdx +++ b/docs/introduction.mdx @@ -54,23 +54,23 @@ Refactron is a powerful Python library that analyzes your code for security vuln Detect SQL injection, code injection, hardcoded secrets, and SSRF vulnerabilities - + Identify magic numbers, long functions, excessive parameters, and deep nesting - + LLM orchestration with RAG (Retrieval-Augmented Generation) for context-aware refactoring - + Learn from your project-specific coding standards and improve over time - + AST caching, incremental analysis, and parallel processing for large codebases - + 14 automated fixers with configurable safety levels and rollback support diff --git a/docs/quickstart.mdx b/docs/quickstart.mdx index 35f585d..d653c9a 100644 --- a/docs/quickstart.mdx +++ b/docs/quickstart.mdx @@ -26,7 +26,7 @@ Follow this workflow to get the most out of Refactron: refactron login ``` - + Set up Refactron in your project: ```bash @@ -34,46 +34,46 @@ Follow this workflow to get the most out of Refactron: ``` Choose a template (base, django, fastapi, or flask) to get started quickly. - + Connect your GitHub repository for enhanced features: ```bash refactron repo connect ``` - + Run comprehensive code analysis: ```bash refactron analyze . --detailed ``` - + Generate AI-powered refactoring suggestions: ```bash refactron suggest myfile.py ``` - + Preview and apply refactoring changes: ```bash # Preview changes first refactron refactor myfile.py --preview - + # Apply when ready refactron refactor myfile.py --apply ``` - + Create a comprehensive technical debt report: ```bash refactron report . --format html -o report.html ``` - + Rollback changes if something goes wrong: ```bash @@ -155,15 +155,15 @@ When you run an analysis, you'll see: āœ“ Analyzing myproject/ Files analyzed: 25 Issues found: 12 - + CRITICAL (2): - SQL injection vulnerability (line 45) - Hardcoded secret detected (line 78) - + ERROR (4): - High cyclomatic complexity (line 120) - Deep nesting detected (line 156) - + WARNING (6): - Magic number usage (line 23) - Missing type hints (line 67) diff --git a/docs/resources/faq.mdx b/docs/resources/faq.mdx index a7e83c7..8c47a6c 100644 --- a/docs/resources/faq.mdx +++ b/docs/resources/faq.mdx @@ -9,15 +9,15 @@ description: 'Frequently asked questions' Refactron is an intelligent Python code refactoring tool that analyzes your code for issues and suggests automated improvements with safety guarantees. - + Yes! Refactron is open source and free to use. Some advanced features require an API key for authentication. - + Refactron supports Python 3.8 and above. - + Absolutely! Refactron is designed for CI/CD integration. Use `refactron ci` to generate configuration templates. @@ -36,7 +36,7 @@ description: 'Frequently asked questions' refactron login ``` - + Refactron works out of the box with sensible defaults. For customization, run: ```bash @@ -44,7 +44,7 @@ description: 'Frequently asked questions' ``` This creates a `.refactron.yaml` configuration file. - + Refactron automatically installs all required dependencies via pip. For AI features, you'll need a Groq API key (free tier available). @@ -60,7 +60,7 @@ description: 'Frequently asked questions' ``` This will scan your code and report issues by severity. - + Refactron includes multiple safety features: - **Preview mode** - See changes before applying @@ -68,7 +68,7 @@ description: 'Frequently asked questions' - **Automatic backups** - All changes are backed up - **Rollback** - Easily undo changes - + Yes! Use the `--type` flag: ```bash @@ -81,7 +81,7 @@ description: 'Frequently asked questions' - add_docstring ``` - + First, set your Groq API key: ```bash @@ -104,11 +104,11 @@ description: 'Frequently asked questions' By default, Refactron uses Groq (Llama 3). You can also configure custom LLM providers. - + When using AI features with cloud LLM providers (like Groq), code snippets are sent for analysis. The RAG indexing happens locally. You can use local LLM providers for complete privacy. - + Re-index after significant code changes: ```bash @@ -127,14 +127,14 @@ description: 'Frequently asked questions' Refactron learns from your feedback on refactoring suggestions. When you accept or reject suggestions, it adapts to your project's style and preferences. - + Yes, in `.refactron.yaml`: ```yaml enable_pattern_learning: false ``` - + By default in `.refactron/patterns/` in your project root. You can customize this: ```yaml @@ -152,7 +152,7 @@ description: 'Frequently asked questions' refactron auth status ``` - + Enable performance optimizations: ```yaml @@ -161,7 +161,7 @@ description: 'Frequently asked questions' max_parallel_workers: 4 ``` - + You can: 1. Provide feedback to pattern learning @@ -175,7 +175,7 @@ description: 'Frequently asked questions' - "*/tests/*" ``` - + List available rollback sessions: ```bash @@ -186,7 +186,7 @@ description: 'Frequently asked questions' refactron rollback --session ``` - + Create the index first: ```bash @@ -202,14 +202,14 @@ description: 'Frequently asked questions' Yes! Extend the `BaseAnalyzer` class: ```python from refactron.analyzers.base_analyzer import BaseAnalyzer - + class MyAnalyzer(BaseAnalyzer): def analyze_file(self, file_path, ast_tree): # Your analysis logic return issues ``` - + Yes! Refactron integrates well with: - **Black** - Code formatting @@ -218,7 +218,7 @@ description: 'Frequently asked questions' - **pre-commit** - Git hooks - **Prometheus** - Monitoring - + Check out our [GitHub repository](https://github.com/Refactron-ai/Refactron_lib) and see the CONTRIBUTING.md guide! diff --git a/documentation/docs/CLI_REFERENCE.md b/documentation/docs/CLI_REFERENCE.md index 56d58d5..2d07ac0 100644 --- a/documentation/docs/CLI_REFERENCE.md +++ b/documentation/docs/CLI_REFERENCE.md @@ -16,32 +16,32 @@ This document contains the reference for all Refactron CLI commands. COMMAND CENTER Select a command by name or number - - ID COMMAND DESCRIPTION - ──────────────────────────────────────────────────────────────────────────────────────────────────────── - 01 ANALYZE Analyze code for issues and technical debt. - 02 AUTH Manage authentication state. - 03 AUTOFIX Automatically fix code issues (Phase 3... - 04 DOCUMENT Generate Google-style docstrings for a... - 05 FEEDBACK Provide feedback on a refactoring operation. - 06 GENERATE-CICD Generate CI/CD integration templates. - 07 INIT Initialize Refactron configuration in the... - 08 LOGIN Log in to Refactron CLI via device-code flow. - 09 LOGOUT Log out of Refactron CLI. - 10 METRICS Display collected metrics from the current... - 11 PATTERNS Pattern learning and project-specific... - 12 RAG RAG (Retrieval-Augmented Generation)... - 13 REFACTOR Refactor code with intelligent... - 14 REPO Manage GitHub repository connections. - 15 REPORT Generate a detailed technical debt report. - 16 ROLLBACK Rollback refactoring changes to restore... - 17 SERVE-METRICS Start a Prometheus metrics HTTP server. - 18 SUGGEST Generate AI-powered refactoring suggestions. - 19 TELEMETRY Manage telemetry settings. - + + ID COMMAND DESCRIPTION + ──────────────────────────────────────────────────────────────────────────────────────────────────────── + 01 ANALYZE Analyze code for issues and technical debt. + 02 AUTH Manage authentication state. + 03 AUTOFIX Automatically fix code issues (Phase 3... + 04 DOCUMENT Generate Google-style docstrings for a... + 05 FEEDBACK Provide feedback on a refactoring operation. + 06 GENERATE-CICD Generate CI/CD integration templates. + 07 INIT Initialize Refactron configuration in the... + 08 LOGIN Log in to Refactron CLI via device-code flow. + 09 LOGOUT Log out of Refactron CLI. + 10 METRICS Display collected metrics from the current... + 11 PATTERNS Pattern learning and project-specific... + 12 RAG RAG (Retrieval-Augmented Generation)... + 13 REFACTOR Refactor code with intelligent... + 14 REPO Manage GitHub repository connections. + 15 REPORT Generate a detailed technical debt report. + 16 ROLLBACK Rollback refactoring changes to restore... + 17 SERVE-METRICS Start a Prometheus metrics HTTP server. + 18 SUGGEST Generate AI-powered refactoring suggestions. + 19 TELEMETRY Manage telemetry settings. + GLOBAL OPTIONS ---version Show the version and exit. +--version Show the version and exit. --help Show this message and exit. USAGE: refactron ... @@ -452,4 +452,3 @@ Options: --help Show this message and exit. ``` - diff --git a/documentation/docs/api/analyzers.md b/documentation/docs/api/analyzers.md index cf39613..beccbb0 100644 --- a/documentation/docs/api/analyzers.md +++ b/documentation/docs/api/analyzers.md @@ -485,4 +485,3 @@ Returns: astroid.nodes.Module ## Functions - diff --git a/documentation/docs/api/autofix.md b/documentation/docs/api/autofix.md index 0cd2213..1e626ab 100644 --- a/documentation/docs/api/autofix.md +++ b/documentation/docs/api/autofix.md @@ -799,4 +799,3 @@ FixRiskLevel(*values) Risk levels for automatic fixes. ## Functions - diff --git a/documentation/docs/api/cicd.md b/documentation/docs/api/cicd.md index c8ff4ee..5cf00e8 100644 --- a/documentation/docs/api/cicd.md +++ b/documentation/docs/api/cicd.md @@ -467,4 +467,3 @@ Returns: Dictionary with issue counts ## Functions - diff --git a/documentation/docs/api/core.md b/documentation/docs/api/core.md index c71b646..3e64e90 100644 --- a/documentation/docs/api/core.md +++ b/documentation/docs/api/core.md @@ -2878,4 +2878,3 @@ WorkspaceMapping.to_dict(self) -> 'Dict[str, Any]' Convert to dictionary for JSON serialization. ## Functions - diff --git a/documentation/docs/api/llm.md b/documentation/docs/api/llm.md index a57f9b6..0c594aa 100644 --- a/documentation/docs/api/llm.md +++ b/documentation/docs/api/llm.md @@ -287,4 +287,3 @@ Returns: Safety check result ## Functions - diff --git a/documentation/docs/api/patterns.md b/documentation/docs/api/patterns.md index 3e4bccf..bba6981 100644 --- a/documentation/docs/api/patterns.md +++ b/documentation/docs/api/patterns.md @@ -911,4 +911,3 @@ Heuristics: - Adjust pattern weights based on project acceptance. ## Functions - diff --git a/documentation/docs/api/rag.md b/documentation/docs/api/rag.md index 930892e..66f6929 100644 --- a/documentation/docs/api/rag.md +++ b/documentation/docs/api/rag.md @@ -348,4 +348,3 @@ RetrievedContext.__init__(self, content: 'str', file_path: 'str', chunk_type: 's Initialize self. See help(type(self)) for accurate signature. ## Functions - diff --git a/documentation/docs/api/refactorers.md b/documentation/docs/api/refactorers.md index 696ca5d..27c08ea 100644 --- a/documentation/docs/api/refactorers.md +++ b/documentation/docs/api/refactorers.md @@ -275,4 +275,3 @@ Returns: List of simplification operations ## Functions - diff --git a/flake8_errors.txt b/flake8_errors.txt deleted file mode 100644 index 1ba1842f6c2e248b510a4bcb0631ba43d8d2f3f5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7996 zcmd5>J5Iw;5ZoGxJGg`bh~w|0po4p$U?39U$VtQHfte>n14S}uA{TKsPGpbwGrK$a z{Fq{h$GDGG>|%;B-r@@O2z!9_``gRd#Cu#v6(x>+EO0F1HX2wZte05h8Uw5yt}^B` zyy_FIGyI;vxxuT8gySlnaqsE-{sXLSoX2UL{Bh@faa9to%8sj%aM4R%f3*Uxg!p-J zC1jM6UrRf#Uc%+h`x5mxPmh(c6uF`?$CAjFLNuA1-s~@N2L)Mgugfyp%=w2i|HAAu z#sAhG;8M8OKW{g{rR15v za}t>rO?OWxGG(gmQ8`|&ZN#4L?*c@o>?jEg?f03+XMSW&)~Tvo2SwcB6KA#pD)a@^ zU#ielkf|51@wtfC{J#A;yMe|`y?TIlJi>l}Mcw#6sxdLmQ$1_pn|W#n?BxpoC;Oa1 zWLh-cb7L$1Z<0_WUdEuNp>-xV|98lLCC~iboZE?3n{K^@$dn1l-HsfxhRe*a7CNiZ0_TNsv03OKvYXATM diff --git a/flake8_errors_temp.txt b/flake8_errors_temp.txt deleted file mode 100644 index 9181c1715322ef9eed73901b9b77f3d8a76c1e38..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7168 zcmdT|%TB{E5S%j-|G*J0(Aas{9Juiv6$<4cr7a4*z{dl#<;aDMghr@}Yda55r?a!` ze16Q>-~o3Salni{cDUkb$78}9-g$P$E9XX@yXR=l(U#v6KkFY?UgCv!U8BXowqV8f z47cdmYuKCc%x7=dJMek?<4mmi$lf`xk85st45(~JJaL7YN1*#ga)DEvaPBWqcU)gV zovo;QiR)_Sy63;Woa>5Y<$9p9m!mG!zf;$R(X<@3o9pK284B)VWjknDk9E0vXB-%0cnZ#|gkCYrw8I>}PriEQQd z!B&h*@BT88H^oofbyY;Awx4(VcQB{;x7$yugxkHp%*^wOPAdJ==_ldd+FLg7{xXv{ z%}=~}CvYo#$9r 79 characters) -refactron/analyzers/code_smell_analyzer.py:51:80: E501 line too long (83 > 79 characters) -refactron/analyzers/code_smell_analyzer.py:67:80: E501 line too long (91 > 79 characters) -refactron/analyzers/code_smell_analyzer.py:68:80: E501 line too long (92 > 79 characters) -refactron/analyzers/code_smell_analyzer.py:74:80: E501 line too long (85 > 79 characters) -refactron/analyzers/code_smell_analyzer.py:89:80: E501 line too long (92 > 79 characters) -refactron/analyzers/code_smell_analyzer.py:101:80: E501 line too long (98 > 79 characters) -refactron/analyzers/code_smell_analyzer.py:105:80: E501 line too long (100 > 79 characters) -refactron/analyzers/code_smell_analyzer.py:128:80: E501 line too long (81 > 79 characters) -refactron/analyzers/code_smell_analyzer.py:146:80: E501 line too long (92 > 79 characters) -refactron/analyzers/code_smell_analyzer.py:149:80: E501 line too long (94 > 79 characters) -refactron/analyzers/code_smell_analyzer.py:158:80: E501 line too long (87 > 79 characters) -refactron/analyzers/code_smell_analyzer.py:177:80: E501 line too long (85 > 79 characters) -refactron/analyzers/code_smell_analyzer.py:182:80: E501 line too long (91 > 79 characters) -refactron/analyzers/code_smell_analyzer.py:186:80: E501 line too long (92 > 79 characters) -refactron/analyzers/code_smell_analyzer.py:197:80: E501 line too long (86 > 79 characters) -refactron/analyzers/code_smell_analyzer.py:203:80: E501 line too long (87 > 79 characters) -refactron/analyzers/code_smell_analyzer.py:211:80: E501 line too long (82 > 79 characters) -refactron/analyzers/code_smell_analyzer.py:212:80: E501 line too long (92 > 79 characters) -refactron/analyzers/code_smell_analyzer.py:220:80: E501 line too long (91 > 79 characters) -refactron/analyzers/code_smell_analyzer.py:225:80: E501 line too long (87 > 79 characters) -refactron/analyzers/code_smell_analyzer.py:227:80: E501 line too long (80 > 79 characters) -refactron/analyzers/code_smell_analyzer.py:232:80: E501 line too long (91 > 79 characters) -refactron/analyzers/code_smell_analyzer.py:236:80: E501 line too long (86 > 79 characters) -refactron/analyzers/code_smell_analyzer.py:240:80: E501 line too long (95 > 79 characters) -refactron/analyzers/code_smell_analyzer.py:260:80: E501 line too long (85 > 79 characters) -refactron/analyzers/code_smell_analyzer.py:274:80: E501 line too long (82 > 79 characters) -refactron/analyzers/code_smell_analyzer.py:285:80: E501 line too long (90 > 79 characters) -refactron/analyzers/code_smell_analyzer.py:295:80: E501 line too long (81 > 79 characters) -refactron/analyzers/code_smell_analyzer.py:314:80: E501 line too long (93 > 79 characters) -refactron/analyzers/code_smell_analyzer.py:328:80: E501 line too long (94 > 79 characters) -refactron/analyzers/code_smell_analyzer.py:330:80: E501 line too long (81 > 79 characters) -refactron/analyzers/code_smell_analyzer.py:338:80: E501 line too long (80 > 79 characters) -refactron/analyzers/code_smell_analyzer.py:340:80: E501 line too long (87 > 79 characters) -refactron/analyzers/code_smell_analyzer.py:354:80: E501 line too long (95 > 79 characters) -refactron/analyzers/code_smell_analyzer.py:380:80: E501 line too long (87 > 79 characters) -refactron/analyzers/code_smell_analyzer.py:386:80: E501 line too long (93 > 79 characters) -refactron/analyzers/code_smell_analyzer.py:387:80: E501 line too long (84 > 79 characters) -refactron/analyzers/code_smell_analyzer.py:390:80: E501 line too long (93 > 79 characters) \ No newline at end of file From 95740f9ede34126a227d8137eb21c0466b1268b7 Mon Sep 17 00:00:00 2001 From: shrutu0929 Date: Wed, 11 Mar 2026 20:30:03 +0530 Subject: [PATCH 4/4] feat: implement automated auto-fix for high-confidence code smells --- refactron/analyzers/code_smell_analyzer.py | 18 +++++ refactron/autofix/engine.py | 13 +++- refactron/autofix/fixers.py | 41 ++++++++++ tests/test_ai_autofix.py | 88 ++++++++++++++++++++++ 4 files changed, 158 insertions(+), 2 deletions(-) create mode 100644 tests/test_ai_autofix.py diff --git a/refactron/analyzers/code_smell_analyzer.py b/refactron/analyzers/code_smell_analyzer.py index 2a88bfd..f52d90f 100644 --- a/refactron/analyzers/code_smell_analyzer.py +++ b/refactron/analyzers/code_smell_analyzer.py @@ -81,6 +81,24 @@ def analyze(self, file_path: Path, source_code: str) -> List[CodeIssue]: issue.metadata["validation_confidence"] = confidence if confidence >= 0.3: + # If confidence is very high, trigger auto-fix suggestion + if confidence > 0.8 and self.orchestrator: + try: + # Generate a suggestion using the full source code for context + suggestion_obj = self.orchestrator.generate_suggestion( + issue, source_code + ) + if suggestion_obj.proposed_code: + issue.suggestion = suggestion_obj.proposed_code + issue.metadata["ai_fix_available"] = True + issue.metadata["ai_explanation"] = suggestion_obj.explanation + issue.metadata["ai_reasoning"] = suggestion_obj.reasoning + except Exception: + # Failing to generate a suggestion shouldn't break triage + pass + else: + pass + final_issues.append(issue) issues = final_issues diff --git a/refactron/autofix/engine.py b/refactron/autofix/engine.py index 95a43a2..b29954e 100644 --- a/refactron/autofix/engine.py +++ b/refactron/autofix/engine.py @@ -34,6 +34,7 @@ def _register_fixers(self) -> Dict[str, "BaseFixer"]: from refactron.autofix.fixers import ( AddDocstringsFixer, AddMissingCommasFixer, + AISuggestionFixer, ConvertToFStringFixer, ExtractMagicNumbersFixer, FixIndentationFixer, @@ -64,6 +65,7 @@ def _register_fixers(self) -> Dict[str, "BaseFixer"]: FixIndentationFixer, AddMissingCommasFixer, RemovePrintStatementsFixer, + AISuggestionFixer, ]: fixer = fixer_class() fixers[fixer.name] = fixer @@ -80,7 +82,9 @@ def can_fix(self, issue: CodeIssue) -> bool: Returns: True if a fixer is available, False otherwise """ - return issue.rule_id in self.fixers if issue.rule_id else False + if issue.rule_id in self.fixers: + return True + return bool(issue.suggestion) def fix(self, issue: CodeIssue, code: str, preview: bool = True) -> FixResult: """ @@ -99,7 +103,12 @@ def fix(self, issue: CodeIssue, code: str, preview: bool = True) -> FixResult: success=False, reason=f"No fixer available for issue: {issue.rule_id or 'unknown'}" ) - fixer = self.fixers[issue.rule_id] + # Prefer rule-based fixer if available, otherwise use AI suggestion + if issue.rule_id and issue.rule_id in self.fixers: + fixer = self.fixers[issue.rule_id] + else: + # Must have issue.suggestion based on can_fix() check + fixer = self.fixers["ai_suggestion"] # Check risk level if fixer.risk_score > self.safety_level.value: diff --git a/refactron/autofix/fixers.py b/refactron/autofix/fixers.py index efde987..f3a6c0b 100644 --- a/refactron/autofix/fixers.py +++ b/refactron/autofix/fixers.py @@ -731,3 +731,44 @@ def apply(self, issue: CodeIssue, code: str) -> FixResult: def _create_diff(self, original: str, fixed: str) -> str: """Create a simple diff.""" return f"--- Original\n{original}\n\n+++ Fixed\n{fixed}" + + +class AISuggestionFixer(BaseFixer): + """Generic fixer that applies AI-generated suggestions.""" + + def __init__(self) -> None: + super().__init__(name="ai_suggestion", risk_score=0.5) + + def preview(self, issue: CodeIssue, code: str) -> FixResult: + """Preview the AI-generated suggestion.""" + if not issue.suggestion: + return FixResult( + success=False, + reason="No AI suggestion available for this issue", + risk_score=self.risk_score, + ) + + return FixResult( + success=True, + reason=issue.metadata.get("ai_explanation", "Applied AI-generated refactoring"), + diff=self._create_diff(code, issue.suggestion), + original=code, + fixed=issue.suggestion, + risk_score=self.risk_score, + ) + + def apply(self, issue: CodeIssue, code: str) -> FixResult: + """Apply the AI-generated suggestion.""" + return self.preview(issue, code) + + def _create_diff(self, original: str, fixed: str) -> str: + """Create a simple diff.""" + import difflib + + diff = difflib.unified_diff( + original.splitlines(keepends=True), + fixed.splitlines(keepends=True), + fromfile="Original", + tofile="AI Fixed", + ) + return "".join(diff) diff --git a/tests/test_ai_autofix.py b/tests/test_ai_autofix.py new file mode 100644 index 0000000..eb1fbf2 --- /dev/null +++ b/tests/test_ai_autofix.py @@ -0,0 +1,88 @@ +import unittest +from pathlib import Path +from unittest.mock import MagicMock, patch + +from refactron.analyzers.code_smell_analyzer import CodeSmellAnalyzer +from refactron.autofix.engine import AutoFixEngine +from refactron.core.config import RefactronConfig +from refactron.core.models import CodeIssue, IssueCategory, IssueLevel +from refactron.llm.models import RefactoringSuggestion, SuggestionStatus + + +class TestAIAutoFixIntegration(unittest.TestCase): + """Integration tests for AI-triggered auto-fixes.""" + + def setUp(self): + self.config = RefactronConfig() # Fresh config + self.config.enable_ai_triage = True + self.orchestrator = MagicMock() + self.analyzer = CodeSmellAnalyzer(self.config, self.orchestrator) + # Use a higher safety level to allow AI suggestions (0.5) + from refactron.autofix.models import FixRiskLevel + self.engine = AutoFixEngine(safety_level=FixRiskLevel.HIGH) + + def test_high_confidence_magic_number_triggers_suggestion(self): + """Test that a high-confidence magic number triggers an AI suggestion.""" + source_code = "def area(radius):\n return 3.14159 * radius * radius" + file_path = Path("test_file.py") + + # Mock AI triage to return high confidence (0.9) for the magic number (rule S004) + # and low confidence for other issues (like missing docstring S005) + self.orchestrator.evaluate_issues_batch.return_value = {"S004": 0.9, "S005": 0.5} + + # Mock AI suggestion generation + proposed_code = "PI = 3.14159\n\ndef area(radius):\n return PI * radius * radius" + suggestion = RefactoringSuggestion( + issue=MagicMock(spec=CodeIssue), + original_code=source_code, + context_files=[], + proposed_code=proposed_code, + explanation="Extracted magic number 3.14159 to constant PI", + reasoning="Magic numbers reduce maintainability. Using a named constant is better.", + model_name="mock-model", + confidence_score=0.9, + status=SuggestionStatus.PENDING + ) + self.orchestrator.generate_suggestion.return_value = suggestion + + # Run analysis + issues = self.analyzer.analyze(file_path, source_code) + + # Verify magic number issue was detected and has a suggestion + magic_number_issue = next((i for i in issues if i.rule_id == "S004"), None) + self.assertIsNotNone(magic_number_issue) + self.assertEqual(magic_number_issue.suggestion, proposed_code) + self.assertTrue(magic_number_issue.metadata.get("ai_fix_available")) + + # Verify engine can fix it using the AI suggestion + self.assertTrue(self.engine.can_fix(magic_number_issue)) + + # Apply the fix + result = self.engine.fix(magic_number_issue, source_code, preview=False) + + self.assertTrue(result.success, f"Fix failed: {result.reason}") + self.assertEqual(result.fixed, proposed_code) + self.assertIn("PI = 3.14159", result.fixed) + self.assertIn("PI * radius * radius", result.fixed) + + def test_low_confidence_does_not_trigger_suggestion(self): + """Test that a low-confidence issue does not trigger an AI suggestion.""" + source_code = "def area(radius):\n return 3.14159 * radius * radius" + file_path = Path("test_file.py") + + # Confidence (0.5) is above filtered threshold (0.3) but below auto-fix threshold (0.8) + # Also mock S005 to be low confidence + self.orchestrator.evaluate_issues_batch.return_value = {"S004": 0.5, "S005": 0.1} + + # Run analysis + issues = self.analyzer.analyze(file_path, source_code) + + # Verify magic number issue exists but NO suggestion was generated (stays default) + magic_number_issue = next((i for i in issues if i.rule_id == "S004"), None) + self.assertIsNotNone(magic_number_issue) + self.assertEqual(magic_number_issue.suggestion, "Consider extracting this number into a named constant.") + self.orchestrator.generate_suggestion.assert_not_called() + + +if __name__ == "__main__": + unittest.main()