Python API

Installation

pip install gridwell          # core: parse, validate, render (no runtime dependencies)
pip install 'gridwell[gt]'    # + Great Tables emitter (gt_to_ir / gt_to_dict)

Requires Python 3.10 or newer. Wheels use the stable ABI (abi3), so one wheel per platform serves every supported Python version.

Parsing

import gridwell

# From JSON string
table = gridwell.Table.from_json(json_str)

# From dict
table = gridwell.Table.from_dict({"ir_version": "1.0", ...})

# Shorthand
table = gridwell.parse_ir(json_str)

Validation

errors = table.validate()  # returns list[str]
if errors:
    for e in errors:
        print(f"Error: {e}")

Text Rendering

html = table.render_html()
latex = table.render_latex()
typst = table.render_typst()
rtf = table.render_rtf()
svg = table.render_svg()
ansi = table.render_ansi()
pandoc = table.render_pandoc()
quarto = table.render_quarto()

# Generic by name
output = table.render("html")

# Writer options: a dict, or keyword arguments to the per-format methods
output = table.render("html", {"inline_styles": True})
output = table.render_html(inline_styles=True)

# Every format, with its options and defaults
gridwell.formats()

See Writer Options for each format’s options.

Binary Rendering

docx_bytes = table.render_docx()    # returns bytes
xlsx_bytes = table.render_xlsx()
pptx_bytes = table.render_pptx()

# Generic by name (binary formats take no options yet)
data = table.render_binary("docx")

Saving to a File

Table.save(path, format=None, **options) renders and writes in one call, for every format. The format comes from the file extension (case-insensitive): .html, .tex (latex), .typ (typst), .rtf, .svg, .txt (ansi), .docx, .xlsx, .pptx. .json is both pandoc and quarto, so it needs format. The bytes are written unchanged (UTF-8 text, no added newline). path may be a str or any os.PathLike, and is returned.

table.save("output.docx")
table.save(Path("out") / "table.tex", booktabs=False)  # writer options as kwargs
table.save("table.json", format="quarto")
table.save("table.txt")                 # plain text, no ANSI escapes
table.save("table.txt", color=True)     # keep the escapes
table.save("table.html", standalone=True)  # a full document, not a fragment

Serialization

json_str = table.to_json()

Great Tables Integration

from great_tables import GT, exibble
import gridwell

gt = GT(exibble.head(5))
ir_json = gridwell.gt_to_ir(gt)
table = gridwell.parse_ir(ir_json)
html = table.render_html()

Error Handling

ValueError is raised for parse errors, unknown format names, and render failures. render() takes text formats and render_binary() binary ones; the other kind is a ValueError. Invalid writer options raise gridwell.InvalidOptionsError (a subclass of ValueError) naming the problem, e.g. an unknown option. save() raises ValueError for an extension it can’t infer a format from and OSError if the file can’t be written; nothing is written if rendering fails.

Every render_* method validates the table first. If the IR is invalid it raises gridwell.InvalidTableError (a subclass of ValueError) whose message lists the validation errors, e.g. [SPAN_OVERFLOW_RIGHT] Cell at (row=1, col=3) .... Use table.validate() to get the errors as a list without raising.

try:
    table = gridwell.Table.from_json(bad_json)
except ValueError as e:
    print(f"Parse error: {e}")

try:
    html = table.render_html()
except gridwell.InvalidTableError as e:
    print(f"Invalid IR: {e}")