Source code for greater_tables.render.notebook

"""Notebook/Quarto integration helpers.

The mimebundle always carries ``text/plain``: it is the one type every
measured consumer renders (JupyterLab, Quarto html/latex/gfm, Sphinx
html/latex), so a table degrades to a monospace rendering rather than to
silence or to ``<GT object at 0x…>``. What joins it depends on the target —
``text/html`` normally, ``text/latex`` (the TikZ rendering) under a Quarto
PDF render, never both. Keying on the target is what structurally fixes
greater_tables 5.x's compute-TikZ-then-discard-it-per-repr waste: an HTML
render now computes no TikZ at all.

``text/html`` is excluded on the PDF path deliberately. Pandoc prefers html
when it is offered, and its LaTeX writer then discards the raw html, so a
``{html, latex, plain}`` bundle renders *nothing*; omitting html means a TikZ
failure degrades to text instead of to an empty page.

Detection reads ``QUARTO_FIG_FORMAT``, the only channel Quarto offers. It is
``pdf`` on the PDF path and ``png`` for html and gfm alike, so html and gfm
are indistinguishable from the environment. A gfm build that needs plain only
has to say so with ``mimes`` — see :func:`quarto_target`.
"""

from __future__ import annotations

from collections.abc import Iterable
import os

from ..ir import TableDoc
from ..spec import HouseStyle
from .html import render_html
from .text import render_text
from .tikz import render_tikz

__all__ = ['KNOWN_MIMES', 'in_quarto', 'mimebundle', 'quarto_target',
           'validate_mimes']

HTML = 'text/html'
LATEX = 'text/latex'
PLAIN = 'text/plain'
KNOWN_MIMES = (HTML, LATEX, PLAIN)


[docs] def in_quarto() -> bool: """True inside a ``quarto render`` (any QUARTO_* env variable set).""" return any(k.startswith('QUARTO_') for k in os.environ)
[docs] def quarto_target() -> str | None: """Which Quarto output is being built: ``'pdf'``, ``'other'``, or None. ``QUARTO_FIG_FORMAT`` is the proxy: ``pdf`` on the PDF path, ``png`` for both html and gfm. ``'other'`` therefore means "a Quarto render that is not PDF" and deliberately not "html" — the environment cannot tell html from gfm, and naming it html would hide a real ambiguity. None means no Quarto render was detected at all. """ if not in_quarto(): return None return 'pdf' if os.environ.get('QUARTO_FIG_FORMAT') == 'pdf' else 'other'
[docs] def validate_mimes(mimes: Iterable[str]) -> tuple[str, ...]: """Check an explicit MIME request, returning it as a tuple. Raises ``ValueError`` on anything outside :data:`KNOWN_MIMES`: a typo would otherwise publish a bundle no consumer can use, and fail silently. """ out = tuple(mimes) unknown = [m for m in out if m not in KNOWN_MIMES] if unknown: raise ValueError(f'mimes: unknown MIME type(s) {unknown}; expected a ' f'subset of {KNOWN_MIMES}') return out
[docs] def mimebundle(doc: TableDoc, *, css: str = 'embed', tikz: bool | None = None, style: HouseStyle | None = None, mimes: Iterable[str] | None = None) -> dict[str, str]: """MIME bundle for ``_repr_mimebundle_``. ``text/plain`` is always present unless ``mimes`` excludes it. With both ``tikz`` and ``mimes`` left at None the published keys are: ================================== ========================== target keys ================================== ========================== ``QUARTO_FIG_FORMAT == 'pdf'`` ``text/latex, text/plain`` any other Quarto render, or none ``text/html, text/plain`` ================================== ========================== Parameters ---------- doc The document. css Stylesheet policy for the HTML entry. tikz Force ``text/latex`` in or out, bypassing target detection; None (default) detects. Forcing it *in* keeps ``text/html`` — it means "also give me TikZ", not "this is a PDF render". Use ``mimes`` for exact control. style HouseStyle, forwarded to every renderer (HTML reads only the rule depth caps; TikZ reads everything). mimes Publish exactly these types, suppressing detection entirely and overriding ``tikz``. Members are validated against :data:`KNOWN_MIMES`. This is the escape hatch for a target GT cannot detect — notably Quarto ``--to gfm``, where pandoc prefers html and the caller must ask for ``('text/plain',)``. """ if mimes is not None: wanted = validate_mimes(mimes) elif tikz is None: wanted = (LATEX, PLAIN) if quarto_target() == 'pdf' else (HTML, PLAIN) else: wanted = (HTML, LATEX, PLAIN) if tikz else (HTML, PLAIN) build = { HTML: lambda: render_html(doc, css=css, style=style), LATEX: lambda: render_tikz(doc, style), PLAIN: lambda: render_text(doc, style), } # KNOWN_MIMES order, so the bundle key order does not depend on the caller return {m: build[m]() for m in KNOWN_MIMES if m in wanted}