Skip to content

Commit 2ec387e

Browse files
committed
fix(reporting): resolve Matplotlib infinite layout loop causing test timeouts
- Removed ax.axis('tight') and plt.tight_layout() constraints around table axes, resolving an infinite dimension-calculation loop in strict test timeouts. - Explicitly marked TestMatplotlibDashboard and TestAllDashboards with @pytest.mark.timeout(30) to grant overhead for 300dpi PDF/PNG rendering.
1 parent b25c885 commit 2ec387e

File tree

2 files changed

+12
-17
lines changed

2 files changed

+12
-17
lines changed

infrastructure/reporting/dashboard_generator.py

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,13 @@
99
from __future__ import annotations
1010

1111
from pathlib import Path
12-
from typing import Any, Dict, List, Tuple
12+
from typing import Any, Dict, List
1313

1414
import matplotlib
1515

1616
matplotlib.use("Agg") # Use non-interactive backend
1717
import csv
1818

19-
import matplotlib.patches as mpatches
2019
import matplotlib.pyplot as plt
2120
import numpy as np
2221
from matplotlib.figure import Figure
@@ -444,7 +443,7 @@ def create_performance_timeline_chart(projects: List[ProjectMetrics]) -> Figure:
444443
test_times = [p.tests.execution_time for p in projects]
445444
coverages = [p.tests.coverage_percent for p in projects]
446445

