docx/table-style-builtin

Apply each built-in Word table-type style (TableGrid, LightShading, MediumShading1, ColorfulGrid, ...) via <w:tblPr><w:tblStyle w:val="<StyleId>"/></w:tblPr>.

Cases (15)

Feature IDAxis bindingspython-docxdocxjs
docx/table-style-builtin--colorful-gridstyle=colorful-grid
docx/table-style-builtin--colorful-liststyle=colorful-list
docx/table-style-builtin--colorful-shadingstyle=colorful-shading
docx/table-style-builtin--dark-liststyle=dark-list
docx/table-style-builtin--light-gridstyle=light-grid
docx/table-style-builtin--light-liststyle=light-list
docx/table-style-builtin--light-shadingstyle=light-shading
docx/table-style-builtin--light-shading-accent-1style=light-shading-accent-1
docx/table-style-builtin--medium-grid-1style=medium-grid-1
docx/table-style-builtin--medium-grid-3style=medium-grid-3
docx/table-style-builtin--medium-list-1style=medium-list-1
docx/table-style-builtin--medium-list-2style=medium-list-2
docx/table-style-builtin--medium-shading-1style=medium-shading-1
docx/table-style-builtin--medium-shading-2style=medium-shading-2
docx/table-style-builtin--table-gridstyle=table-grid

Aggregate

LibraryPassFailPending
python-docx0015
docxjs0015

Parameter axes

Spec notes

Built-in table styles ship in Word's default styles.xml and are referenced from a table via <w:tblPr><w:tblStyle w:val="<StyleId>"/></w:tblPr>. Clause 17.7 of ECMA-376 Part 1 covers style definitions in general; 17.4.40 specifies w:tblStyle specifically, and 17.9.21 lists the reserved built-in style identifiers. The style_id is the whitespace-collapsed camel/pascal-case identifier (e.g. 'LightShading', 'MediumShading1', 'LightShading-Accent1') while the display name shown in Word's UI may include spaces and accent numbers ('Light Shading', 'Medium Shading 1', 'Light Shading Accent 1'). python-docx's default document template (via Document()) already materialises all 100 built-in table styles, so no latent-style materialisation is required. This manifest picks a representative subset spanning the major style families (Grid, Light Shading/List/Grid, Medium Shading/List/Grid variants, Dark List, Colorful Shading/List/Grid). The 'TableNormal' default is excluded because python-docx does not emit an explicit <w:tblStyle> for it.

Generator source

scripts/gen_table_style_builtin.py — runs with --arg_template --style-id {style.style_id} --out fixtures/docx/table-style-builtin--{style.id}.docx

#!/usr/bin/env python3
"""Generate ``fixtures/docx/table-style-builtin--<style-id>.docx`` fixtures.

Parameterised generator driven by
``features/docx/table-style-builtin.json``. For each built-in Word
table-type style, produce a 2x2 table whose ``w:tblPr`` carries
``<w:tblStyle w:val="<StyleId>"/>``.

The generator accepts the camel/pascal-case *style_id* (what appears
in ``styles.xml`` and in Word's XML, e.g. ``LightShading``,
``MediumShading1``, ``LightShading-Accent1``) and looks the style up
via its *display name* because python-docx's ``doc.styles[...]``
lookup by style_id raises a ``DeprecationWarning`` in modern
python-docx.

python-docx's default ``Document()`` template already materialises all
100 built-in table styles (including ``TableNormal``, which is
excluded from the manifest because no explicit ``<w:tblStyle>`` is
emitted for it). No latent-style materialisation is required.
"""

from __future__ import annotations

import argparse
from pathlib import Path

from docx import Document

_REPO_ROOT = Path(__file__).resolve().parent.parent


def _write(style_id: str, out: Path) -> None:
    doc = Document()
    # Resolve style_id -> display name once, because `doc.styles[style_id]`
    # triggers a DeprecationWarning in modern python-docx — the supported
    # key is the display name.
    display_name = None
    for style in doc.styles:
        if getattr(style, "style_id", None) == style_id:
            display_name = style.name
            break
    if display_name is None:
        raise SystemExit(
            f"Built-in table style {style_id!r} not found in the default template"
        )

    table = doc.add_table(rows=2, cols=2)
    table.style = doc.styles[display_name]
    table.rows[0].cells[0].text = "A1"
    table.rows[0].cells[1].text = "B1"
    table.rows[1].cells[0].text = "A2"
    table.rows[1].cells[1].text = "B2"

    out.parent.mkdir(parents=True, exist_ok=True)
    doc.save(out, reproducible=True)


def main() -> int:
    parser = argparse.ArgumentParser()
    parser.add_argument(
        "--style-id",
        required=True,
        help="Built-in table style identifier (e.g. 'LightShading', 'MediumShading1').",
    )
    parser.add_argument("--out", required=True, help="Output .docx path.")
    args = parser.parse_args()

    out_path = Path(args.out)
    if not out_path.is_absolute():
        out_path = _REPO_ROOT / out_path
    _write(args.style_id, out_path)
    print(out_path)
    return 0


