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.
Library verdicts: python-pptx: — pptxjs: —
| Feature id | pptx/interop-shape-roster--diamond |
|---|---|
| Format | pptx |
| Category | interop |
| Family | pptx/interop-shape-roster |
| Axis values | preset=diamond |
| Spec | ecma-376-5-part-1 § 20.1.9.18 a:prstGeom |
| ID / part | Predicate | XPath | python-pptx | pptxjs |
|---|---|---|---|---|
prst-is-diamondppt/slides/slide1.xml | equal = diamondThe slide's auto-shape must declare <a:prstGeom prst="diamond"/>. | //a:prstGeom/@prst | — | — |
slide-has-sp-diamondppt/slides/slide1.xml | existThe slide must contain at least one <p:sp> shape element — the parent of prstGeom. | //p:sp | — | — |
| ID | Predicate | Selector | python-pptx | pptxjs |
|---|---|---|---|---|
interop-shape-diamond-dom-present | css_selector/ existA DOM node representing the shape must exist in the pptxjs render (preferred: data-shape-preset='diamond'; fallback to any descendant under a slide section). | [data-shape-preset='diamond'], .pptx-shape, [data-kind='sp'], section[data-slide] *, section.slide * | — | — |
scripts/gen_interop_shape_roster.py
#!/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())
{
"$schema": "../manifest.schema.json",
"id": "pptx/interop-shape-roster--diamond",
"kind": "literal",
"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--diamond"
},
"generator": {
"python": "scripts/gen_interop_shape_roster.py",
"arg_template": "--preset {preset.mso} --out fixtures/pptx/interop-shape-roster--{preset.id}.pptx"
},
"_expansion": {
"parent_id": "pptx/interop-shape-roster",
"bindings": {
"preset": "diamond"
}
},
"assertions": [
{
"id": "prst-is-diamond",
"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": "diamond",
"description": "The slide's auto-shape must declare <a:prstGeom prst=\"diamond\"/>."
},
{
"id": "slide-has-sp-diamond",
"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": [
{
"id": "interop-shape-diamond-dom-present",
"kind": "css_selector",
"selector": "[data-shape-preset='diamond'], .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='diamond'; fallback to any descendant under a slide section)."
}
]
}
No rendered reference is available for this case.