StableFill tries to keep legacy warning behavior for ordinary fills, but expected failures now include structured diagnostic context. When available, errors report:
This is useful when a table has too few values, a numeric placeholder receives
text, or an input row appears before any <Tab:...> or <Val:...> label.
If this input is used:
<Tab:broken_numeric>
not-a-number
with this template:
\begin{table}
\label{tab:broken_numeric}
\begin{tabular}{lr}
Bad value & #0,# \\
\end{tabular}
\end{table}
StableFill returns an error that includes the placeholder and table context:
[PLACEHOLDER_ERROR] Could not fill template placeholder.
Details: location=.../template.tex:6; table=broken_numeric; entry=1;
placeholder='#0,#'; context='Bad value & #0,# \\'
The full traceback is still returned by the Python API and command-line wrapper, so advanced users can inspect the original exception as well.
The template scanner uses an explicit grammar for each supported file type. For LaTeX, a fillable table is:
\begin{table} or \begin{subtable} region\label{tab:name} inside itname matches an input <Tab:name> block###, #0,#, or #*#Sequential table placeholders are ignored in comments unless
--fill-comments is used. Tables with tab: labels but no placeholders are
treated as already-filled content: they are left unchanged and do not produce
missing-input warnings.
Inline placeholders such as `` are independent of table regions and can appear in prose, captions, notes, or table text.
The repository contains a long integration fixture in
test/input/complex_latex/. It includes:
AT\&T, R\&D, Price \#1, and escaped bracesRun the full suite with:
uv run --extra test python -m pytest -q
When xelatex is installed, the complex fixture is filled from the command
line and compiled to PDF. When pdfinfo is also installed, the test verifies
that the rendered PDF is four or five pages.