#!/usr/bin/env python3 """ Database Session Auto-Fixer Automatically fixes common database session management patterns. """ import os import re from typing import List, Tuple def fix_session_management(content: str) -> Tuple[str, int]: """ Fix database session management patterns in a file. Returns (fixed_content, number_of_changes) """ changes = 0 lines = content.split('\n') fixed_lines = [] i = 0 while i < len(lines): line = lines[i] original_line = line # Pattern 1: db = SessionLocal() followed by try/finally if re.search(r'(\w+)\s*=\s*SessionLocal\(\)', line): indent = len(line) - len(line.lstrip()) var_name = re.search(r'(\w+)\s*=\s*SessionLocal\(\)', line).group(1) # Check if next lines have try/finally pattern if i + 1 < len(lines) and 'try:' in lines[i + 1]: # Skip the db = SessionLocal() line i += 1 # Move to try: fixed_lines.append(lines[i]) # Keep try: # Replace with with get_db_session() pattern new_indent = ' ' * indent fixed_lines.append(f'{new_indent}from core.database import get_db_session') fixed_lines.append(f'{new_indent}') fixed_lines.append(f'{new_indent}with get_db_session() as {var_name}:') changes += 1 i += 1 continue # Pattern 2: with SessionLocal() as db: if re.search(r'with\s+SessionLocal\(\)\s+as\s+(\w+):', line): var_name = re.search(r'with\s+SessionLocal\(\)\s+as\s+(\w+):', line).group(1) line = re.sub(r'with\s+SessionLocal\(\)\s+as\s+(\w+):', f'with get_db_session() as {var_name}:', line) changes += 1 # Pattern 3: Remove manual db.close() in with blocks if re.search(rf'{var_name}\.close\(\)' if 'var_name' in locals() else r'\w+\.close\(\)', line): # Only remove if it's in a finally block if 'finally:' in lines[i-1] if i > 0 else False: line = '#' + line + ' # Removed: context manager handles cleanup' changes += 1 # Pattern 4: Remove manual db.commit() at end of with block # (context manager auto-commits on success) # We'll leave this for manual review as it's context-dependent fixed_lines.append(line) i += 1 return '\n'.join(fixed_lines), changes def add_get_db_import(content: str) -> str: """Add get_db_session import if not present.""" if 'from core.database import get_db_session' in content: return content # Find existing database import if 'from core.database import' in content: # Add to existing import content = re.sub( r'from core\.database import ([^\n]+)', r'from core.database import \1, get_db_session', content ) else: # Add new import after imports lines = content.split('\n') import_idx = 0 for i, line in enumerate(lines): if line.startswith('from ') or line.startswith('import '): import_idx = i + 1 elif import_idx > 0 and not line.startswith('from ') and not line.startswith('import '): break lines.insert(import_idx, 'from core.database import get_db_session') content = '\n'.join(lines) return content def fix_file(file_path: str, dry_run: bool = True) -> Tuple[bool, int]: """ Fix a single file. Returns (success, number_of_changes) """ try: with open(file_path, 'r', encoding='utf-8') as f: original_content = f.read() fixed_content, changes = fix_session_management(original_content) if changes > 0: # Add import if needed if 'get_db_session' in fixed_content: fixed_content = add_get_db_import(fixed_content) if not dry_run: with open(file_path, 'w', encoding='utf-8') as f: f.write(fixed_content) return True, changes return False, 0 except Exception as e: print(f" ❌ Error: {e}") return False, 0 def main(): import argparse parser = argparse.ArgumentParser(description='Auto-fix database session management') parser.add_argument('--file', help='File to fix') parser.add_argument('--list', help='File with list of files to fix') parser.add_argument('--dry-run', action='store_true', default=True, help='Show changes without applying (default: True)') parser.add_argument('--apply', action='store_true', help='Actually apply changes (disables dry-run)') args = parser.parse_args() if args.apply: args.dry_run = False files_to_fix = [] if args.file: files_to_fix.append(args.file) elif args.list: with open(args.list, 'r') as f: files_to_fix = [line.strip() for line in f if line.strip()] else: print("Usage: python fix_db_sessions.py --file or --list ") return mode = "DRY RUN" if args.dry_run else "APPLY" print(f"Mode: {mode}") print(f"Files to fix: {len(files_to_fix)}") print() total_changes = 0 success_count = 0 for file_path in files_to_fix: if not os.path.exists(file_path): print(f"⚠️ File not found: {file_path}") continue print(f"Processing: {file_path}") success, changes = fix_file(file_path, args.dry_run) if success: print(f" ✅ {changes} changes") total_changes += changes success_count += 1 else: print(f" ℹ️ No changes needed") print() print(f"Summary: {success_count} files, {total_changes} changes") if args.dry_run: print("⚠️ DRY RUN MODE - No files were modified") print("Use --apply to actually apply changes") if __name__ == '__main__': main()