#!/usr/bin/env python3 """Quick Python file statistics reporter. Usage: python py_stats.py [output_file] Reports: number of .py files, total lines, imports, functions, classes. """ import os import sys import ast from pathlib import Path def analyze_py_file(filepath): """Analyze a single Python file.""" result = { 'lines': 0, 'imports': 0, 'functions': 0, 'classes': 0 } try: with open(filepath, 'r', encoding='utf-8') as f: content = f.read() result['lines'] = len(content.splitlines()) tree = ast.parse(content) for node in ast.walk(tree): if isinstance(node, (ast.Import, ast.ImportFrom)): result['imports'] += 1 elif isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)): result['functions'] += 1 elif isinstance(node, ast.ClassDef): result['classes'] += 1 except Exception as e: result['error'] = str(e) return result def scan_directory(directory): """Scan directory for Python files and report statistics.""" stats = { 'files': 0, 'total_lines': 0, 'total_imports': 0, 'total_functions': 0, 'total_classes': 0, 'file_details': [] } for root, dirs, files in os.walk(directory): # Skip hidden directories and common non-source folders dirs[:] = [d for d in dirs if not d.startswith('.') and d not in ('__pycache__', 'venv', '.venv', 'node_modules')] for file in files: if file.endswith('.py'): filepath = os.path.join(root, file) relpath = os.path.relpath(filepath, directory) fstats = analyze_py_file(filepath) fstats['path'] = relpath stats['file_details'].append(fstats) stats['files'] += 1 stats['total_lines'] += fstats['lines'] stats['total_imports'] += fstats['imports'] stats['total_functions'] += fstats['functions'] stats['total_classes'] += fstats['classes'] return stats def main(): if len(sys.argv) < 2: print("Usage: python py_stats.py [output_file]") sys.exit(1) directory = sys.argv[1] output_file = sys.argv[2] if len(sys.argv) > 2 else None if not os.path.isdir(directory): print(f"Error: {directory} is not a directory") sys.exit(1) stats = scan_directory(directory) output = [] output.append(f"Python File Statistics for: {directory}") output.append("=" * 50) output.append(f"Total .py files: {stats['files']}") output.append(f"Total lines: {stats['total_lines']}") output.append(f"Total imports: {stats['total_imports']}") output.append(f"Total functions: {stats['total_functions']}") output.append(f"Total classes: {stats['total_classes']}") output.append("") if stats['files'] <= 20: # Show details for small projects output.append("File details:") output.append("-" * 50) for f in stats['file_details']: output.append(f" {f['path']}: {f['lines']} lines, {f['imports']} imports, {f['functions']} funcs, {f['classes']} classes") result = "\n".join(output) print(result) if output_file: with open(output_file, 'w') as f: f.write(result) print(f"\nResults written to: {output_file}") if __name__ == '__main__': main()