d1a3d58a6b
Mejoras transversales del motor de render (no del contenido de capítulos): 1. Fix negrita pisa texto (PDF): _place_rich_lines mide el ancho REAL de cada span con las métricas de fuente del renderer (peso correcto) en vez del grid de ancho medio; negrita y normal en la misma línea ya no se solapan. 2. Zebra striping: filas pares sombreadas (#f6f8fa) en DataTable (PDF + PPTX), coherente al partir tablas largas (índice de fila lógico, no por página). 3. Keep-together: bloque Group nuevo; el renderer mide el grupo entero y lo mueve completo a la página/slide siguiente si no cabe, y encoge la figura (height_in) para dejar sitio a su título y texto. num_distr lo usa. 4. Caption siempre visible en toda figura PPTX (fallback al heading); la figura reserva el alto de su caption para que ambos quepan en el mismo slide. 5. Portada construida al final (con resumen agregado del análisis vía ctx['document_summary']) pero colocada primera por build_document. 6. Glosario: capítulo nuevo (último) + GlossaryCollector en ctx; los capítulos registran términos y marcan apariciones con [[term:key]]...[[/term]]. Links clicables reales: PDF (PyMuPDF, link GOTO) y PPTX (slide-jump nativo). Enganchado "entropía" en cat_distr como ejemplo end-to-end. Funciones reutilizables delegadas a fn-constructor (tag eda): - add_pdf_internal_links_py_datascience (PyMuPDF) - pptx_link_run_to_slide_py_datascience (slide-jump) Contrato docs/automatic_eda_contract.md actualizado (§1/§3/§5 + §11 nueva) con la API de glosario, keep-together y zebra para la siguiente fase. PyMuPDF declarado en pyproject. Suite verde (90 tests); golden titanic verificado. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
48 lines
1.9 KiB
Python
48 lines
1.9 KiB
Python
"""Glossary chapter (GLOSARIO) — always the last chapter, clickable terms.
|
|
|
|
Renders one entry per glossary term that the other chapters registered during
|
|
the document build through ``ctx['glossary'].add(key, label, definition)`` (see
|
|
``GlossaryCollector`` in ``model.py``). Each entry is a clickable destination:
|
|
every in-text appearance a chapter marked with ``[[term:key]]texto[[/term]]``
|
|
becomes a real jump to its entry here — PDF link annotations (PyMuPDF) and PPTX
|
|
native slide jumps, both wired by the renderers.
|
|
|
|
Returns ``None`` when no term was registered (there is nothing to show), so the
|
|
chapter simply disappears from documents that did not mark any term.
|
|
|
|
Contract: build_<id>(profile, ctx) -> Chapter | None ; CHAPTER_VERSION = "x.y.z".
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from .. import model
|
|
|
|
CHAPTER_VERSION = "1.0.0"
|
|
CHAPTER_ID = "glosario"
|
|
CHAPTER_TITLE = "Glosario"
|
|
|
|
|
|
def build_glosario(profile: dict, ctx: dict):
|
|
"""Build the glossary Chapter from the shared collector, or None if empty."""
|
|
ctx = ctx or {}
|
|
glossary = ctx.get("glossary")
|
|
if not isinstance(glossary, model.GlossaryCollector) or not glossary:
|
|
return None
|
|
|
|
blocks = [
|
|
model.Heading(text="Glosario de términos", level=1),
|
|
model.Markdown(text=(
|
|
"Definición de los términos técnicos que aparecen en el informe. "
|
|
"Cada término va resaltado en el texto y, al pulsarlo, salta a su "
|
|
"definición en esta sección.")),
|
|
]
|
|
# One clickable destination per term, alphabetically by visible label.
|
|
for term in glossary.terms(by="label"):
|
|
blocks.append(model.GlossaryEntry(
|
|
key=model._safe_str(term.get("key")),
|
|
label=model._safe_str(term.get("label")),
|
|
definition=model._safe_str(term.get("definition"))))
|
|
|
|
return model.Chapter(id=CHAPTER_ID, title=CHAPTER_TITLE,
|
|
version=CHAPTER_VERSION, blocks=blocks)
|