if __name__ == "__main__":
    raise SystemExit(main())

Manifest (parent, unexpanded)

{
  "$schema": "../manifest.schema.json",
  "id": "docx/table-style-builtin",
  "kind": "parameterised",
  "title": "Built-in table styles",
  "format": "docx",
  "category": "tables",
  "summary": "Apply each built-in Word table-type style (TableGrid, LightShading, MediumShading1, ColorfulGrid, ...) via <w:tblPr><w:tblStyle w:val=\"<StyleId>\"/></w:tblPr>.",
  "spec": {
    "source": "ecma-376-5-part-1",
    "clause": "17.7",
    "element": "w:tblStyle",
    "rnc_reference": "spec/ecma-376-5/part-1/rnc/WordprocessingML.rnc",
    "xsd_reference": "spec/ecma-376-5/part-1/xsd/wml.xsd",
    "notes": "Built-in table styles ship in Word's default styles.xml and are referenced from a table via <w:tblPr><w:tblStyle w:val=\"<StyleId>\"/></w:tblPr>. Clause 17.7 of ECMA-376 Part 1 covers style definitions in general; 17.4.40 specifies w:tblStyle specifically, and 17.9.21 lists the reserved built-in style identifiers. The style_id is the whitespace-collapsed camel/pascal-case identifier (e.g. 'LightShading', 'MediumShading1', 'LightShading-Accent1') while the display name shown in Word's UI may include spaces and accent numbers ('Light Shading', 'Medium Shading 1', 'Light Shading Accent 1'). python-docx's default document template (via Document()) already materialises all 100 built-in table styles, so no latent-style materialisation is required. This manifest picks a representative subset spanning the major style families (Grid, Light Shading/List/Grid, Medium Shading/List/Grid variants, Dark List, Colorful Shading/List/Grid). The 'TableNormal' default is excluded because python-docx does not emit an explicit <w:tblStyle> for it."
  },
  "fixtures": {
    "machine": "docx/table-style-builtin"
  },
  "generator": {
    "python": "scripts/gen_table_style_builtin.py",
    "arg_template": "--style-id {style.style_id} --out fixtures/docx/table-style-builtin--{style.id}.docx"
  },
  "parameters": {
    "style": [
      {
        "id": "table-grid",
        "style_id": "TableGrid",
        "display": "Table Grid"
      },
      {
        "id": "light-shading",
        "style_id": "LightShading",
        "display": "Light Shading"
      },
      {
        "id": "light-shading-accent-1",
        "style_id": "LightShading-Accent1",
        "display": "Light Shading Accent 1"
      },
      {
        "id": "light-list",
        "style_id": "LightList",
        "display": "Light List"
      },
      {
        "id": "light-grid",
        "style_id": "LightGrid",
        "display": "Light Grid"
      },
      {
        "id": "medium-shading-1",
        "style_id": "MediumShading1",
        "display": "Medium Shading 1"
      },
      {
        "id": "medium-shading-2",
        "style_id": "MediumShading2",
        "display": "Medium Shading 2"
      },
      {
        "id": "medium-list-1",
        "style_id": "MediumList1",
        "display": "Medium List 1"
      },
      {
        "id": "medium-list-2",
        "style_id": "MediumList2",
        "display": "Medium List 2"
      },
      {
        "id": "medium-grid-1",
        "style_id": "MediumGrid1",
        "display": "Medium Grid 1"
      },
      {
        "id": "medium-grid-3",
        "style_id": "MediumGrid3",
        "display": "Medium Grid 3"
      },
      {
        "id": "dark-list",
        "style_id": "DarkList",
        "display": "Dark List"
      },
      {
        "id": "colorful-shading",
        "style_id": "ColorfulShading",
        "display": "Colorful Shading"
      },
      {
        "id": "colorful-list",
        "style_id": "ColorfulList",
        "display": "Colorful List"
      },
      {
        "id": "colorful-grid",
        "style_id": "ColorfulGrid",
        "display": "Colorful Grid"
      }
    ]
  },
  "assertions_template": [
    {
      "id": "tblstyle-element-present-{style.id}",
      "part": "word/document.xml",
      "namespaces": {
        "w": "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
      },
      "xpath": "//w:tbl/w:tblPr/w:tblStyle",
      "must": "exist",
      "description": "The sample table must carry a <w:tblStyle> inside its <w:tblPr>."
    },
    {
      "id": "tblstyle-is-{style.id}",
      "part": "word/document.xml",
      "namespaces": {
        "w": "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
      },
      "xpath": "//w:tbl/w:tblPr/w:tblStyle/@w:val",
      "must": "equal",
      "value": "{style.style_id}",
      "description": "The tblStyle value must equal the built-in table style identifier '{style.style_id}' (display name: '{style.display}')."
    }
  ],
  "render_assertions_template": [
    {
      "id": "visual-matches-libreoffice-render",
      "kind": "visual_ssim",
      "min_ssim": 0.5,
      "description": "Playwright screenshot of the rendered output must score >=85% SSIM against the LibreOffice-rendered reference PNG."
    }
  ]
}