14 KiB
14 KiB
Sprint 18: PDF Report Generation
| Document ID | DEV-002 |
|---|---|
| Version | 1.0.0 |
| Status | Draft |
| Author | Kai Chappell |
| Created | 2026-01-29 |
| Last Updated | 2026-01-29 |
Purpose
This document defines Sprint 18 of py-dvt-ate development: automated PDF report generation from test results. Reports are designed to be professional and well-presented for recruiters/clients evaluating the simulation platform.
For project context, see:
01_requirements.md- What the system must do02_technical_specification.md- How to implement03_architecture_decisions.md- Why decisions were made04_development_plan.md- Phase 1 MVP sprints (1-17)
Feature Overview
Add automated PDF report generation with:
- Professional, well-presented layout suitable for external stakeholders
- Clean UX with easy download from CLI and dashboard
- Test metadata, results table with pass/fail status, and measurement charts
- Configurable company branding
Design Principles
Following existing project patterns:
- Small, Focused Commits - Each task = 1 commit, ~50-150 lines changed
- Stubs First - Define interfaces/types before implementation
- Test Alongside - Write tests immediately after implementation
- UK English - characterisation, behaviour, colour
- Minimal Context - Each task completable with knowledge of 1-3 files
Task Breakdown
Task 18.1: Add reporting dependencies to pyproject.toml
- Add
matplotlib>=3.8to reports optional dependency group - Verify jinja2 and weasyprint already present
- Files:
pyproject.toml - Commit: "Add matplotlib to reports dependencies"
Task 18.2: Create report data models
- Create
src/py_dvt_ate/reporting/models.py - Define
ReportConfigdataclass:company_name: str- Company name for headerlogo_path: Path | None- Optional logo image pathinclude_charts: bool- Whether to include chartschart_dpi: int- Chart resolution
- Define
ReportDatadataclass:run: TestRun- Test run metadataresults: list[TestResult]- Scalar results with limitsmeasurements: pd.DataFrame | None- Time-series datacharts: dict[str, str]- Chart name to base64 PNG
- Files:
src/py_dvt_ate/reporting/models.py - Commit: "Add report data models"
Task 18.3: Create reporting exceptions
- Create
src/py_dvt_ate/reporting/exceptions.py - Define exception hierarchy:
ReportingError- Base exceptionReportGenerationError- General generation failureTemplateRenderError- HTML rendering failurePDFConversionError- HTML to PDF conversion failureChartGenerationError- Chart generation failure
- Files:
src/py_dvt_ate/reporting/exceptions.py - Commit: "Add reporting exception classes"
Task 18.4: Create CSS stylesheet for reports
- Create
src/py_dvt_ate/reporting/templates/styles.css - Professional styling:
- A4 page setup with margins
- Header with company branding
- Footer with page numbers
- Data tables with borders
- Status badges (pass=green, fail=red, info=blue)
- Summary cards with colour coding
- Chart containers
- Print-optimised with page breaks
- Files:
src/py_dvt_ate/reporting/templates/styles.css - Commit: "Add professional CSS stylesheet for reports"
Task 18.5: Create base HTML template
- Create
src/py_dvt_ate/reporting/templates/base.html - Jinja2 base template with:
<head>with CSS include- Header block with company name, logo, report metadata
- Content block (for child templates)
- Footer block with confidentiality notice, page numbers
- WeasyPrint
@pagerules for PDF pagination - Files:
src/py_dvt_ate/reporting/templates/base.html - Commit: "Add base HTML report template"
Task 18.6: Create test report template
- Create
src/py_dvt_ate/reporting/templates/test_report.html - Extends
base.htmlwith sections:- Test Overview: name, description, status, timestamps, duration, operator
- Results Summary: total/pass/fail cards with counts
- Results Table: parameter, value, unit, limits, pass/fail badge
- Charts: voltage vs temperature (if available)
- Configuration: test config JSON (optional)
- Jinja2 filters for formatting (floats, dates)
- Files:
src/py_dvt_ate/reporting/templates/test_report.html - Commit: "Add test report HTML template"
Task 18.7: Implement HTML renderer
- Create
src/py_dvt_ate/reporting/renderers/__init__.py - Create
src/py_dvt_ate/reporting/renderers/html.py HTMLRendererclass:- Constructor takes
ReportConfig - Uses
jinja2.EnvironmentwithPackageLoader render(report_data: ReportData) -> strmethod- Custom filters for number formatting
- Constructor takes
- Template loading from
py_dvt_ate.reporting.templatespackage - Files:
src/py_dvt_ate/reporting/renderers/html.py,src/py_dvt_ate/reporting/renderers/__init__.py - Commit: "Implement HTML renderer with Jinja2"
Task 18.8: Implement PDF renderer
- Create
src/py_dvt_ate/reporting/renderers/pdf.py PDFRendererclass:render_to_file(html: str, output_path: Path) -> Nonerender_to_bytes(html: str) -> bytes
- Use WeasyPrint
HTML(string=html).write_pdf() - Handle WeasyPrint warnings gracefully
- Files:
src/py_dvt_ate/reporting/renderers/pdf.py - Commit: "Implement PDF renderer with WeasyPrint"
Task 18.9: Implement chart generator
- Create
src/py_dvt_ate/reporting/charts/__init__.py - Create
src/py_dvt_ate/reporting/charts/matplotlib_charts.py ChartGeneratorclass:- Constructor takes
ReportConfig(for DPI) _setup_style()- Configure matplotlib for professional appearancegenerate_voltage_vs_temperature(measurements: DataFrame) -> str- Scatter plot with trend line
- Calculate and display slope (ppm/C)
- Return base64-encoded PNG
generate_all(run, results, measurements) -> dict[str, str]- Dispatch to appropriate chart methods based on test type
- Constructor takes
- Use
matplotlib.use('Agg')for non-interactive backend - Files:
src/py_dvt_ate/reporting/charts/matplotlib_charts.py,src/py_dvt_ate/reporting/charts/__init__.py - Commit: "Implement matplotlib chart generator"
Task 18.10: Implement ReportGenerator class
- Create
src/py_dvt_ate/reporting/generator.py IReportGeneratorProtocol:generate(run_id: UUID, output_path: Path | None) -> Pathgenerate_bytes(run_id: UUID) -> bytes
ReportGeneratorclass:- Constructor:
repository,config,output_dir - Private:
_html_renderer,_pdf_renderer,_chart_generator _gather_data(run_id: UUID) -> ReportData- Fetch run, results, measurements from repository
- Generate charts if measurements available
_generate_output_path(run: TestRun) -> Path- Format:
{test_name}_{run_id_short}_{timestamp}.pdf
- Format:
- Error handling with appropriate exception types
- Constructor:
- Files:
src/py_dvt_ate/reporting/generator.py - Commit: "Implement ReportGenerator class"
Task 18.11: Update reporting module exports
- Update
src/py_dvt_ate/reporting/__init__.py - Export public API:
ReportGenerator,IReportGeneratorReportConfig,ReportData- All exception classes
- Add module docstring with usage example
- Lazy imports to handle missing optional dependencies
- Files:
src/py_dvt_ate/reporting/__init__.py - Commit: "Update reporting module public API"
Task 18.12: Add ReportingConfig to app config
- Update
src/py_dvt_ate/app/config.py - Add
ReportingConfigPydantic model:company_name: str = "DVT Engineering"logo_path: str | None = Noneinclude_charts: bool = Truechart_dpi: int = 150
- Add
reporting: ReportingConfigtoAppConfig - Files:
src/py_dvt_ate/app/config.py - Commit: "Add ReportingConfig to application config"
Task 18.13: Add reporting section to default.yaml
- Update
config/default.yaml - Add
reporting:section with all options - Document each option with comments
- Files:
config/default.yaml - Commit: "Add reporting configuration to default.yaml"
Task 18.14: Add list-runs CLI command
- Update
src/py_dvt_ate/app/cli.py - Add
list-runscommand:--limitoption (default 10)--configoption for config file
- Output format:
{id:8} {test_name:15} {status:8} {timestamp} - Load repository from config
- Files:
src/py_dvt_ate/app/cli.py - Commit: "Add list-runs CLI command"
Task 18.15: Add export-report CLI command
- Update
src/py_dvt_ate/app/cli.py - Add
export-reportcommand:run_idargument (required)--output/-ooption for output path--companyoption for company name override--configoption for config file
- Support short (8-char) and full UUID lookup
- Display progress and result path
- Files:
src/py_dvt_ate/app/cli.py - Commit: "Add export-report CLI command"
Task 18.16: Add PDF download to dashboard
- Update
src/py_dvt_ate/app/dashboard/app.py - In results viewer page, add:
- "Generate PDF Report" button (primary)
st.download_buttonfor PDF download- Progress spinner during generation
- Error handling for missing dependencies
- Store generated PDF in
st.session_state - Files:
src/py_dvt_ate/app/dashboard/app.py - Commit: "Add PDF download button to dashboard"
Task 18.17: Add reporting unit tests
- Create
tests/unit/reporting/__init__.py - Create
tests/unit/reporting/test_models.py- Test ReportConfig and ReportData creation
- Test default values
- Create
tests/unit/reporting/test_html_renderer.py- Test template rendering with mock data
- Test custom filters
- Create
tests/unit/reporting/test_chart_generator.py- Test chart generation produces valid base64
- Test with sample DataFrame
- Files:
tests/unit/reporting/ - Commit: "Add reporting unit tests"
Task 18.18: Add reporting integration test
- Create
tests/integration/test_report_generation.py - End-to-end test:
- Create test run with sample results in repository
- Generate PDF report
- Verify PDF file created and non-empty
- Optionally verify PDF structure (page count)
- Use pytest fixtures for repository setup
- Files:
tests/integration/test_report_generation.py - Commit: "Add report generation integration test"
Task 18.19: Update CHANGELOG
- Update
CHANGELOG.md - Add
## [Unreleased]section if not present - Document:
- New
export-reportCLI command - New
list-runsCLI command - Dashboard PDF download feature
- Reporting module with PDF/HTML generation
- New
- Files:
CHANGELOG.md - Commit: "Update CHANGELOG with report generation feature"
File Structure (New Files)
src/py_dvt_ate/reporting/
├── __init__.py # Task 18.11 - Public API
├── models.py # Task 18.2 - ReportConfig, ReportData
├── exceptions.py # Task 18.3 - Exception hierarchy
├── generator.py # Task 18.10 - ReportGenerator
├── renderers/
│ ├── __init__.py # Task 18.7
│ ├── html.py # Task 18.7 - HTMLRenderer
│ └── pdf.py # Task 18.8 - PDFRenderer
├── charts/
│ ├── __init__.py # Task 18.9
│ └── matplotlib_charts.py # Task 18.9 - ChartGenerator
└── templates/
├── styles.css # Task 18.4 - CSS
├── base.html # Task 18.5 - Base template
└── test_report.html # Task 18.6 - Report template
tests/unit/reporting/
├── __init__.py # Task 18.17
├── test_models.py # Task 18.17
├── test_html_renderer.py # Task 18.17
└── test_chart_generator.py # Task 18.17
tests/integration/
└── test_report_generation.py # Task 18.18
Files to Modify
| File | Tasks | Changes |
|---|---|---|
pyproject.toml |
18.1 | Add matplotlib to reports deps |
src/py_dvt_ate/app/config.py |
18.12 | Add ReportingConfig |
config/default.yaml |
18.13 | Add reporting section |
src/py_dvt_ate/app/cli.py |
18.14, 18.15 | Add list-runs, export-report |
src/py_dvt_ate/app/dashboard/app.py |
18.16 | Add PDF download |
CHANGELOG.md |
18.19 | Document new features |
Dependencies
| Package | Version | Purpose |
|---|---|---|
| jinja2 | >=3.1 | HTML template rendering |
| weasyprint | >=60.0 | HTML to PDF conversion |
| matplotlib | >=3.8 | Chart generation |
All in [project.optional-dependencies] reports group.
Install with: pip install py-dvt-ate[reports]
Verification
CLI Verification
# List recent test runs
py-dvt-ate list-runs
# Generate PDF report
py-dvt-ate export-report <run_id>
# With options
py-dvt-ate export-report <run_id> -o ./my_report.pdf --company "Acme Corp"
# View generated PDF
xdg-open ./data/reports/*.pdf
Dashboard Verification
# Start dashboard
streamlit run src/py_dvt_ate/app/dashboard/app.py
# In browser:
# 1. Navigate to Results Viewer
# 2. Select a test run
# 3. Click "Generate PDF Report"
# 4. Click "Download PDF Report"
# 5. Open downloaded PDF
Test Verification
# Run unit tests
pytest tests/unit/reporting/ -v
# Run integration test
pytest tests/integration/test_report_generation.py -v
# Check coverage
pytest tests/unit/reporting/ --cov=py_dvt_ate.reporting --cov-report=term-missing
Task Progress
| Task | Status | Description |
|---|---|---|
| 18.1 | pending | Add matplotlib dependency |
| 18.2 | pending | Report data models |
| 18.3 | pending | Reporting exceptions |
| 18.4 | pending | CSS stylesheet |
| 18.5 | pending | Base HTML template |
| 18.6 | pending | Test report template |
| 18.7 | pending | HTML renderer |
| 18.8 | pending | PDF renderer |
| 18.9 | pending | Chart generator |
| 18.10 | pending | ReportGenerator class |
| 18.11 | pending | Module exports |
| 18.12 | pending | App config update |
| 18.13 | pending | default.yaml update |
| 18.14 | pending | list-runs CLI |
| 18.15 | pending | export-report CLI |
| 18.16 | pending | Dashboard download |
| 18.17 | pending | Unit tests |
| 18.18 | pending | Integration test |
| 18.19 | pending | CHANGELOG update |
End of Sprint 18 Plan