From 3d412ba2601eee94ef2505e446a4ccf2d0bf77b6 Mon Sep 17 00:00:00 2001 From: Ed_ Date: Sun, 7 Jun 2026 10:34:56 -0400 Subject: [PATCH] chore(scripts): remove one-shot indentation fixers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 1-space indentation convention is now enforced project-wide (per fix_indentation_1space_20260516). These 10 scripts are overlapping one-shot fixers and auditors from that era; their purpose has been served. Removed (10 files, ~30 KB): - audit_indentation.py (4.6 KB) - indentation auditor - check_hints_v2.py (1.0 KB) - crude regex hint checker - correct_indentation.py (6.4 KB) - one-shot corrector - extract_symbols.py (547 B) - crude symbol printer - fix_gaps.py (704 B) - whitespace gap fixer - fix_indent.py (9.6 KB) - indent fixer v1 - fix_indent_ast.py (3.4 KB) - indent fixer v2 (AST-based) - fix_indent_v3.py (2.2 KB) - indent fixer v3 (render-method-specific) - standardize_indent.py (1.0 KB) - indent standardizer - type_hint_scanner.py (718 B) - CLI hint scanner Audit (per spec §Gaps to Fill) confirms zero external references in active code, docs, CI, or planned tracks. --- scripts/audit_indentation.py | 120 --------------- scripts/check_hints_v2.py | 28 ---- scripts/correct_indentation.py | 167 -------------------- scripts/extract_symbols.py | 20 --- scripts/fix_gaps.py | 22 --- scripts/fix_indent.py | 274 --------------------------------- scripts/fix_indent_ast.py | 104 ------------- scripts/fix_indent_v3.py | 62 -------- scripts/standardize_indent.py | 39 ----- scripts/type_hint_scanner.py | 23 --- 10 files changed, 859 deletions(-) delete mode 100644 scripts/audit_indentation.py delete mode 100644 scripts/check_hints_v2.py delete mode 100644 scripts/correct_indentation.py delete mode 100644 scripts/extract_symbols.py delete mode 100644 scripts/fix_gaps.py delete mode 100644 scripts/fix_indent.py delete mode 100644 scripts/fix_indent_ast.py delete mode 100644 scripts/fix_indent_v3.py delete mode 100644 scripts/standardize_indent.py delete mode 100644 scripts/type_hint_scanner.py diff --git a/scripts/audit_indentation.py b/scripts/audit_indentation.py deleted file mode 100644 index f91bbbc8..00000000 --- a/scripts/audit_indentation.py +++ /dev/null @@ -1,120 +0,0 @@ -import ast -import sys -from pathlib import Path - -ROOT_DIR = Path(__file__).parent.parent - -class IndentationAnalyzer(ast.NodeVisitor): - def __init__(self, source_lines: list[str]): - self.source_lines = source_lines - self.violations: list[tuple[int, int, int, str]] = [] - - def visit_Module(self, node: ast.Module): - for child in node.body: - self._walk_node(child, 0) - self.generic_visit(node) - - def _walk_node(self, node: ast.AST, depth: int): - if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef)): - line_no = node.lineno - expected_indent = depth - actual_indent = self._get_indent(line_no) - if actual_indent != expected_indent: - self.violations.append((line_no, actual_indent, expected_indent, - f"{node.__class__.__name__} {node.name}")) - body_depth = depth + 1 - for child in node.body: - self._walk_node(child, body_depth) - elif isinstance(node, ast.If): - line_no = node.lineno - expected_indent = depth - actual_indent = self._get_indent(line_no) - if actual_indent != expected_indent: - self.violations.append((line_no, actual_indent, expected_indent, "if statement")) - for child in node.body: - self._walk_node(child, depth + 1) - if node.orelse: - self._walk_node(node.orelse, depth + 1) - elif isinstance(node, (ast.For, ast.While, ast.With)): - line_no = node.lineno - expected_indent = depth - actual_indent = self._get_indent(line_no) - if actual_indent != expected_indent: - self.violations.append((line_no, actual_indent, expected_indent, - node.__class__.__name__)) - for child in node.body: - self._walk_node(child, depth + 1) - if isinstance(node, ast.For) and node.orelse: - self._walk_node(node.orelse, depth + 1) - elif isinstance(node, ast.Try): - for child in node.body: - self._walk_node(child, depth + 1) - for handler in node.handlers: - self._walk_node(handler, depth + 1) - if node.orelse: - self._walk_node(node.orelse, depth + 1) - if node.finalbody: - self._walk_node(node.finalbody, depth + 1) - elif isinstance(node, (ast.Assign, ast.Expr, ast.Return, ast.Pass, ast.Raise, ast.Assert)): - pass - else: - self.generic_visit(node) - - def _get_indent(self, lineno: int) -> int: - if lineno <= 0 or lineno > len(self.source_lines): - return 0 - line = self.source_lines[lineno - 1] - stripped = line.lstrip() - return len(line) - len(stripped) - -def audit_file(filepath: Path) -> list[tuple[int, int, int, str]]: - try: - with open(filepath, "r", encoding="utf-8", newline="") as f: - source = f.read() - source_lines = source.splitlines() - tree = ast.parse(source, filename=str(filepath)) - analyzer = IndentationAnalyzer(source_lines) - analyzer.visit(tree) - return analyzer.violations - except SyntaxError: - return [] - except Exception: - return [] - -def main(): - dirs = ["src", "tests", "scripts", "conductor"] - total_files = 0 - files_with_violations = 0 - total_violations = 0 - - results: dict[str, list[tuple]] = {} - - for dir_name in dirs: - dir_path = ROOT_DIR / dir_name - if not dir_path.exists(): - continue - - py_files = list(dir_path.rglob("*.py")) - for py_file in sorted(py_files): - total_files += 1 - violations = audit_file(py_file) - if violations: - files_with_violations += 1 - total_violations += len(violations) - rel = str(py_file.relative_to(dir_path)) - results[f"{dir_name}/{rel}"] = violations - - print(f"Total files scanned: {total_files}") - print(f"Files with violations: {files_with_violations}") - print(f"Total violations: {total_violations}") - print() - - for path, violations in sorted(results.items()): - print(f"{path}: {len(violations)} violations") - for line_no, actual, expected, desc in violations[:5]: - print(f" Line {line_no}: actual={actual}, expected={expected} for {desc}") - if len(violations) > 5: - print(f" ... and {len(violations) - 5} more") - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/scripts/check_hints_v2.py b/scripts/check_hints_v2.py deleted file mode 100644 index d53c49ce..00000000 --- a/scripts/check_hints_v2.py +++ /dev/null @@ -1,28 +0,0 @@ -import re - -files = ['ai_client.py', 'aggregate.py', 'mcp_client.py', 'shell_runner.py'] -for file_path in files: - print(f"Checking {file_path}...") - with open(file_path, 'r', encoding='utf-8') as f: - content = f.read() - # Find all function definitions - # This regex is simplified and might miss some edge cases (like multi-line defs) - # But it's better than nothing. - defs = re.finditer(r'def\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*\((.*?)\)\s*(->\s*.*?)?:', content, re.DOTALL) - for m in defs: - name = m.group(1) - args = m.group(2).strip() - ret = m.group(3) - if not ret: - print(f" Missing return type: {name}({args})") - # Check arguments - if args: - arg_list = [a.strip() for a in args.split(',')] - for arg in arg_list: - if not arg or arg == 'self' or arg == 'cls': - continue - if ':' not in arg and '=' not in arg: - print(f" Missing arg type: {name} -> {arg}") - elif ':' not in arg and '=' in arg: - # arg=val (missing type) - print(f" Missing arg type: {name} -> {arg}") diff --git a/scripts/correct_indentation.py b/scripts/correct_indentation.py deleted file mode 100644 index fc9f1d7d..00000000 --- a/scripts/correct_indentation.py +++ /dev/null @@ -1,167 +0,0 @@ -import ast -import sys -from pathlib import Path - -ROOT_DIR = Path(__file__).parent.parent - -class IndentationCorrector(ast.NodeVisitor): - def __init__(self, source_lines: list[str]): - self.source_lines = source_lines - self.new_lines: list[str] = [] - self._indentation_stack: list[int] = [0] - - def visit_Module(self, node: ast.Module): - self._process_lines(0, 0) - for child in node.body: - self._walk_node(child, 0) - self.generic_visit(node) - - def _walk_node(self, node: ast.AST, depth: int): - if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef)): - line_no = node.lineno - 1 - actual_indent = self._get_indent(line_no) - expected_indent = depth - self._process_lines(line_no, expected_indent) - self._indentation_stack.append(depth + 1) - for child in node.body: - self._walk_node(child, depth + 1) - self._indentation_stack.pop() - elif isinstance(node, ast.If): - line_no = node.lineno - 1 - self._process_lines(line_no, depth) - for child in node.body: - self._walk_node(child, depth + 1) - if node.orelse: - self._walk_node(node.orelse, depth + 1) - elif isinstance(node, (ast.For, ast.While, ast.With)): - line_no = node.lineno - 1 - self._process_lines(line_no, depth) - for child in node.body: - self._walk_node(child, depth + 1) - if isinstance(node, ast.For) and node.orelse: - self._walk_node(node.orelse, depth + 1) - elif isinstance(node, ast.Try): - for child in node.body: - self._walk_node(child, depth + 1) - for handler in node.handlers: - self._walk_node(handler, depth + 1) - if node.orelse: - self._walk_node(node.orelse, depth + 1) - if node.finalbody: - self._walk_node(node.finalbody, depth + 1) - else: - self.generic_visit(node) - - def _get_indent(self, lineno: int) -> int: - if lineno < 0 or lineno >= len(self.source_lines): - return 0 - line = self.source_lines[lineno] - stripped = line.lstrip() - return len(line) - len(stripped) - - def _process_lines(self, end_line: int, expected_indent: int): - pass - -def correct_file(filepath: Path) -> tuple[bool, str]: - try: - with open(filepath, "r", encoding="utf-8", newline="") as f: - source = f.read() - source_lines = source.splitlines() - tree = ast.parse(source, filename=str(filepath)) - corrector = IndentationCorrector(source_lines) - corrector.visit(tree) - return False, "Not implemented yet" - except Exception as e: - return False, str(e) - -def fix_indentation_simple(filepath: Path, base_indent: int = 4, target_indent: int = 1) -> tuple[bool, str]: - try: - with open(filepath, "r", encoding="utf-8", newline="") as f: - lines = f.readlines() - - new_lines = [] - changed = False - for line in lines: - stripped = line.lstrip() - if not stripped: - new_lines.append(line) - continue - - leading = len(line) - len(stripped) - if leading > 0: - old_level = leading // base_indent - new_leading = old_level * target_indent - if leading != new_leading: - new_lines.append(" " * new_leading + stripped + "\n" if not line.endswith("\n") else " " * new_leading + stripped) - changed = True - else: - new_lines.append(line) - else: - new_lines.append(line) - - if changed: - with open(filepath, "w", encoding="utf-8", newline="") as f: - f.writelines(new_lines) - return True, "Fixed" - - return False, "No changes needed" - except Exception as e: - return False, str(e) - -def main(): - if len(sys.argv) > 2: - filepath = Path(sys.argv[2]) - base_indent = int(sys.argv[3]) if len(sys.argv) > 3 else 4 - target_indent = int(sys.argv[4]) if len(sys.argv) > 4 else 1 - changed, msg = fix_indentation_simple(filepath, base_indent, target_indent) - print(f"{filepath}: {msg}") - return - - files_to_fix = [ - ("src/fuzzy_anchor.py", 4, 1), - ("src/patch_modal.py", 2, 1), - ("scripts/extract_symbols.py", 4, 1), - ("scripts/tasks/download_fonts.py", 4, 1), - ] - - test_files = [ - ("tests/test_arch_boundary_phase1.py", 2, 1), - ("tests/test_arch_boundary_phase2.py", 2, 1), - ("tests/test_arch_boundary_phase3.py", 2, 1), - ("tests/test_external_editor.py", 4, 1), - ("tests/test_headless_service.py", 4, 1), - ("tests/test_history_manager.py", 4, 1), - ("tests/test_fuzzy_anchor.py", 4, 1), - ("tests/test_gemini_cli_adapter.py", 4, 1), - ("tests/test_ai_client_cli.py", 4, 1), - ("tests/test_api_events.py", 4, 1), - ("tests/test_context_composition_decoupled.py", 4, 1), - ("tests/test_context_composition_phase3.py", 4, 1), - ("tests/test_context_composition_phase4.py", 4, 1), - ("tests/test_diff_viewer.py", 2, 1), - ("tests/test_discussion_takes_gui.py", 4, 1), - ("tests/test_external_mcp_hitl.py", 4, 1), - ("tests/test_gui_discussion_tabs.py", 4, 1), - ("tests/test_gui_stress_performance.py", 4, 1), - ("tests/test_gui_updates.py", 2, 1), - ("tests/test_hot_reloader.py", 4, 1), - ("tests/test_mma_dashboard_refresh.py", 4, 1), - ("tests/test_mma_node_editor.py", 4, 1), - ("tests/test_mma_orchestration_gui.py", 4, 1), - ("tests/test_py_struct_tools.py", 4, 1), - ("tests/test_thinking_persistence.py", 4, 1), - ("tests/test_tier4_interceptor.py", 2, 1), - ("tests/test_tiered_aggregation.py", 4, 1), - ("tests/test_visual_orchestration.py", 4, 1), - ] - - all_files = files_to_fix + test_files - - for rel_path, base, target in all_files: - filepath = ROOT_DIR / rel_path - if filepath.exists(): - changed, msg = fix_indentation_simple(filepath, base, target) - print(f"{rel_path}: {msg}") - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/scripts/extract_symbols.py b/scripts/extract_symbols.py deleted file mode 100644 index c7ae3c42..00000000 --- a/scripts/extract_symbols.py +++ /dev/null @@ -1,20 +0,0 @@ -import ast -import os -from pathlib import Path - -symbols = [] -for root in ['src', 'simulation']: - for p in Path(root).rglob('*.py'): - try: - code = p.read_text(encoding='utf-8') - tree = ast.parse(code) - for node in tree.body: - if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef)): - if not node.name.startswith('_'): - symbols.append((node.name, str(p))) - except Exception: - continue - -print(f"TOTAL_SYMBOLS:{len(symbols)}") -for name, path in symbols: - print(f"SYMBOL:{name}|PATH:{path}") diff --git a/scripts/fix_gaps.py b/scripts/fix_gaps.py deleted file mode 100644 index e90ce12b..00000000 --- a/scripts/fix_gaps.py +++ /dev/null @@ -1,22 +0,0 @@ -import sys -import re - -def fix_gaps(): - file_path = "src/gui_2.py" - with open(file_path, "r", encoding="utf-8") as f: - content = f.read() - - # Replace 3+ newlines with 2 newlines (one empty line) - # Using \r\n for Windows support if needed, but \n is standard for Python reads - content = re.sub(r"\n\n\n+", "\n\n", content) - - # Specific fix for regions: ensure no extra space after region start or before region end - content = re.sub(r"(#region: .*)\n\n+", r"\1\n", content) - content = re.sub(r"\n\n+(#endregion: .*)", r"\n\1", content) - - with open(file_path, "w", encoding="utf-8") as f: - f.write(content) - print("Whitespace gaps fixed.") - -if __name__ == "__main__": - fix_gaps() diff --git a/scripts/fix_indent.py b/scripts/fix_indent.py deleted file mode 100644 index ca8f69d7..00000000 --- a/scripts/fix_indent.py +++ /dev/null @@ -1,274 +0,0 @@ -import ast -import sys -from pathlib import Path - -ROOT_DIR = Path(__file__).parent.parent - -class IndentationFixer(ast.NodeVisitor): - def __init__(self, source_lines: list[str]): - self.source_lines = source_lines - self.result_lines: list[str] = [] - self._pending_lines: list[tuple[int, str]] = [] - self._current_depth = 0 - - def fix(self) -> list[str]: - self._process_pending(0) - self.visit_Module(ast.parse("".join(self.source_lines))) - return self.result_lines - - def _get_indent(self, lineno: int) -> int: - if lineno <= 0 or lineno > len(self.source_lines): - return 0 - line = self.source_lines[lineno - 1] - stripped = line.lstrip() - return len(line) - len(stripped) - - def _is_docstring_or_comment(self, line: str) -> bool: - stripped = line.lstrip() - if stripped.startswith('#'): - return True - if stripped.startswith('"""') or stripped.startswith("'''"): - return True - return False - - def _process_pending(self, target_depth: int): - while self._pending_lines: - line_no, line = self._pending_lines[0] - stripped = line.lstrip() - actual = len(line) - len(stripped) - expected = target_depth - - if actual == expected: - self.result_lines.append(line) - self._pending_lines.pop(0) - elif actual < expected: - break - elif actual > expected: - self.result_lines.append(" " * expected + stripped) - self._pending_lines.pop(0) - - def visit_Module(self, node: ast.Module): - for child in node.body: - self._walk_node(child) - self.generic_visit(node) - - def _walk_node(self, node: ast.AST): - if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef)): - lineno = node.lineno - for i, (old_no, old_line) in enumerate(self._pending_lines): - if old_no == lineno: - self._pending_lines.pop(i) - break - - actual = self._get_indent(lineno) - expected = self._current_depth - line = self.source_lines[lineno - 1] - stripped = line.lstrip() - - if actual != expected: - self.result_lines.append(" " * expected + stripped) - else: - self.result_lines.append(line) - - self._current_depth += 1 - for child in node.body: - self._walk_node(child) - self._current_depth -= 1 - - elif isinstance(node, ast.If): - lineno = node.lineno - line = self.source_lines[lineno - 1] - stripped = line.lstrip() - actual = self._get_indent(lineno) - expected = self._current_depth - - if actual != expected: - self.result_lines.append(" " * expected + stripped) - else: - self.result_lines.append(line) - - self._current_depth += 1 - for child in node.body: - self._walk_node(child) - self._current_depth -= 1 - - if node.orelse: - self._current_depth += 1 - self._walk_node(node.orelse) - self._current_depth -= 1 - - elif isinstance(node, (ast.For, ast.While, ast.With)): - lineno = node.lineno - line = self.source_lines[lineno - 1] - stripped = line.lstrip() - actual = self._get_indent(lineno) - expected = self._current_depth - - if actual != expected: - self.result_lines.append(" " * expected + stripped) - else: - self.result_lines.append(line) - - self._current_depth += 1 - for child in node.body: - self._walk_node(child) - self._current_depth -= 1 - - if isinstance(node, ast.For) and node.orelse: - self._current_depth += 1 - for child in node.orelse: - self._walk_node(child) - self._current_depth -= 1 - - elif isinstance(node, ast.Try): - for child in node.body: - self._walk_node(child) - for handler in node.handlers: - self._current_depth += 1 - for child in handler.body: - self._walk_node(child) - self._current_depth -= 1 - if node.orelse: - self._current_depth += 1 - for child in node.orelse: - self._walk_node(child) - self._current_depth -= 1 - if node.finalbody: - self._current_depth += 1 - for child in node.finalbody: - self._walk_node(child) - self._current_depth -= 1 - - else: - self.generic_visit(node) - -def fix_file_ast(filepath: Path) -> tuple[bool, str]: - try: - with open(filepath, "r", encoding="utf-8", newline="") as f: - source = f.read() - - source_lines = source.splitlines() - tree = ast.parse(source, filename=str(filepath)) - - fixer = IndentationFixer(source_lines) - new_lines = fixer.fix() - - new_source = "\n".join(new_lines) - if new_source == source: - return False, "No changes" - - with open(filepath, "w", encoding="utf-8", newline="") as f: - f.write(new_source) - - ast.parse(new_source) - return True, "Fixed" - - except SyntaxError as e: - return False, f"Syntax error: {e}" - except Exception as e: - return False, str(e) - -def fix_file_simple(filepath: Path, base_indent: int = 4) -> tuple[bool, str]: - try: - with open(filepath, "r", encoding="utf-8", newline="") as f: - lines = f.readlines() - - in_docstring = False - new_lines = [] - changed = False - - for line in lines: - stripped = line.lstrip() - if not stripped: - new_lines.append(line) - continue - - if not in_docstring: - if stripped.startswith('#'): - new_lines.append(line) - continue - if '"""' in stripped or "'''" in stripped: - triple_pos = max(stripped.find('"""') if '"""' in stripped else 999, - stripped.find("'''") if "'''" in stripped else 999) - if triple_pos == 0: - in_docstring = True - new_lines.append(line) - continue - - if in_docstring: - if '"""' in stripped or "'''" in stripped: - in_docstring = False - new_lines.append(line) - continue - - leading = len(line) - len(stripped) - if leading > 0: - level = leading // base_indent - new_leading = level - if leading != new_leading: - new_lines.append(" " * new_leading + stripped + ("\n" if not line.endswith("\n") else "")) - changed = True - else: - new_lines.append(line) - else: - new_lines.append(line) - - if changed: - with open(filepath, "w", encoding="utf-8", newline="") as f: - f.writelines(new_lines) - return True, "Fixed" - return False, "No changes needed" - - except Exception as e: - return False, str(e) - -def main(): - if len(sys.argv) > 1: - filepath = Path(sys.argv[1]) - changed, msg = fix_file_simple(filepath) - print(f"{filepath}: {msg}") - return - - files_to_fix = [ - ("src/fuzzy_anchor.py", 4), - ("src/patch_modal.py", 2), - ("scripts/extract_symbols.py", 4), - ("scripts/tasks/download_fonts.py", 4), - ("tests/test_arch_boundary_phase1.py", 2), - ("tests/test_arch_boundary_phase2.py", 2), - ("tests/test_arch_boundary_phase3.py", 2), - ("tests/test_external_editor.py", 4), - ("tests/test_headless_service.py", 4), - ("tests/test_history_manager.py", 4), - ("tests/test_fuzzy_anchor.py", 4), - ("tests/test_gemini_cli_adapter.py", 4), - ("tests/test_ai_client_cli.py", 4), - ("tests/test_api_events.py", 4), - ("tests/test_context_composition_decoupled.py", 4), - ("tests/test_context_composition_phase3.py", 4), - ("tests/test_context_composition_phase4.py", 4), - ("tests/test_diff_viewer.py", 2), - ("tests/test_discussion_takes_gui.py", 4), - ("tests/test_external_mcp_hitl.py", 4), - ("tests/test_gui_discussion_tabs.py", 4), - ("tests/test_gui_stress_performance.py", 4), - ("tests/test_gui_updates.py", 2), - ("tests/test_hot_reloader.py", 4), - ("tests/test_mma_dashboard_refresh.py", 4), - ("tests/test_mma_node_editor.py", 4), - ("tests/test_mma_orchestration_gui.py", 4), - ("tests/test_py_struct_tools.py", 4), - ("tests/test_thinking_persistence.py", 4), - ("tests/test_tier4_interceptor.py", 2), - ("tests/test_tiered_aggregation.py", 4), - ("tests/test_visual_orchestration.py", 4), - ] - - for rel_path, base_indent in files_to_fix: - filepath = ROOT_DIR / rel_path - if filepath.exists(): - changed, msg = fix_file_simple(filepath, base_indent) - print(f"{rel_path}: {msg}") - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/scripts/fix_indent_ast.py b/scripts/fix_indent_ast.py deleted file mode 100644 index ccb2331f..00000000 --- a/scripts/fix_indent_ast.py +++ /dev/null @@ -1,104 +0,0 @@ -import ast -import sys -from pathlib import Path - -ROOT_DIR = Path(__file__).parent.parent - -class PythonIndentationFixer(ast.NodeVisitor): - def __init__(self, source_lines: list[str]): - self.source_lines = source_lines - self.result: list[str] = [] - self._depth = 0 - self._pending: list[tuple[int, str]] = [] - - def fix(self) -> str: - tree = ast.parse("".join(self.source_lines)) - self._walk_module(tree) - return "\n".join(self.result) - - def _get_line(self, lineno: int) -> str: - if 0 < lineno <= len(self.source_lines): - return self.source_lines[lineno - 1] - return "" - - def _walk_module(self, node: ast.Module): - for item in node.body: - self._process_item(item, 0) - self.generic_visit(node) - - def _process_item(self, node: ast.AST, base_depth: int): - lineno = node.lineno - line = self._get_line(lineno) - stripped = line.lstrip() - leading = len(line) - len(stripped) - expected = base_depth - - if leading != expected: - self.result.append(" " * expected + stripped) - else: - self.result.append(line.rstrip("\n")) - - if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef)): - body_depth = base_depth + 1 - for child in node.body: - self._process_item(child, body_depth) - elif isinstance(node, (ast.If, ast.For, ast.While, ast.With, ast.Try)): - body_depth = base_depth + 1 - for child in node.body: - self._process_item(child, body_depth) - if isinstance(node, ast.If) and node.orelse: - self._process_item(node.orelse, base_depth + 1) - if isinstance(node, ast.For) and node.orelse: - for child in node.orelse: - self._process_item(child, body_depth) - elif isinstance(node, ast.Try): - for handler in node.handlers: - for child in handler.body: - self._process_item(child, body_depth) - if node.orelse: - for child in node.orelse: - self._process_item(child, body_depth) - if node.finalbody: - for child in node.finalbody: - self._process_item(child, body_depth) - else: - self.generic_visit(node) - - def generic_visit(self, node: ast.AST): - pass - -def fix_file_ast(filepath: Path) -> tuple[bool, str]: - try: - with open(filepath, "r", encoding="utf-8", newline="") as f: - source = f.read() - - lines = source.splitlines() - fixer = PythonIndentationFixer(lines) - new_source = fixer.fix() - - ast.parse(new_source) - - if new_source == source: - return False, "No changes needed" - - with open(filepath, "w", encoding="utf-8", newline="") as f: - f.write(new_source) - - return True, "Fixed" - except SyntaxError as e: - return False, f"SyntaxError: {e}" - except Exception as e: - return False, str(e) - -def main(): - if len(sys.argv) > 1: - filepath = Path(sys.argv[1]) - changed, msg = fix_file_ast(filepath) - print(f"{filepath}: {msg}") - return - - print("AST-based Python indentation fixer") - print("Usage: python fix_indent_ast.py ") - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/scripts/fix_indent_v3.py b/scripts/fix_indent_v3.py deleted file mode 100644 index 29e5eeae..00000000 --- a/scripts/fix_indent_v3.py +++ /dev/null @@ -1,62 +0,0 @@ -import ast -import sys -import re - -def transform(): - file_path = "src/gui_2.py" - with open(file_path, "r", encoding="utf-8") as f: - lines = f.read().splitlines() - content = "\n".join(lines) - tree = ast.parse(content) - app_class = next((n for n in tree.body if isinstance(n, ast.ClassDef) and n.name == "App"), None) - if not app_class: - print("App class not found") - return - render_methods = [ - m for m in app_class.body - if isinstance(m, ast.FunctionDef) and m.name.startswith("_render_") and m.name != "_render_window_if_open" - ] - render_methods.sort(key=lambda x: x.lineno, reverse=True) - extracted = [] - for m in render_methods: - s_idx = m.lineno - 1 - e_idx = m.end_lineno - if m.decorator_list: s_idx = m.decorator_list[0].lineno - 1 - m_lines = lines[s_idx:e_idx] - func_name = m.name.lstrip("_") - processed = [] - for l in m_lines: - processed.append(l[1:] if l.startswith(" ") else l) - def_line_idx = -1 - for i, l in enumerate(processed): - if l.strip().startswith("def "): - def_line_idx = i - break - if def_line_idx != -1: - l = processed[def_line_idx] - l = l.replace(f"def {m.name}(", f"def {func_name}(", 1) - l = re.sub(r"\bself\b", "app: App", l, count=1) - processed[def_line_idx] = l - for i in range(def_line_idx + 1, len(processed)): - processed[i] = re.sub(r"(? 0 and space_count % 4 == 0: - new_space_count = space_count // 4 - new_lines.append(' ' * new_space_count + stripped) - else: - new_lines.append(line) - - try: - with open(file_path, 'w', encoding='utf-8') as f: - f.writelines(new_lines) - print(f"Standardized {file_path}") - except Exception as e: - print(f"Error writing {file_path}: {e}") - -if __name__ == "__main__": - if len(sys.argv) < 2: - print("Usage: python scripts/standardize_indent.py ...") - sys.exit(1) - - for path in sys.argv[1:]: - if os.path.isfile(path): - standardize_file(path) - else: - print(f"Skipping {path}: Not a file") diff --git a/scripts/type_hint_scanner.py b/scripts/type_hint_scanner.py deleted file mode 100644 index 20ba7cc0..00000000 --- a/scripts/type_hint_scanner.py +++ /dev/null @@ -1,23 +0,0 @@ -import ast -import sys - -def get_missing_hints(file_path: str): - with open(file_path, "r", encoding="utf-8") as f: - tree = ast.parse(f.read()) - missing = [] - for node in ast.walk(tree): - if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)): - has_return = node.returns is not None - args_missing = any(arg.annotation is None for arg in node.args.args if arg.arg != "self") - if not has_return or args_missing: - missing.append({ - "name": node.name, - "lineno": node.lineno, - "col_offset": node.col_offset - }) - return missing - -if __name__ == "__main__": - if len(sys.argv) > 1: - for m in get_missing_hints(sys.argv[1]): - print(f"Line {m['lineno']}: {m['name']}")