Skip to content

feat: export analysis reports as PDF (closes #138)#154

Merged
luceinaltis merged 1 commit into
mainfrom
feat/138-pdf-reports
Apr 9, 2026
Merged

feat: export analysis reports as PDF (closes #138)#154
luceinaltis merged 1 commit into
mainfrom
feat/138-pdf-reports

Conversation

@luceinaltis
Copy link
Copy Markdown
Owner

Summary

Adds a PDF export option to ReportExporter so analysis results can be shared as formatted PDFs alongside the existing Markdown and JSON formats. This is a small, focused re-implementation targeting current main after #144 was closed for being branched from the pre-refactor src/tracer layout.

Closes #138.

What changed

  • qracer/conversation/report_exporter.py — new save_pdf() method. Renders header, query, response body, optional Trade Thesis, and successful data sources via fpdf2. The import is lazy so ReportExporter keeps working without the optional dep; callers get a clear ImportError with install instructions instead of a hard crash at module import.
  • qracer/conversation/engine.pysave_last_report(fmt="pdf") routes to the new method.
  • qracer/cli.pysave pdf / /save pdf REPL commands, with a friendly message when fpdf2 is missing. Help text and banner updated.
  • pyproject.toml — new [pdf] = ["fpdf2>=2.7.0"] optional extra, plus fpdf2 added to the dev dependency group so CI exercises the feature end-to-end (CI runs uv sync --extra web, which pulls in the dev group).
  • tests/conversation/test_report_exporter.py — 4 new tests covering basic write, Trade Thesis rendering, data-sources filtering (only successful tools), and the general-ticker fallback. Because fpdf2 zlib-compresses page streams, a small _extract_pdf_text helper decompresses FlateDecode blocks so assertions can look for literal text without pulling in a PDF parser. Each PDF test uses pytest.importorskip("fpdf") to stay opt-in on environments without the extra.

How to test

uv sync --extra web --extra pdf
uv run ruff check .
uv run ruff format --check .
uv run pyright
uv run pytest tests/conversation/test_report_exporter.py -v

Or exercise the new REPL command manually:

uv run qracer repl
> Analyze AAPL
> save pdf
# -> Saved to ~/.qracer/reports/AAPL-YYYY-MM-DD.pdf

The generated PDF contains the header, query, response, Trade Thesis (when present), and the list of successful data sources.

Notes

  • Full suite (pytest --cov=qracer --cov-fail-under=80) passes locally at 80.37% coverage with all 711 tests green.
  • ruff check, ruff format --check, and pyright all clean.
  • save_pdf() intentionally mirrors save_markdown()'s "successful tools only" behavior for the Data Sources section so the three formats stay consistent.

Add a third report format alongside Markdown and JSON so users can
hand formatted PDF output to stakeholders.

- `ReportExporter.save_pdf()` renders a header, query, response body,
  optional Trade Thesis section, and successful data sources using
  fpdf2. The import is lazy so `ReportExporter` stays usable when the
  optional dep isn't installed — callers get a clear ImportError with
  install instructions instead.
- `ConversationEngine.save_last_report(fmt="pdf")` routes to the new
  method.
- REPL gains `save pdf` / `/save pdf` commands with a friendly error
  when fpdf2 is missing; help text and banner updated.
- `fpdf2>=2.7.0` registered as a new `[pdf]` optional extra and added
  to the dev dependency group so CI exercises the feature.
- Tests cover the basic write, Trade Thesis section, data-sources
  filtering (only successful tools), and general-ticker fallback.
  Since fpdf2 compresses page streams, a small helper decompresses
  FlateDecode blocks so assertions can look for literal text without
  pulling in a PDF parser.

Co-authored-by: Claude <noreply@anthropic.com>
@luceinaltis luceinaltis merged commit 85759b2 into main Apr 9, 2026
3 checks passed
@luceinaltis luceinaltis deleted the feat/138-pdf-reports branch April 9, 2026 00:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: export analysis reports as PDF

2 participants