Files

99 lines
3.0 KiB
Python

#!/usr/bin/env python3
"""
Quick Python file analyzer - extracts basic metrics from Python source files.
Line count, function count, class count, imports, docstrings.
"""
import ast
import sys
from pathlib import Path
def analyze_python_file(filepath: str) -> dict:
"""Analyze a Python file and return metrics."""
path = Path(filepath)
if not path.exists():
return {"error": f"File not found: {filepath}"}
content = path.read_text()
lines = content.splitlines()
result = {
"file": filepath,
"total_lines": len(lines),
"code_lines": 0,
"comment_lines": 0,
"blank_lines": 0,
"functions": 0,
"classes": 0,
"imports": 0,
"docstrings": 0,
}
# Count line types
for line in lines:
stripped = line.strip()
if not stripped:
result["blank_lines"] += 1
elif stripped.startswith("#"):
result["comment_lines"] += 1
else:
result["code_lines"] += 1
# Parse AST for structural metrics
try:
tree = ast.parse(content)
for node in ast.walk(tree):
if isinstance(node, ast.FunctionDef):
result["functions"] += 1
elif isinstance(node, ast.ClassDef):
result["classes"] += 1
elif isinstance(node, (ast.Import, ast.ImportFrom)):
result["imports"] += 1
# Count module docstrings
if (tree.body and isinstance(tree.body[0], ast.Expr) and
isinstance(tree.body[0].value, ast.Constant) and
isinstance(tree.body[0].value.value, str)):
result["docstrings"] += 1
except SyntaxError as e:
result["ast_error"] = str(e)
return result
def main():
if len(sys.argv) < 2:
print("Usage: py_analyzer.py <file1.py> [file2.py] ...")
sys.exit(1)
files = sys.argv[1:]
for filepath in files:
result = analyze_python_file(filepath)
print(f"\n{'='*60}")
print(f"Analysis: {filepath}")
print('='*60)
if "error" in result:
print(f" ERROR: {result['error']}")
continue
print(f" Total lines: {result['total_lines']}")
print(f" Code lines: {result['code_lines']}")
print(f" Comment lines: {result['comment_lines']}")
print(f" Blank lines: {result['blank_lines']}")
print(f" Functions: {result['functions']}")
print(f" Classes: {result['classes']}")
print(f" Imports: {result['imports']}")
print(f" Docstrings: {result['docstrings']}")
# Quick quality check
cyclomatic = result['code_lines'] - (result['functions'] + result['classes']) + 1
complexity = "HIGH" if cyclomatic > 50 else "MODERATE" if cyclomatic > 20 else "LOW"
print(f" Cyclomatic est: {cyclomatic} ({complexity} complexity)")
if __name__ == "__main__":
main()