pptx/interop-shape-roster

A curated roster of six primitive MSO_SHAPE preset geometries (rect, ellipse, triangle, diamond, right-triangle, right-arrow). python-pptx authors each fixture; pptxjs renders it. The manifest asserts both that the written XML carries the canonical <a:prstGeom prst=...> token AND that pptxjs produces a DOM node for the shape. Catches cases where python-pptx writes valid DrawingML but pptxjs renders nothing or drops the preset geometry.

Cases (6)

Feature IDAxis bindingspython-pptxpptxjs
pptx/interop-shape-roster--diamondpreset=diamond
pptx/interop-shape-roster--ellipsepreset=ellipse
pptx/interop-shape-roster--rectpreset=rect
pptx/interop-shape-roster--right-arrowpreset=right-arrow
pptx/interop-shape-roster--right-trianglepreset=right-triangle
pptx/interop-shape-roster--trianglepreset=triangle

Aggregate

LibraryPassFailPending
python-pptx006
pptxjs006

Parameter axes

Spec notes

DrawingML <a:prstGeom prst="..."/> selects one of the ~180 preset auto-shape geometries enumerated in ST_ShapeType. This interop manifest differs from `pptx/shape-preset-geometry` in two ways: (1) it covers a *curated primitive roster* instead of the full ~180-member enum — just the shapes that should be unambiguous to render; (2) it carries a `render_assertions` block that asserts the output pptxjs DOM, specifically targeting cross-library drift: python-pptx writes valid XML but pptxjs must render it as a visible shape node.

Generator source

scripts/gen_interop_shape_roster.py — runs with --arg_template --preset {preset.mso} --out fixtures/pptx/interop-shape-roster--{preset.id}.pptx

#!/usr/bin/env python3
"""Generate a ``fixtures/pptx/interop-shape-roster--<id>.pptx`` fixture.

Parameterised generator for the ``pptx/interop-shape-roster`` manifest
(Wave 5-C cross-library interop). Each expanded case produces a single
slide containing one auto-shape from a curated list of primitive MSO_SHAPE
presets (rect, ellipse, triangle, diamond, line, right-arrow). The
manifest asserts both that python-pptx writes the canonical
``<a:prstGeom prst=...>`` token AND that pptxjs emits a recognisable DOM
node for that shape.
"""

from __future__ import annotations

import argparse
import datetime as _dt
from pathlib import Path

from pptx import Presentation
from pptx.enum.shapes import MSO_SHAPE
from pptx.util import Inches

_REPO_ROOT = Path(__file__).resolve().parent.parent
_REPRODUCIBLE_DT = _dt.datetime(2000, 1, 1, 0, 0, 0)


def _write(preset_name: str, out: Path) -> None:
    shape_enum = getattr(MSO_SHAPE, preset_name)
    prs = Presentation()
    slide = prs.slides.add_slide(prs.slide_layouts[5])
    slide.shapes.add_shape(shape_enum, Inches(1), Inches(1), Inches(3), Inches(2))
    out.parent.mkdir(parents=True, exist_ok=True)
    prs.save(out, zip_date_time=_REPRODUCIBLE_DT)


def main() -> int:
    parser = argparse.ArgumentParser()
    parser.add_argument("--preset", required=True)
    parser.add_argument("--out", required=True)
    args = parser.parse_args()

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


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

Manifest (parent, unexpanded)

{
  "$schema": "../manifest.schema.json",
  "id": "pptx/interop-shape-roster",
  "kind": "parameterised",
  "title": "Cross-library shape roster (python-pptx -> pptxjs)",
  "format": "pptx",
  "category": "interop",
  "summary": "A curated roster of six primitive MSO_SHAPE preset geometries (rect, ellipse, triangle, diamond, right-triangle, right-arrow). python-pptx authors each fixture; pptxjs renders it. The manifest asserts both that the written XML carries the canonical <a:prstGeom prst=...> token AND that pptxjs produces a DOM node for the shape. Catches cases where python-pptx writes valid DrawingML but pptxjs renders nothing or drops the preset geometry.",
  "spec": {
    "source": "ecma-376-5-part-1",
    "clause": "20.1.9.18",
    "element": "a:prstGeom",
    "rnc_reference": "spec/ecma-376-5/part-1/rnc/DrawingML.rnc",
    "xsd_reference": "spec/ecma-376-5/part-1/xsd/dml-shape.xsd",
    "notes": "DrawingML <a:prstGeom prst=\"...\"/> selects one of the ~180 preset auto-shape geometries enumerated in ST_ShapeType. This interop manifest differs from `pptx/shape-preset-geometry` in two ways: (1) it covers a *curated primitive roster* instead of the full ~180-member enum — just the shapes that should be unambiguous to render; (2) it carries a `render_assertions` block that asserts the output pptxjs DOM, specifically targeting cross-library drift: python-pptx writes valid XML but pptxjs must render it as a visible shape node."
  },
  "fixtures": {
    "machine": "pptx/interop-shape-roster"
  },
  "generator": {
    "python": "scripts/gen_interop_shape_roster.py",
    "arg_template": "--preset {preset.mso} --out fixtures/pptx/interop-shape-roster--{preset.id}.pptx"
  },
  "parameters": {
    "preset": [
      {
        "id": "rect",
        "mso": "RECTANGLE",
        "prst": "rect"
      },
      {
        "id": "ellipse",
        "mso": "OVAL",
        "prst": "ellipse"
      },
      {
        "id": "triangle",
        "mso": "ISOSCELES_TRIANGLE",
        "prst": "triangle"
      },
      {
        "id": "right-triangle",
        "mso": "RIGHT_TRIANGLE",
        "prst": "rtTriangle"
      },
      {
        "id": "diamond",
        "mso": "DIAMOND",
        "prst": "diamond"
      },
      {
        "id": "right-arrow",
        "mso": "RIGHT_ARROW",
        "prst": "rightArrow"
      }
    ]
  },
  "assertions_template": [
    {
      "id": "prst-is-{preset.id}",
      "part": "ppt/slides/slide1.xml",
      "namespaces": {
        "p": "http://schemas.openxmlformats.org/presentationml/2006/main",
        "a": "http://schemas.openxmlformats.org/drawingml/2006/main"
      },
      "xpath": "//a:prstGeom/@prst",
      "must": "equal",
      "value": "{preset.prst}",
      "description": "The slide's auto-shape must declare <a:prstGeom prst=\"{preset.prst}\"/>."
    },
    {
      "id": "slide-has-sp-{preset.id}",
      "part": "ppt/slides/slide1.xml",
      "namespaces": {
        "p": "http://schemas.openxmlformats.org/presentationml/2006/main",
        "a": "http://schemas.openxmlformats.org/drawingml/2006/main"
      },
      "xpath": "//p:sp",
      "must": "exist",
      "description": "The slide must contain at least one <p:sp> shape element — the parent of prstGeom."
    }
  ],
  "render_assertions_template": [
    {
      "id": "interop-shape-{preset.id}-dom-present",
      "kind": "css_selector",
      "selector": "[data-shape-preset='{preset.prst}'], .pptx-shape, [data-kind='sp'], section[data-slide] *, section.slide *",
      "must": "exist",
      "description": "A DOM node representing the shape must exist in the pptxjs render (preferred: data-shape-preset='{preset.prst}'; fallback to any descendant under a slide section)."
    }
  ]
}