#!/usr/bin/env python3 """ Pre-commit hook to warn about usage of deprecated get_setting_from_db_main_thread wrapper. This function is deprecated because it's redundant - use the SettingsManager directly with proper session context management instead. NOTE: This hook currently only warns about usage to allow gradual migration. """ import sys from pathlib import Path from typing import List, Tuple def check_file(filepath: Path) -> List[Tuple[int, str]]: """Check a single Python file for deprecated wrapper usage. Args: filepath: Path to the Python file to check Returns: List of (line_number, error_message) tuples """ errors = [] try: content = filepath.read_text(encoding="utf-8") # Short-circuit: no mention at all → nothing to check. if "get_setting_from_db_main_thread" not in content: return errors # Per-line scan. Previously this routine also walked the AST and # appended a second error per call site, producing duplicate # diagnostics on every hit. The AST walk (ast.Name match) is # strictly weaker than this line scan — any bare identifier # reference also appears on the line that contains it — so it # is safe to remove. for i, line in enumerate(content.split("\n"), 1): # Skip comment and docstring lines — they can legitimately # mention the deprecated name without invoking it. stripped = line.strip() if stripped.startswith(("#", '"""', "'''")): continue if "get_setting_from_db_main_thread" not in line: continue if "from" in line and "import" in line: errors.append( ( i, "Importing deprecated get_setting_from_db_main_thread - use SettingsManager with proper session context", ) ) else: errors.append( ( i, "Using deprecated get_setting_from_db_main_thread - use SettingsManager with get_user_db_session context manager", ) ) except Exception as e: print(f"Error checking {filepath}: {e}", file=sys.stderr) return errors def main(): """Main entry point for the pre-commit hook.""" files_to_check = sys.argv[1:] if not files_to_check: print("No files to check") return 0 all_errors = [] for filepath_str in files_to_check: filepath = Path(filepath_str) # Skip non-Python files if filepath.suffix != ".py": continue # Skip the file that defines the function (db_utils.py), this hook itself, # and test files that test the deprecated function if filepath.name in [ "db_utils.py", "check-deprecated-settings-wrapper.py", "test_db_utils.py", "test_db_utils_deep_coverage.py", ]: continue errors = check_file(filepath) if errors: all_errors.append((filepath, errors)) if all_errors: print( "\n⚠️ Warning: Found usage of deprecated get_setting_from_db_main_thread wrapper:\n" ) print( "This function is deprecated and will be removed in a future version." ) print( "For Flask routes/views, use SettingsManager with proper session context:\n" ) print( " from local_deep_research.database.session_context import get_user_db_session" ) print( " from local_deep_research.utilities.db_utils import get_settings_manager" ) print("") print(" with get_user_db_session(username) as db_session:") print( " settings_manager = get_settings_manager(db_session, username)" ) print(" value = settings_manager.get_setting(key, default)") print("\nFor background threads, use settings_snapshot pattern.") print("\nFiles with deprecated usage:") for filepath, errors in all_errors: print(f"\n {filepath}:") for line_num, error_msg in errors: print(f" Line {line_num}: {error_msg}") # Return 1 to fail and enforce migration return 1 return 0 if __name__ == "__main__": sys.exit(main())