import ast import os ignore_keywords = ["temp", "cache", "archive", "__pycache__", "test"] def analyze_python_package(package_path): ''' Analyzes a Python package directory and extracts structural metrics ''' if not os.path.exists(package_path): print(f"Error: The path '{package_path}' does not exist.") return None # Summary metrics initialization metrics = { "total_modules": 0, "total_lines": 0, "total_classes": 0, "total_functions": 0, "total_func_calls": 0, "total_if_blocks": 0, "total_for_loops": 0, "total_while_loops": 0, } # Walk through the directory structure for root, dirs, files in os.walk(package_path): dirs[:] = [ d for d in dirs if not d.startswith(".") and not any(keyword in d for keyword in ignore_keywords) ] for file in files: # Only process Python source files if file.endswith(".py"): metrics["total_modules"] += 1 file_path = os.path.join(root, file) try: with open(file_path, "r", encoding="utf-8") as f: content = f.read() # Count physical lines of code metrics["total_lines"] += len(content.splitlines()) # Parse code into Abstract Syntax Tree (AST) tree = ast.parse(content, filename=file_path) # Traverse AST nodes to count definitions and calls for node in ast.walk(tree): if isinstance(node, ast.ClassDef): metrics["total_classes"] += 1 elif isinstance( node, (ast.FunctionDef, ast.AsyncFunctionDef) ): metrics["total_functions"] += 1 elif isinstance(node, ast.Call): metrics["total_func_calls"] += 1 elif isinstance(node, ast.If): metrics["total_if_blocks"] += 1 elif isinstance(node, (ast.For, ast.AsyncFor)): metrics["total_for_loops"] += 1 elif isinstance(node, ast.While): metrics["total_while_loops"] += 1 except (SyntaxError, UnicodeDecodeError) as e: print(f"Skipping file {file_path} due to error: {e}") return metrics # --- Execution Example --- if __name__ == "__main__": # Replace with the path to the package directory you want to scan TARGET_PACKAGE = "./Calculix2VTK" result = analyze_python_package(TARGET_PACKAGE) if result: print(f"\n=== Summary Report for Package: {TARGET_PACKAGE} ===\n") print(f" * Number of modules (.py files): {result['total_modules']}\n") print(f" * Total lines of code: {result['total_lines']}\n") print(f" * Number of classes: {result['total_classes']}\n") print(f" * Number of functions/methods: {result['total_functions']}\n") print(f" * Number of function calls: {result['total_func_calls']}\n") print(f" * Number of IF blocks: {result['total_if_blocks']}\n") print(f" * Number of FOR loops: {result['total_for_loops']}\n") print(f" * Number of WHILE loops: {result['total_while_loops']}\n")