pdf_export.py builds a PDF report (summary stats, AGP chart, hypo/hyper event summaries) via fpdf2 + matplotlib rather than plotly's kaleido, to avoid bundling a Chromium build into the image just for this. The Export page lets the user pick which sections to include and a date range, then download the result to send to the hospital team. This completes all ten functional requirements in docs/requirements-reporting.md. Co-Authored-By: Claude Sonnet 5 <[email protected]>
42 lines
1.3 KiB
Python
42 lines
1.3 KiB
Python
from datetime import date
|
|
|
|
import pandas as pd
|
|
|
|
from pdf_export import SECTION_AGP, SECTION_EVENTS, SECTION_SUMMARY, build_report_pdf
|
|
|
|
|
|
def _sample_glucose():
|
|
timestamps = pd.date_range("2026-01-01", periods=48, freq="30min")
|
|
return pd.DataFrame({"timestamp": timestamps, "mmol": [6.0 + (i % 5) for i in range(48)]})
|
|
|
|
|
|
def test_build_report_pdf_produces_valid_pdf_bytes():
|
|
glucose = _sample_glucose()
|
|
events_summary = {
|
|
"Hypo Level 1": {"count": 2, "avg_duration_minutes": 20.0, "events_per_week": 1.0},
|
|
}
|
|
pdf_bytes = build_report_pdf(
|
|
[SECTION_SUMMARY, SECTION_AGP, SECTION_EVENTS],
|
|
glucose,
|
|
events_summary,
|
|
date(2026, 1, 1),
|
|
date(2026, 1, 2),
|
|
)
|
|
assert isinstance(pdf_bytes, bytes)
|
|
assert pdf_bytes.startswith(b"%PDF")
|
|
assert len(pdf_bytes) > 500
|
|
|
|
|
|
def test_build_report_pdf_handles_empty_glucose():
|
|
empty = pd.DataFrame(columns=["timestamp", "mmol"])
|
|
pdf_bytes = build_report_pdf(
|
|
[SECTION_SUMMARY, SECTION_AGP], empty, {}, date(2026, 1, 1), date(2026, 1, 2)
|
|
)
|
|
assert pdf_bytes.startswith(b"%PDF")
|
|
|
|
|
|
def test_build_report_pdf_handles_no_sections_selected():
|
|
glucose = _sample_glucose()
|
|
pdf_bytes = build_report_pdf([], glucose, {}, date(2026, 1, 1), date(2026, 1, 2))
|
|
assert pdf_bytes.startswith(b"%PDF")
|