Compose & Templates
power_pptx.compose covers JSON-first authoring with from_spec, and thePresentation methods import_slide / apply_template cover cross-presentation operations.
from_spec — JSON authoring
from power_pptx.compose import from_spec
prs = from_spec({
"slides": [
{"layout": "title",
"title": "Q4 Review",
"subtitle": "Engineering"},
{"layout": "bullets",
"title": "Highlights",
"bullets": ["Shipped v2.10", "Lint pass clean"]},
{"layout": "kpi",
"title": "Run-rate metrics",
"kpis": [{"label": "ARR", "value": "$4.2M", "delta": +0.08},
{"label": "NDR", "value": "131%", "delta": +0.03}]},
],
"lint": "raise", # built-in lint gate: raise | warn | off
})
prs.save("q4.pptx")With "lint": "raise" in the spec the build fails fast on geometry errors — ideal in CI or agent pipelines where a broken deck is worse than no deck.
Free-standing shapes on a spec slide
Layouts and recipes place their own shapes. When you need something a layout doesn't provide, a slide entry may carry a "shapes" list, applied after the layout runs:
prs = from_spec({
"slides": [
{"layout": "blank",
"shapes": [
{"name": "card", "shape": "rounded_rectangle",
"left": 1, "top": 1.4, "width": 4, "height": 2,
"layer": "card"},
{"name": "badge", "shape": "oval", "text": "NEW",
"left": 4.4, "top": 1.0, "width": 1.2, "height": 0.8,
"layer_above": "card"},
]},
],
})| Key | Meaning |
|---|---|
left / top / width / height | Required. Plain numbers are inches; pass a Length such as Inches(1.5) to opt out |
name | The shape's name, and the handle allow_overlap_with resolves against. Unique within the slide |
shape | An MSO_SHAPE member name, case- and separator-insensitive. Defaults to "textbox" |
text | Text for the shape's text frame |
lint_group / layer / layer_above / allow_overlap_with | The linter's intent declarations — see below |
Unknown keys are rejected with a did-you-mean hint rather than silently ignored, and every error names the offending entry as slides[i].shapes[j]. This is deliberately minimal — geometry, type, text, intent. It is not a drawing DSL; reach for the Python API when you need fills, effects, or anything structural.
Declaring intentional overlaps in a spec
This is what makes the list more than a convenience: a generator — an LLM, most usefully — can declare at generation time that an overlap is deliberate, so the deck it emits lints clean with no manual tagging pass afterwards. All three mechanisms from thelinter are spec-level fields:
{"name": "badge", ..., "lint_group": "kpi-1"} # n-ary tag
{"name": "badge", ..., "allow_overlap_with": "card"} # one pair
{"name": "badge", ..., "allow_overlap_with": ["card", "rule"]}
{"name": "card", ..., "layer": "card"} # asserts z-order
{"name": "badge", ..., "layer_above": "card"}allow_overlap_with names other shapes by their spec name, not by shape id — ids don't exist until the deck is built. Resolution happens in a second pass, after every shape on the slide exists, so a forward reference works: naming a shape defined later in the same list is fine. Names must be unique within a slide, and a reference may not cross slides, because an allowance is keyed on shape id and ids are only unique per slide. Both mistakes raise ValueError locating the bad entry.
import_slide — copy slides between decks
from power_pptx import Presentation
source = Presentation("template.pptx")
prs.import_slide(source.slides[2]) # deep-copies slide + related partsImage renames, layout references and master/theme parts are handled automatically;merge_master="dedupe" (the default) reuses an equivalent master in the destination,"clone" always brings a fresh copy.
apply_template
prs.apply_template("corporate.potx") # masters, layouts and themeRe-points every slide's layout/master/theme at the template's masters (name → type → first layout matching); slide content is preserved and unreferenced old parts are dropped on save.
When to use which
| Need | Use |
|---|---|
| Deck from LLM/DB/JSON output | from_spec |
| Reuse slides across decks | import_slide |
| Re-skin an existing deck | apply_template |
| Re-palette + re-font only | theme writer |