"""``GT`` — the greater_tables constructor-compatible facade.
Thin, not bug-for-bug: the common blog/Quarto call
``GT(df, caption=..., ratio_cols=..., formatters=...)`` works and renders via
the GT2 engine; exotic 5.x config knobs are accepted with a warning and
ignored. Everything is lazy cached — constructing a GT computes nothing, and
TikZ is never computed on the HTML path (the 5.x eager-TikZ waste is gone by
construction).
``formatters`` is passed straight through: it is a real ``TableSpec`` field,
not a translated shim. One deliberate difference from 5.x — a bare int now
groups (``{'paid': 2}`` → ``1,234.57``, where 5.x meant ``1234.57``), because
GT2 groups whenever it chooses the format for you. Write ``'.2f'`` for the
ungrouped form.
"""
from __future__ import annotations
import warnings
from dataclasses import fields as _dc_fields
from functools import cached_property
from .config import load_spec
from .ir import TableDoc
from .render.html import render_html
from .render.notebook import mimebundle, validate_mimes
from .render.text import render_text
from .spec import HouseStyle, TableSpec
__all__ = ['GT']
_SPEC_FIELDS = {f.name for f in _dc_fields(TableSpec)}
_STYLE_FIELDS = {f.name for f in _dc_fields(HouseStyle)}
[docs]
class GT:
"""Table facade: data + spec in, renderings out (all lazy, all cached).
Parameters mirror the greater_tables constructor where they still make
sense; ``formatters`` accepts the 5.x shapes (callable, ``'{x:...}'``
format string, or int = decimal digits, now grouped). ``config_path``
loads YAML TableSpec defaults which explicit arguments override.
``style`` takes a :class:`~greater_tables.spec.HouseStyle` and is
forwarded to every renderer. ``mimes`` pins what ``_repr_mimebundle_``
publishes — None (default) detects the target, an explicit tuple such as
``('text/plain',)`` publishes exactly that. It is a whole-document
policy, so the intended form is
``render = partial(GT, mimes=('text/plain',))``. Additional keyword
arguments naming TableSpec fields pass through; unknown ones warn and are
ignored (migration aid), and a HouseStyle field name warns with the fix.
"""
def __init__(self, data=None, caption=None, label=None, aligners=None,
formatters=None, unbreakable=None, ratio_cols=None,
year_cols=None, date_cols=None, raw_cols=None,
show_index=None, config_path=None, style=None, mimes=None,
**overrides):
base = load_spec(config_path) if config_path else TableSpec()
kwargs = {
'caption': caption, 'label': label, 'aligners': aligners,
'unbreakable': unbreakable, 'ratio_cols': ratio_cols,
'year_cols': year_cols, 'date_cols': date_cols,
'raw_cols': raw_cols, 'show_index': show_index,
'formatters': formatters,
}
for key, value in overrides.items():
if key in _SPEC_FIELDS:
kwargs[key] = value
elif key in _STYLE_FIELDS:
warnings.warn(f'GT: {key!r} is a HouseStyle field — pass '
f'style=HouseStyle({key}=...)', stacklevel=2)
else:
warnings.warn(f'GT: ignoring unknown option {key!r} '
'(gone in greater_tables)', stacklevel=2)
merged = {f.name: getattr(base, f.name) for f in _dc_fields(TableSpec)}
merged.update({k: v for k, v in kwargs.items() if v is not None})
self.spec = TableSpec(**merged)
self.style = style
# validated here, not at display time, so a typo names its call site
self.mimes = None if mimes is None else validate_mimes(mimes)
self._data = data
[docs]
@cached_property
def doc(self) -> TableDoc:
"""The table document (the IR) — built on first access."""
from .engine.build import build
return build(self._data, self.spec)
[docs]
@cached_property
def html(self) -> str:
"""HTML fragment (stylesheet embedded)."""
return render_html(self.doc, style=self.style)
[docs]
@cached_property
def text(self) -> str:
"""Monospace text rendering (the conformance oracle's view)."""
return render_text(self.doc, self.style)
[docs]
@cached_property
def tikz(self) -> str:
"""TikZ/LaTeX rendering (table environment + tikzpicture)."""
from .render.tikz import render_tikz
return render_tikz(self.doc, self.style)
def __str__(self) -> str:
return self.text
def __repr__(self) -> str:
# the table, not <GT at 0x…> — this is what makes GT usable from a
# plain script, a REPL, and any consumer that falls back to repr()
return self.text
def _repr_mimebundle_(self, include=None, exclude=None):
return mimebundle(self.doc, style=self.style, mimes=self.mimes)