feat(eda): render de models en markdown + PDF DB-level para profile_database (H4,H9)

- H4: render_eda_markdown anade seccion Modelos (PCA/KMeans/normalidad/outliers);
  render_eda_pdf formatea models/series/caveats como tablas (no str(dict) crudo)
- H9: profile_database gana flag emit_pdf -> PDF movil DB-level (resumen tablas +
  join graph) via render_eda_pdf_relational; clave report_pdf_path
- aditivos y retrocompatibles (flags default False). 38 tests verdes

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Egutierrez
2026-06-29 04:05:38 +02:00
parent caf8c25d99
commit c4cff5ed5b
7 changed files with 706 additions and 15 deletions
@@ -165,3 +165,36 @@ def test_profile_database_writes_report(tmp_path):
assert "# EDA base —" in md
assert "## Relaciones inter-tabla" in md
assert "```mermaid" in md
def test_profile_database_emit_pdf(tmp_path):
# H9: con emit_pdf=True, profile_database genera un PDF DB-level (>0 bytes,
# cabecera %PDF) además del markdown + JSON.
db_path = os.path.join(str(tmp_path), "shop3.duckdb")
_build_related_db(db_path)
report_dir = os.path.join(str(tmp_path), "reports")
res = profile_database(
db_path, report_dir=report_dir, write_report=True, emit_pdf=True
)
assert res["status"] == "ok", res
pdf = res.get("report_pdf_path")
assert pdf is not None
assert os.path.exists(pdf)
assert os.path.getsize(pdf) > 0
with open(pdf, "rb") as fh:
assert fh.read(4) == b"%PDF"
def test_profile_database_emit_pdf_false_retrocompat(tmp_path):
# Edge: emit_pdf=False (default) se comporta como antes — no genera PDF y
# report_pdf_path es None.
db_path = os.path.join(str(tmp_path), "shop4.duckdb")
_build_related_db(db_path)
report_dir = os.path.join(str(tmp_path), "reports")
res = profile_database(db_path, report_dir=report_dir, write_report=True)
assert res["status"] == "ok", res
assert res.get("report_pdf_path") is None