447-
scatter = ax2.scatter(
446+
ax2.scatter(
448447
test_times, coverages, s=100, c=range(len(projects)), cmap="viridis", alpha=0.7
449448
)
450449
for i, name in enumerate(project_names):
@@ -529,7 +528,6 @@ def create_summary_table(
529528
Matplotlib Figure
530529
"""
531530
fig, ax = plt.subplots(figsize=(16, 8))
532-
ax.axis("tight")
533531
ax.axis("off")
534532

535533
# Import health score calculation
@@ -626,7 +624,6 @@ def create_summary_table(
626624
"Comprehensive Project Metrics Summary", fontweight="bold", fontsize=16, pad=30
627625
)
628626

629-
plt.tight_layout()
630627
return fig
631628

632629

@@ -689,7 +686,7 @@ def generate_matplotlib_dashboard(
689686
# Coverage with thresholds
690687
ax2 = axes[0, 1]
691688
coverage = [p.tests.coverage_percent for p in projects]
692-
bars = ax2.bar(x, coverage, color=COLORS["primary"], alpha=0.8)
689+
ax2.bar(x, coverage, color=COLORS["primary"], alpha=0.8)
693690
ax2.axhline(
694691
y=90,
695692
color=COLORS["success"],
@@ -716,7 +713,7 @@ def generate_matplotlib_dashboard(
716713
# Pipeline performance
717714
ax3 = axes[0, 2]
718715
durations = [p.pipeline.total_duration for p in projects]
719-
bars = ax3.bar(x, durations, color=COLORS["warning"], alpha=0.8)
716+
ax3.bar(x, durations, color=COLORS["warning"], alpha=0.8)
720717
ax3.set_xlabel("Project", fontweight="bold")
721718
ax3.set_ylabel("Duration (seconds)", fontweight="bold")
722719
ax3.set_title("Pipeline Execution Time", fontweight="bold")
@@ -739,7 +736,7 @@ def generate_matplotlib_dashboard(
739736
ax4 = axes[1, 0]
740737
word_counts = [p.manuscript.total_words for p in projects]
741738
equations = [p.manuscript.equations for p in projects]
742-
scatter = ax4.scatter(
739+
ax4.scatter(
743740
word_counts,
744741
equations,
745742
s=100,
@@ -816,7 +813,7 @@ def generate_matplotlib_dashboard(
816813
for count, duration in zip(pdf_counts, durations)
817814
]
818815

819-
bars = ax6.bar(x, efficiency, color=COLORS["success"], alpha=0.8)
816+
ax6.bar(x, efficiency, color=COLORS["success"], alpha=0.8)
820817
ax6.set_xlabel("Project", fontweight="bold")
821818
ax6.set_ylabel("PDFs per Second", fontweight="bold")
822819
ax6.set_title("Pipeline Efficiency", fontweight="bold")
@@ -843,7 +840,7 @@ def generate_matplotlib_dashboard(
843840
health_scores = [
844841
calculate_project_health_score(p)["percentage"] for p in projects
845842
]
846-
bars = ax7.bar(x, health_scores, color=COLORS["primary"], alpha=0.8)
843+
ax7.bar(x, health_scores, color=COLORS["primary"], alpha=0.8)
847844
ax7.axhline(
848845
y=85,
849846
color=COLORS["success"],
@@ -875,7 +872,7 @@ def generate_matplotlib_dashboard(
875872
ax8 = axes[2, 1]
876873
test_times = [p.tests.execution_time for p in projects]
877874
coverages = [p.tests.coverage_percent for p in projects]
878-
scatter = ax8.scatter(
875+
ax8.scatter(
879876
test_times,
880877
coverages,
881878
s=100,
@@ -898,7 +895,6 @@ def generate_matplotlib_dashboard(
898895

899896
# Enhanced summary table
900897
ax9 = axes[2, 2]
901-
ax9.axis("tight")
902898
ax9.axis("off")
903899

904900
headers = ["Project", "Health", "Words", "Tests", "Coverage"]
@@ -953,8 +949,6 @@ def generate_matplotlib_dashboard(
953949

954950
ax9.set_title("Executive Summary", fontweight="bold", fontsize=12, pad=20)
955951

956-
plt.tight_layout()
957-
958952
# Save as PNG (high resolution)
959953
organizer = OutputOrganizer()
960954
png_path = organizer.get_output_path("dashboard.png", output_dir, FileType.PNG)
@@ -2347,7 +2341,7 @@ def generate_codebase_complexity_chart(
23472341
methods = [p.codebase.methods for p in projects]
23482342
classes = [p.codebase.classes for p in projects]
23492343

2350-
scatter = ax2.scatter(
2344+
ax2.scatter(
23512345
methods,
23522346
classes,
23532347
s=100,

tests/infra_tests/reporting/test_dashboard_generator.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
Tests visual dashboard generation in multiple formats (PNG, PDF, HTML).
44
"""
55

6-
from pathlib import Path
76

87
import pytest
98

@@ -213,6 +212,7 @@ def test_create_summary_table(self, sample_projects, sample_aggregate):
213212
class TestMatplotlibDashboard:
214213
"""Test matplotlib dashboard generation."""
215214

215+
@pytest.mark.timeout(30)
216216
def test_generate_matplotlib_dashboard(self, sample_summary, tmp_path):
217217
"""Test generating matplotlib dashboard (PNG and PDF)."""
218218
saved_files = generate_matplotlib_dashboard(sample_summary, tmp_path)
@@ -267,7 +267,7 @@ class TestPlotlyDashboard:
267267
def test_generate_plotly_dashboard(self, sample_summary, tmp_path):
268268
"""Test generating plotly dashboard (interactive HTML)."""
269269
try:
270-
import plotly
270+
import plotly # noqa: F401
271271

272272
html_path = generate_plotly_dashboard(sample_summary, tmp_path)
273273

@@ -284,6 +284,7 @@ def test_generate_plotly_dashboard(self, sample_summary, tmp_path):
284284
class TestAllDashboards:
285285
"""Test generating all dashboard formats."""
286286

287+
@pytest.mark.timeout(30)
287288
def test_generate_all_dashboards(self, sample_summary, tmp_path):
288289
"""Test generating all dashboard formats."""
289290
all_files = generate_all_dashboards(sample_summary, tmp_path)

0 commit comments

Comments
 (0)