chore(scripts): remove one-shot indentation fixers
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.
This commit is contained in:
@@ -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()
|
||||
@@ -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}")
|
||||
@@ -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()
|
||||
@@ -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}")
|
||||
@@ -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()
|
||||
@@ -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()
|
||||
@@ -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 <filepath>")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -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"(?<![a-zA-Z0-9_])self\.", "app.", processed[i])
|
||||
processed[i] = re.sub(r"(?<![a-zA-Z0-9_])self(?![a-zA-Z0-9_:])", "app", processed[i])
|
||||
extracted.append("\n".join(processed))
|
||||
arg_names = [a.arg for a in m.args.args if a.arg != "self"]
|
||||
kw_names = [a.arg for a in m.args.kwonlyargs]
|
||||
call_args = ["self"] + arg_names + [f"{k}={k}" for k in kw_names]
|
||||
orig_def_line = m_lines[0]
|
||||
if m.decorator_list:
|
||||
for l in m_lines:
|
||||
if l.strip().startswith("def "):
|
||||
orig_def_line = l
|
||||
break
|
||||
wrapper = [orig_def_line, f" {func_name}({', '.join(call_args)})"]
|
||||
lines[s_idx:e_idx] = wrapper
|
||||
extracted.reverse()
|
||||
final = "\n".join(lines) + "\n\n" + "\n\n".join(extracted) + "\n"
|
||||
with open(file_path, "w", encoding="utf-8") as f:
|
||||
f.write(final)
|
||||
print(f"Successfully transformed {file_path}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
transform()
|
||||
@@ -1,39 +0,0 @@
|
||||
import sys
|
||||
import os
|
||||
|
||||
def standardize_file(file_path):
|
||||
try:
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
lines = f.readlines()
|
||||
except Exception as e:
|
||||
print(f"Error reading {file_path}: {e}")
|
||||
return
|
||||
|
||||
new_lines = []
|
||||
for line in lines:
|
||||
stripped = line.lstrip(' ')
|
||||
space_count = len(line) - len(stripped)
|
||||
|
||||
if space_count > 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 <file_path1> <file_path2> ...")
|
||||
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")
|
||||
@@ -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']}")
|
||||
Reference in New Issue
Block a user