A text run inside a textbox has its font size set via run.font.size = Pt(N); python-pptx emits <a:r>/<a:rPr sz="N*100"/> where sz is the point-size in hundredths of a point. This manifest is a parameterised family over 10 common point sizes: one manifest file expands into 10 cases, each backed by a distinct fixture pptx/font-size-sp--<id>.pptx generated from the same gen_font_size_sp.py script parameterised by --pt. The id suffix 'sp' disambiguates from the docx font-size family.
Library verdicts: python-pptx: — pptxjs: —
| Feature id | pptx/font-size-sp--pt8 |
|---|---|
| Format | pptx |
| Category | text-formatting |
| Family | pptx/font-size-sp |
| Axis values | size=pt8 |
| Spec | ecma-376-5-part-1 § 21.1.2.3.3 a:rPr |
| ID / part | Predicate | XPath | python-pptx | pptxjs |
|---|---|---|---|---|
font-size-sp-pt8ppt/slides/slide1.xml | equal = 800The textbox run's <a:rPr> must declare sz="800" (=8 pt in hundredths). | //p:sp[p:nvSpPr/p:cNvSpPr[@txBox='1']]//a:r/a:rPr/@sz | — | — |
No render assertions declared.
scripts/gen_font_size_sp.py
#!/usr/bin/env python3
"""Generate a single ``fixtures/pptx/font-size-sp--<id>.pptx`` fixture.
Parameterised generator for the ``pptx/font-size-sp`` manifest family.
The conformance runner invokes this script once per case with
``--pt <POINTS> --out <path>``.
Each invocation produces a single-slide presentation containing one
textbox whose single run has its font size set via ``run.font.size =
Pt(pt)``. The underlying XML is ``<p:txBody>/<a:p>/<a:r>/<a:rPr sz="..."/>``;
the manifest asserts the ``@sz`` attribute equals the point-value in
hundredths (e.g. 14 pt -> sz="1400").
"""
from __future__ import annotations
import argparse
import datetime as _dt
from pathlib import Path
from pptx import Presentation
from pptx.util import Inches, Pt
_REPO_ROOT = Path(__file__).resolve().parent.parent
_REPRODUCIBLE_DT = _dt.datetime(2000, 1, 1, 0, 0, 0)
def _write(pt: int, out: Path) -> None:
prs = Presentation()
# "Title Only" layout — an empty title placeholder plus our textbox.
slide = prs.slides.add_slide(prs.slide_layouts[5])
tb = slide.shapes.add_textbox(Inches(1), Inches(1), Inches(6), Inches(2))
tf = tb.text_frame
tf.text = f"Sized text {pt}pt"
tf.paragraphs[0].runs[0].font.size = Pt(pt)
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(
"--pt",
required=True,
type=int,
help="Font size in whole points.",
)
parser.add_argument(
"--out",
required=True,
help="Output fixture path (absolute or repo-relative).",
)
args = parser.parse_args()
out_path = Path(args.out)
if not out_path.is_absolute():
out_path = _REPO_ROOT / out_path
_write(args.pt, out_path)
print(out_path)
return 0
if __name__ == "__main__":
raise SystemExit(main())
{
"$schema": "../manifest.schema.json",
"id": "pptx/font-size-sp--pt8",
"kind": "literal",
"title": "Run-level font size (textbox)",
"format": "pptx",
"category": "text-formatting",
"summary": "A text run inside a textbox has its font size set via run.font.size = Pt(N); python-pptx emits <a:r>/<a:rPr sz=\"N*100\"/> where sz is the point-size in hundredths of a point. This manifest is a parameterised family over 10 common point sizes: one manifest file expands into 10 cases, each backed by a distinct fixture pptx/font-size-sp--<id>.pptx generated from the same gen_font_size_sp.py script parameterised by --pt. The id suffix 'sp' disambiguates from the docx font-size family.",
"spec": {
"source": "ecma-376-5-part-1",
"clause": "21.1.2.3.3",
"element": "a:rPr",
"rnc_reference": "spec/ecma-376-5/part-1/rnc/DrawingML.rnc",
"xsd_reference": "spec/ecma-376-5/part-1/xsd/dml-text.xsd",
"notes": "DrawingML <a:rPr> is the run-properties element inside <a:r>. Its @sz attribute is a ST_TextFontSize in hundredths of a point: an 8-pt run has sz=\"800\", 14 pt -> sz=\"1400\", 72 pt -> sz=\"7200\". python-pptx's ``run.font.size = Pt(n)`` computes this conversion and writes the @sz attribute. The assertion targets the run inside a textbox's <p:txBody>, avoiding matches against the slide's title placeholder run (which has no @sz)."
},
"fixtures": {
"machine": "pptx/font-size-sp--pt8"
},
"generator": {
"python": "scripts/gen_font_size_sp.py",
"arg_template": "--pt {size.pt} --out fixtures/pptx/font-size-sp--{size.id}.pptx"
},
"_expansion": {
"parent_id": "pptx/font-size-sp",
"bindings": {
"size": "pt8"
}
},
"assertions": [
{
"id": "font-size-sp-pt8",
"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[p:nvSpPr/p:cNvSpPr[@txBox='1']]//a:r/a:rPr/@sz",
"must": "equal",
"value": "800",
"description": "The textbox run's <a:rPr> must declare sz=\"800\" (=8 pt in hundredths)."
}
]
}
