spark: py_stats.py - quick Python file analyzer with AST parsing
This commit is contained in:
1 parent
1a8e9968e7
commit
484e6cd34f
2 files changed
+114
No files matched your search
@@ -0,0 +1,7 @@
|
||||
Python File Statistics for: /root/.hermes/profiles/spark/
|
||||
==================================================
|
||||
Total .py files: 50
|
||||
Total lines: 11590
|
||||
Total imports: 434
|
||||
Total functions: 415
|
||||
Total classes: 10
|
||||
@@ -0,0 +1,107 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Quick Python file statistics reporter.
|
||||
Usage: python py_stats.py <directory> [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 <directory> [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()
|
||||
Reference in new issue
Block a user