Atlas / scripts /utilities /check_imports.py
findEthics
Complete codebase cleanup and project structure validation
f0b765c
Raw
History Blame Contribute Delete
5.38 kB
#!/usr/bin/env python3
"""
Check import organization in Python files and identify files that need manual standardization.
"""
import ast
import os
from pathlib import Path
from typing import List, Tuple
def analyze_imports(file_path: str) -> Tuple[bool, List[str]]:
"""Analyze imports in a file and return (is_standardized, issues)"""
try:
with open(file_path, 'r', encoding='utf-8') as f:
content = f.read()
tree = ast.parse(content)
except (SyntaxError, UnicodeDecodeError) as e:
return False, [f"Parse error: {e}"]
issues = []
stdlib_imports = []
third_party_imports = []
local_imports = []
# Standard library modules (common ones)
stdlib_modules = {
'os', 'sys', 'json', 'logging', 'datetime', 'time', 'asyncio',
'typing', 'functools', 'collections', 'itertools', 'pathlib',
'unittest', 'argparse', 'subprocess', 're', 'uuid', 'ssl',
'threading', 'ast', 'shutil', 'tempfile'
}
for node in ast.walk(tree):
if isinstance(node, ast.Import):
for alias in node.names:
module_root = alias.name.split('.')[0]
if module_root in stdlib_modules:
stdlib_imports.append((node.lineno, f"import {alias.name}"))
elif module_root in ['analytics', 'tests', 'scripts']:
local_imports.append((node.lineno, f"import {alias.name}"))
else:
third_party_imports.append((node.lineno, f"import {alias.name}"))
elif isinstance(node, ast.ImportFrom):
if node.module:
module_root = node.module.split('.')[0]
names = [alias.name for alias in node.names]
import_str = f"from {node.module} import {', '.join(names)}"
if module_root in stdlib_modules:
stdlib_imports.append((node.lineno, import_str))
elif module_root in ['analytics', 'tests', 'scripts'] or node.module.startswith('.'):
local_imports.append((node.lineno, import_str))
else:
third_party_imports.append((node.lineno, import_str))
# Check if imports are properly ordered
all_imports = stdlib_imports + third_party_imports + local_imports
all_imports.sort(key=lambda x: x[0]) # Sort by line number
# Check ordering
current_section = 'stdlib'
for line_no, import_str in all_imports:
if import_str.split()[1].split('.')[0] in stdlib_modules:
if current_section not in ['stdlib']:
issues.append(f"Line {line_no}: stdlib import after non-stdlib imports")
current_section = 'stdlib'
elif any(import_str.startswith(f"from {mod}") or import_str.startswith(f"import {mod}")
for mod in ['analytics', 'tests', 'scripts']) or '.database' in import_str:
if current_section not in ['stdlib', 'third_party', 'local']:
issues.append(f"Line {line_no}: local import in wrong position")
current_section = 'local'
else:
if current_section not in ['stdlib', 'third_party']:
issues.append(f"Line {line_no}: third-party import after local imports")
current_section = 'third_party'
return len(issues) == 0, issues
def main():
"""Check import organization across the codebase"""
project_root = Path(__file__).parent.parent.parent
files_to_check = []
# Collect Python files
for pattern in ['*.py', 'analytics/*.py', 'tests/*.py', 'scripts/**/*.py', 'archive/*.py']:
files_to_check.extend(project_root.glob(pattern))
# Also check subdirectories
for subdir in ['tests/unit', 'tests/integration', 'tests/utilities', 'tests/performance']:
subdir_path = project_root / subdir
if subdir_path.exists():
files_to_check.extend(subdir_path.glob('*.py'))
print("🔍 Checking import organization...")
needs_attention = []
well_organized = []
for file_path in files_to_check:
if 'backup' in str(file_path):
continue # Skip backup files
is_standardized, issues = analyze_imports(str(file_path))
if is_standardized:
well_organized.append(str(file_path))
else:
needs_attention.append((str(file_path), issues))
print(f"\n✅ Well-organized files: {len(well_organized)}")
for file_path in well_organized:
rel_path = os.path.relpath(file_path, project_root)
print(f" ✓ {rel_path}")
print(f"\n⚠️ Files needing attention: {len(needs_attention)}")
for file_path, issues in needs_attention:
rel_path = os.path.relpath(file_path, project_root)
print(f" 📝 {rel_path}")
for issue in issues[:3]: # Show first 3 issues
print(f" - {issue}")
if len(issues) > 3:
print(f" - ... and {len(issues) - 3} more issues")
print(f"\n📊 Summary:")
print(f" Total files checked: {len(well_organized) + len(needs_attention)}")
print(f" Well-organized: {len(well_organized)}")
print(f" Need attention: {len(needs_attention)}")
if __name__ == "__main__":
main()