import os import re import ast from collections import Counter def audit_file(path): with open(path, 'r', encoding='utf-8') as f: lines = f.readlines() content = "".join(lines) findings = [] # 1. Detect multiple identical import lines imports = [line.strip() for line in lines if line.strip().startswith('import ')] import_counts = Counter(imports) for imp, count in import_counts.items(): if count > 1: findings.append(f"Duplicate import: '{imp}' ({count} times)") # 2. Detect multiple 'from X import Y' lines for the same module X and symbol Y from_imports = [line.strip() for line in lines if line.strip().startswith('from ')] from_counts = Counter(from_imports) for imp, count in from_counts.items(): if count > 1: findings.append(f"Duplicate from-import: '{imp}' ({count} times)") # 3. Detect mixed indentation (look for 4-space blocks) four_spaces = " " for i, line in enumerate(lines): if line.startswith(four_spaces): findings.append(f"Mixed indentation: 4-space block found at line {i+1}") break # Only report once per file # 4. List all functions and classes that appear more than once try: tree = ast.parse(content) defs = [] for node in ast.walk(tree): if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef)): defs.append(node.name) def_counts = Counter(defs) for name, count in def_counts.items(): if count > 1: findings.append(f"Duplicate definition: '{name}' ({count} times)") except Exception as e: findings.append(f"AST Parse Error: {e}") return findings def main(): src_dir = 'src' if not os.path.exists(src_dir): print(f"Directory {src_dir} not found.") return for root, dirs, files in os.walk(src_dir): for file in files: if file.endswith('.py'): path = os.path.join(root, file) findings = audit_file(path) if findings: print(f"--- {path} ---") for f in findings: print(f" {f}") print() if __name__ == "__main__": main()