annator-atom / backend /scripts /fix_indentation_ast.py
techprotrade's picture
Full stack ATOM backend + AIMONEYFLOW clients (port 7860) (part 5)
f84a02d verified
Raw
History Blame Contribute Delete
8.47 kB
#!/usr/bin/env python3
"""
AST-based auto-fix script for indentation errors in Atom backend.
This script uses the tokenize module to precisely fix indentation issues
where `with get_db_session() as db:` is followed by an incorrectly indented `try:` block.
"""
import io
import os
from pathlib import Path
import sys
import tokenize
from typing import List, Tuple
# Backend directory
BACKEND_DIR = Path("/Users/rushiparikh/projects/atom/backend")
def fix_file_tokens(filepath: Path) -> Tuple[bool, str]:
"""
Fix indentation issues using token-level processing.
Returns (success, message)
"""
try:
with open(filepath, 'rb') as f:
tokens = list(tokenize.tokenize(f.readline))
# Convert tokens back to source with fixes
result_tokens = []
i = 0
while i < len(tokens):
token = tokens[i]
# Look for pattern: WITH_KEYWORD ('with') followed by NAME ('get_db_session')
# then incorrectly indented try block
if token.type == tokenize.NAME and token.string == 'with':
# Check if this is our pattern
j = i
found_get_db_session = False
found_try_at_wrong_indent = False
# Look ahead for get_db_session
while j < len(tokens) and tokens[j].type != tokenize.NEWLINE:
if tokens[j].type == tokenize.NAME and tokens[j].string == 'get_db_session':
found_get_db_session = True
j += 1
if found_get_db_session:
# Now look for the try statement
# Skip to next line
while j < len(tokens) and tokens[j].type in (tokenize.NEWLINE, tokenize.NL, tokenize.COMMENT):
j += 1
# Check if next line is 'try' with insufficient indentation
if j < len(tokens) and tokens[j].type == tokenize.NAME and tokens[j].string == 'try':
# Check indentation - should be more than 'with' statement
with_indent = tokens[i].start[1]
try_indent = tokens[j].start[1]
if try_indent <= with_indent + 1:
# Found the issue! We need to increase try indentation
# Create a new token with proper indentation
new_start = (tokens[j].start[0], with_indent + 4)
if tokens[j].end[1] == tokens[j].start[1]: # Single token
new_end = (tokens[j].end[0], with_indent + 4 + len(tokens[j].string))
else:
new_end = tokens[j].end
new_end = (new_end[0], new_end[1] + (with_indent + 4 - try_indent))
fixed_token = tokenize.TokenInfo(
type=tokens[j].type,
string=tokens[j].string,
start=new_start,
end=new_end,
line=tokens[j].line
)
result_tokens.append(fixed_token)
i = j + 1
continue
result_tokens.append(token)
i += 1
# Reconstruct source from tokens
source_lines = []
current_line = 1
current_col = 0
for token in result_tokens:
if token.type == tokenize.ENCODING:
continue
# Handle line breaks
while current_line < token.start[0]:
source_lines.append('\n')
current_line += 1
current_col = 0
# Handle column spacing
while current_col < token.start[1]:
source_lines.append(' ')
current_col += 1
# Add the token string
if token.type != tokenize.NEWLINE and token.type != tokenize.NL:
source_lines.append(token.string)
current_col += len(token.string)
else:
source_lines.append('\n')
current_line += 1
current_col = 0
# Join and write back
fixed_content = ''.join(source_lines)
with open(filepath, 'w') as f:
f.write(fixed_content)
return True, "Fixed indentation"
except Exception as e:
return False, f"Error: {str(e)}"
def fix_simple_pattern(filepath: Path) -> bool:
"""
Simple line-based fix for the specific pattern.
"""
try:
with open(filepath, 'r') as f:
lines = f.readlines()
new_lines = []
i = 0
fixes = 0
while i < len(lines):
line = lines[i]
# Check for pattern: "with get_db_session() as db:"
if 'with get_db_session() as db:' in line:
# Get indentation
indent = len(line) - len(line.lstrip())
new_lines.append(line)
i += 1
# Check next line for "try:" at wrong indentation
if i < len(lines):
next_line = lines[i]
next_indent = len(next_line) - len(next_line.lstrip())
# If "try:" is at same or less indentation than "with"
if 'try:' in next_line and next_indent <= indent + 1:
# Fix indentation
fixed_try = ' ' * (indent + 4) + 'try:' + '\n'
new_lines.append(fixed_try)
fixes += 1
i += 1
# Continue with remaining lines
while i < len(lines):
new_lines.append(lines[i])
i += 1
break
new_lines.append(line)
i += 1
if fixes > 0:
with open(filepath, 'w') as f:
f.writelines(new_lines)
return True
return False
except Exception as e:
print(f" ✗ Error: {e}")
return False
def scan_and_fix():
"""Scan all Python files and fix indentation errors."""
print("=" * 70)
print("Auto-fixing indentation errors in Atom backend")
print("=" * 70)
print()
# List of known problematic files
problematic_files = [
"core/business_agents.py",
"core/chat_session_manager.py",
"core/change_order_agent.py",
"core/communication_service.py",
"core/workflow_engine.py",
"core/resource_manager.py",
"core/atom_meta_agent.py",
"core/lifecycle_comm_generator.py",
"core/background_agent_runner.py",
"core/admin_bootstrap.py",
"core/formula_memory.py",
"core/uptime_tracker.py",
"core/scheduler.py",
"core/llm/byok_handler.py",
"core/archive/database_v1.py",
"integrations/chat_orchestrator.py",
"integrations/universal_webhook_bridge.py",
"integrations/zoho_workdrive_service.py",
]
fixed_count = 0
for rel_path in problematic_files:
filepath = BACKEND_DIR / rel_path
if not filepath.exists():
continue
print(f"🔧 {rel_path}")
if fix_simple_pattern(filepath):
print(f" ✓ Fixed")
fixed_count += 1
else:
print(f" (no fix needed or failed)")
print()
print("=" * 70)
print(f"Fixed {fixed_count} files")
print("=" * 70)
print()
# Verify
import ast
print("Verifying fixes...")
remaining = 0
for rel_path in problematic_files:
filepath = BACKEND_DIR / rel_path
if not filepath.exists():
continue
try:
with open(filepath, 'r') as f:
content = f.read()
ast.parse(content)
except (SyntaxError, IndentationError) as e:
print(f" ✗ {rel_path}:{e.lineno} - {e.msg}")
remaining += 1
if remaining == 0:
print("✅ All files fixed successfully!")
return 0
else:
print(f"⚠️ {remaining} files still have errors")
return 1
if __name__ == '__main__':
sys.exit(scan_and_fix())