Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
172 changes: 19 additions & 153 deletions analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,18 @@
get_health_rating,
)

from reporting.terminal import (
generate_codebase_summary,
display_line_metrics,
display_structure_metrics,
display_control_flow_metrics,
display_operation_metrics,
display_function_analysis_metrics,
display_quality_issues_metrics,
display_health_score_metrics,
generate_report,
)


def generate_json_report(results, output_file="codebase_report.json"):
if not results:
Expand Down Expand Up @@ -118,15 +130,15 @@ def main():


def analyze_codebase(
py_files,
generate_json=False,
py_files,
generate_json=False,
output_file="codebase_report.json",
):
results = []
for file in py_files:
metrics = analyze_file(file)

# skipping files with syntax errors
# skipping files with syntax errors
if metrics is None:
continue

Expand All @@ -144,7 +156,7 @@ def analyze_codebase(


def analyze_file(file):
# encoding with utf-8 as it causes "unicode error" on windows
# encoding with utf-8 as it causes "unicode error" on windows
with file.open(encoding="utf-8") as f:
source = f.read()
lines = source.splitlines()
Expand All @@ -163,7 +175,7 @@ def analyze_file(file):
line_data["fixmes"],
)

# ** is used to unpack dictionaries
# ** is used to unpack dictionaries
return {
"file": file,
"total_lines": len(lines),
Expand All @@ -178,157 +190,11 @@ def parse_python_file(source, file):
try:
return ast.parse(source)

# handling the syntax errors
# handling the syntax errors
except SyntaxError as err:
print(f"Syntax error in {file}: {err}")
return None


def generate_codebase_summary(results):
if not results:
print("No valid Python files found.")
return

total_files = len(results)
total_lines = sum(result["total_lines"] for result in results)
total_functions = sum(result["functions"] for result in results)
total_classes = sum(result["classes"] for result in results)
total_todos = sum(result["todos"] for result in results)
total_fixmes = sum(result["fixmes"] for result in results)

average_health_score = (
sum(result["health_score"] for result in results) / total_files
)

print("=" * 50)
print("CODEBASE SUMMARY")
print("=" * 50)

print(f"\nPython files: {total_files}")
print(f"Total lines: {total_lines}")
print(f"Total functions: {total_functions}")
print(f"Total classes: {total_classes}")
print(f"Total TODOs: {total_todos}")
print(f"Total FIXMEs: {total_fixmes}")

print("\nHealth")
print("-" * 20)
print(f"Average score: {average_health_score:.1f}/100")
print(f"Rating: {get_health_rating(average_health_score)}")

print("\nFiles Needing Attention")
print("-" * 20)

problem_files = []

for result in results:
if result["issues"]:
problem_files.append(result)

sorted_results = sorted(problem_files, key=lambda result: result["health_score"])

for result in sorted_results[:3]:
print(f"{result['file'].name}: " f"{result['health_score']}/100")

for issue in result["issues"]:
print(f" - {issue}")
print()


def display_line_metrics(metrics):
print("\nLines")
print("-" * 20)
print(f"Total lines: {metrics['total_lines']}")
print(f"Code lines: {metrics['code_lines']}")
print(f"Blank lines: {metrics['blank_lines']}")
print(f"Comment lines: {metrics['comment_lines']}")


def display_structure_metrics(metrics):
print("\nStructure")
print("-" * 20)
print(f"Functions: {metrics['functions']}")
print(f"Classes: {metrics['classes']}")
print(f"Imports: {metrics['imports']}")
print(f"From imports: {metrics['import_from']}")


def display_control_flow_metrics(metrics):
print("\nControl Flow")
print("-" * 20)
print(f"If statements: {metrics['if_statements']}")
print(f"For loops: {metrics['for_loops']}")
print(f"While loops: {metrics['while_loops']}")
print(f"Try blocks: {metrics['try_blocks']}")


def display_operation_metrics(metrics):
print("\nOperations")
print("-" * 20)
print(f"Function calls: {metrics['function_calls']}")
print(f"Return statements: {metrics['return_statements']}")
print(f"Exceptions raised: {metrics['exceptions_raised']}")
print(f"Assertions: {metrics['assertions']}")


def display_function_analysis_metrics(metrics):
print("\nFunction Analysis")
print("-" * 20)

for function in metrics["function_details"]:
print(f"{function['name']}")
print(f" Start Line: {function['start_line']}")
print(f" Lines: {function['lines']}")
print(f" Arguments: {function['arguments']}")
print(f" Complexity: {function['complexity']}")
print()


def display_quality_issues_metrics(metrics):
print("\nQuality Issues")
print("-" * 20)

print(f"TODOs: {metrics['todos']}")
print(f"FIXMEs: {metrics['fixmes']}")
print()

if metrics["issues"]:
for issue in metrics["issues"]:
print(f"WARNING: {issue}")

if metrics["todos"] > 0:
print(f"WARNING: {metrics['todos']} TODO(s) found")

if metrics["fixmes"] > 0:
print(f"WARNING: {metrics['fixmes']} FIXME(s) found")

if not metrics["issues"] and metrics["todos"] == 0 and metrics["fixmes"] == 0:
print("No issues detected")


def display_health_score_metrics(metrics):
print("\nHealth Score")
print("-" * 20)

print(f"Score: {metrics['health_score']}/100")
print(f"Rating: {get_health_rating(metrics['health_score'])}")


def generate_report(metrics):
print("=" * 50)
print("CODEBASE HEALTH REPORT")
print("=" * 50)

print(f"\nFile: {metrics['file'].name}")

display_line_metrics(metrics)
display_structure_metrics(metrics)
display_control_flow_metrics(metrics)
display_operation_metrics(metrics)
display_function_analysis_metrics(metrics)
display_quality_issues_metrics(metrics)
display_health_score_metrics(metrics)


if __name__ == "__main__":
main()
main()
Empty file added reporting/__init__.py
Empty file.
147 changes: 147 additions & 0 deletions reporting/terminal.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
from analysis.quality import get_health_rating


def generate_codebase_summary(results):
if not results:
print("No valid Python files found.")
return

total_files = len(results)
total_lines = sum(result["total_lines"] for result in results)
total_functions = sum(result["functions"] for result in results)
total_classes = sum(result["classes"] for result in results)
total_todos = sum(result["todos"] for result in results)
total_fixmes = sum(result["fixmes"] for result in results)

average_health_score = (
sum(result["health_score"] for result in results) / total_files
)

print("=" * 50)
print("CODEBASE SUMMARY")
print("=" * 50)

print(f"\nPython files: {total_files}")
print(f"Total lines: {total_lines}")
print(f"Total functions: {total_functions}")
print(f"Total classes: {total_classes}")
print(f"Total TODOs: {total_todos}")
print(f"Total FIXMEs: {total_fixmes}")

print("\nHealth")
print("-" * 20)
print(f"Average score: {average_health_score:.1f}/100")
print(f"Rating: {get_health_rating(average_health_score)}")

print("\nFiles Needing Attention")
print("-" * 20)

problem_files = []

for result in results:
if result["issues"]:
problem_files.append(result)

sorted_results = sorted(problem_files, key=lambda result: result["health_score"])

for result in sorted_results[:3]:
print(f"{result['file'].name}: " f"{result['health_score']}/100")

for issue in result["issues"]:
print(f" - {issue}")
print()


def display_line_metrics(metrics):
print("\nLines")
print("-" * 20)
print(f"Total lines: {metrics['total_lines']}")
print(f"Code lines: {metrics['code_lines']}")
print(f"Blank lines: {metrics['blank_lines']}")
print(f"Comment lines: {metrics['comment_lines']}")


def display_structure_metrics(metrics):
print("\nStructure")
print("-" * 20)
print(f"Functions: {metrics['functions']}")
print(f"Classes: {metrics['classes']}")
print(f"Imports: {metrics['imports']}")
print(f"From imports: {metrics['import_from']}")


def display_control_flow_metrics(metrics):
print("\nControl Flow")
print("-" * 20)
print(f"If statements: {metrics['if_statements']}")
print(f"For loops: {metrics['for_loops']}")
print(f"While loops: {metrics['while_loops']}")
print(f"Try blocks: {metrics['try_blocks']}")


def display_operation_metrics(metrics):
print("\nOperations")
print("-" * 20)
print(f"Function calls: {metrics['function_calls']}")
print(f"Return statements: {metrics['return_statements']}")
print(f"Exceptions raised: {metrics['exceptions_raised']}")
print(f"Assertions: {metrics['assertions']}")


def display_function_analysis_metrics(metrics):
print("\nFunction Analysis")
print("-" * 20)

for function in metrics["function_details"]:
print(f"{function['name']}")
print(f" Start Line: {function['start_line']}")
print(f" Lines: {function['lines']}")
print(f" Arguments: {function['arguments']}")
print(f" Complexity: {function['complexity']}")
print()


def display_quality_issues_metrics(metrics):
print("\nQuality Issues")
print("-" * 20)

print(f"TODOs: {metrics['todos']}")
print(f"FIXMEs: {metrics['fixmes']}")
print()

if metrics["issues"]:
for issue in metrics["issues"]:
print(f"WARNING: {issue}")

if metrics["todos"] > 0:
print(f"WARNING: {metrics['todos']} TODO(s) found")

if metrics["fixmes"] > 0:
print(f"WARNING: {metrics['fixmes']} FIXME(s) found")

if not metrics["issues"] and metrics["todos"] == 0 and metrics["fixmes"] == 0:
print("No issues detected")


def display_health_score_metrics(metrics):
print("\nHealth Score")
print("-" * 20)

print(f"Score: {metrics['health_score']}/100")
print(f"Rating: {get_health_rating(metrics['health_score'])}")


def generate_report(metrics):
print("=" * 50)
print("CODEBASE HEALTH REPORT")
print("=" * 50)

print(f"\nFile: {metrics['file'].name}")

display_line_metrics(metrics)
display_structure_metrics(metrics)
display_control_flow_metrics(metrics)
display_operation_metrics(metrics)
display_function_analysis_metrics(metrics)
display_quality_issues_metrics(metrics)
display_health_score_metrics(metrics)
Loading