Add export-report CLI command
This commit is contained in:
@@ -208,6 +208,127 @@ def list_runs_cmd(
|
|||||||
repo.close()
|
repo.close()
|
||||||
|
|
||||||
|
|
||||||
|
@app.command(name="export-report")
|
||||||
|
def export_report_cmd(
|
||||||
|
run_id: Annotated[
|
||||||
|
str,
|
||||||
|
typer.Argument(help="Test run ID (short 8-char or full UUID)."),
|
||||||
|
],
|
||||||
|
output: Annotated[
|
||||||
|
str | None,
|
||||||
|
typer.Option("--output", "-o", help="Output PDF file path."),
|
||||||
|
] = None,
|
||||||
|
company: Annotated[
|
||||||
|
str | None,
|
||||||
|
typer.Option("--company", help="Company name for report header."),
|
||||||
|
] = None,
|
||||||
|
config_file: Annotated[
|
||||||
|
str | None,
|
||||||
|
typer.Option("--config", "-c", help="Path to configuration YAML file."),
|
||||||
|
] = None,
|
||||||
|
) -> None:
|
||||||
|
"""Export a PDF report for a test run.
|
||||||
|
|
||||||
|
Generate a professional PDF report from test results. The run_id can be
|
||||||
|
the short 8-character ID shown by list-runs, or the full UUID.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
py-dvt-ate export-report abc12345
|
||||||
|
py-dvt-ate export-report abc12345 --output ./my_report.pdf
|
||||||
|
py-dvt-ate export-report abc12345 --company "My Company"
|
||||||
|
"""
|
||||||
|
from pathlib import Path
|
||||||
|
from uuid import UUID
|
||||||
|
|
||||||
|
from rich.console import Console
|
||||||
|
|
||||||
|
from py_dvt_ate.app.config import load_config
|
||||||
|
from py_dvt_ate.data.repository import SQLiteRepository
|
||||||
|
|
||||||
|
console = Console()
|
||||||
|
|
||||||
|
# Check for reporting dependencies
|
||||||
|
try:
|
||||||
|
from py_dvt_ate.reporting import ReportConfig, ReportGenerator
|
||||||
|
except ImportError:
|
||||||
|
console.print(
|
||||||
|
"[red]Error:[/red] Report generation requires additional dependencies.\n"
|
||||||
|
"Install with: [cyan]pip install py_dvt_ate[reports][/cyan]"
|
||||||
|
)
|
||||||
|
raise typer.Exit(1)
|
||||||
|
|
||||||
|
# Load config
|
||||||
|
if config_file is None:
|
||||||
|
config_path = Path("config/default.yaml")
|
||||||
|
if config_path.exists():
|
||||||
|
config_file = str(config_path)
|
||||||
|
|
||||||
|
config = load_config(config_file)
|
||||||
|
|
||||||
|
# Create repository
|
||||||
|
repo = SQLiteRepository(
|
||||||
|
db_path=config.data.database_path,
|
||||||
|
measurements_dir=config.data.measurements_dir,
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Resolve short ID to full UUID
|
||||||
|
full_run_id: UUID | None = None
|
||||||
|
|
||||||
|
if len(run_id) == 8:
|
||||||
|
# Short ID - need to find full UUID
|
||||||
|
all_runs = repo.get_all_runs()
|
||||||
|
matching_runs = [r for r in all_runs if r.id.startswith(run_id)]
|
||||||
|
|
||||||
|
if not matching_runs:
|
||||||
|
console.print(f"[red]Error:[/red] No test run found with ID starting with '{run_id}'")
|
||||||
|
raise typer.Exit(1)
|
||||||
|
elif len(matching_runs) > 1:
|
||||||
|
console.print(f"[red]Error:[/red] Multiple runs match '{run_id}'. Use full UUID.")
|
||||||
|
for run in matching_runs:
|
||||||
|
console.print(f" - {run.id} ({run.test_name})")
|
||||||
|
raise typer.Exit(1)
|
||||||
|
|
||||||
|
full_run_id = UUID(matching_runs[0].id)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
full_run_id = UUID(run_id)
|
||||||
|
except ValueError:
|
||||||
|
console.print(f"[red]Error:[/red] Invalid run ID: '{run_id}'")
|
||||||
|
raise typer.Exit(1)
|
||||||
|
|
||||||
|
# Create report config
|
||||||
|
report_config = ReportConfig(
|
||||||
|
company_name=company or config.reporting.company_name,
|
||||||
|
logo_path=Path(config.reporting.logo_path) if config.reporting.logo_path else None,
|
||||||
|
include_charts=config.reporting.include_charts,
|
||||||
|
chart_dpi=config.reporting.chart_dpi,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Create generator
|
||||||
|
generator = ReportGenerator(
|
||||||
|
repository=repo,
|
||||||
|
config=report_config,
|
||||||
|
reports_dir=Path(config.data.reports_dir),
|
||||||
|
)
|
||||||
|
|
||||||
|
# Generate report
|
||||||
|
console.print(f"[cyan]Generating report for run {str(full_run_id)[:8]}...[/cyan]")
|
||||||
|
|
||||||
|
output_path = Path(output) if output else None
|
||||||
|
pdf_path = generator.generate(full_run_id, output_path)
|
||||||
|
|
||||||
|
console.print(f"[green]Report saved to:[/green] {pdf_path}")
|
||||||
|
|
||||||
|
except typer.Exit:
|
||||||
|
raise
|
||||||
|
except Exception as e:
|
||||||
|
console.print(f"[red]Error generating report:[/red] {e}")
|
||||||
|
raise typer.Exit(1)
|
||||||
|
finally:
|
||||||
|
repo.close()
|
||||||
|
|
||||||
|
|
||||||
@app.command(name="query")
|
@app.command(name="query")
|
||||||
def query_cmd(
|
def query_cmd(
|
||||||
instrument: Annotated[
|
instrument: Annotated[
|
||||||
|
|||||||
Reference in New Issue
Block a user