Skip to content

Slide Masters, Layouts & .potx Templates — issue #19 epic#54

Merged
MHoroszowski merged 2 commits into
masterfrom
feature/masters-layouts-potx
May 17, 2026
Merged

Slide Masters, Layouts & .potx Templates — issue #19 epic#54
MHoroszowski merged 2 commits into
masterfrom
feature/masters-layouts-potx

Conversation

@MHoroszowski
Copy link
Copy Markdown
Owner

Summary

Resolves the entire #19 epic — slide masters, layouts and .potx
templates go from visible-but-frozen to first-class authorable surfaces.
All nine sub-features implemented additively (no public API removed or
changed), as manual semantic ports of upstream prior art onto our
ruff-formatted base (never git cherry-pick, per CONTRIBUTING §2).

Sub-feature Upstream prior art
SF1 Presentation('.potx') opens scanny#1071
SF2 Presentation.save_as_potx(file)
SF3 SlideLayouts.add_layout(name) scanny#1091 (also closes scanny#1044)
SF4 SlideLayouts.copy_from(other)
SF5 SlideMaster.shapes.add_* scanny#575
SF6 SlideLayout.placeholders.add(idx, ph_type, …)
SF7 Slide.slide_layout setter / apply_layout() scanny#1028
SF8 chart-into-placeholder (clean reject on non-chart) scanny#199
SF9 SlideMaster.get_layout(slide_layout_id, default=None) scanny#269

The defect visual verification caught (and why it matters)

The full test trinity was green — and PowerPoint still refused to open
the combined deck (repair dialog). Root cause: p:sldMasterId/@id,
p:sldLayoutId/@id and p:sldId/@id form one shared id pool in
PowerPoint's repair heuristic; new layout ids allocated from a low floor
(256) collided with the first slide's sldId (256). Fixed: all three
layout-id allocators now allocate high-range (>= 0x80000000,
max(existing)+1, uint32-ceiling-guarded). SF3 tests strengthened to
assert full shared-pool disjointness incl. sldId — the blind spot that
let a green suite ship a PowerPoint-rejecting file.

Tests

  • +54 unit tests (tests/test_issue19_masters_layouts.py, tests/test_api.py)
  • +9 behave scenarios (features/sld-add-layout.feature)
  • Trinity: pytest 3708 passed · ruff check clean · ruff format clean · behave 1057 scenarios 0 failed
python3 -m pytest tests/ -q | tail -1      → 3708 passed
ruff check src tests                       → All checks passed!
ruff format --check src tests              → 217 files already formatted
python3 -m behave features/ --no-color     → 1057 scenarios passed, 0 failed

Verification notes

  • SF1/SF2/SF3 visually verified in real PowerPoint (Interceptor).
  • SF7: implemented; the cross-master 2-master id-collision path is not
    unit-testable (no public 2-master construction API yet) — tested on
    single-master/multi-layout incl. anti-orphan; documented, not faked.
  • uat_issue19.py at repo root: 15/15 PASS (maintainer UAT signoff received).

Closes #19
Refs scanny#1071 scanny#1091 scanny#1044 scanny#575 scanny#1028 scanny#199 scanny#269

Resolves all nine sub-features of the #19 epic, additively, manual
semantic ports of upstream prior art (never cherry-pick; repo §2):

- SF1 .potx read: api.py _is_pptx_package allowlists PML_TEMPLATE_MAIN
  (port of scanny#1071). ValueError on .potx → opens.
- SF2 Presentation.save_as_potx(file): non-mutating content-type rewrite.
- SF3 SlideLayouts.add_layout(name): new <p:sldLayout> part + rels
  (port of scanny#1091; also closes upstream scanny#1044 via
  LayoutShapes→_BaseGroupShapes). Uses next_partname not len+1.
- SF4 SlideLayouts.copy_from(other): deep layout duplication, rel re-relate.
- SF5 SlideMaster.shapes.add_* : MasterShapes→_BaseGroupShapes.
- SF6 SlideLayout.placeholders.add(idx, ph_type, ...): dup-idx rejected.
- SF7 Slide.slide_layout setter / apply_layout(): cross-master rel repoint.
- SF8 chart-into-placeholder: clean TypeError on non-chart (scanny#199).
- SF9 SlideMaster.get_layout(slide_layout_id, default=None) (scanny#269).

ID-POOL FIX: _next_id now allocates high-range (>=0x80000000,
max(existing)+1) — a low-256 allocation collided with the first slide's
sldId(256) in PowerPoint's shared id pool and triggered the repair
dialog. Caught by Interceptor visual verification; the entire green
trinity missed it. SF3 tests strengthened to assert full-pool
disjointness (sldMasterId + sldId).

Tests: +54 pytest (tests/test_issue19_masters_layouts.py,
tests/test_api.py), +9 behave scenarios. Trinity green: pytest 3708,
ruff check + format clean, behave 1057 scenarios 0 failed.

uat_issue19.py authored (15/15 PASS as script-QA). Combined-deck
PowerPoint visual signoff deferred to maintainer UAT per repo §6a;
agent does not claim signoff.

Refs #19  Refs scanny#1071 scanny#1091 scanny#1044 scanny#199 scanny#269
…dit)

Cato cross-vendor audit flagged defect-instance vs defect-class scoping:
the id-pool fix landed only in CT_SlideLayoutIdList._next_id (the
reproduced path). The two parallel allocators used by the cross-package
append_from / SF7 path were correct only incidentally:

- _add_sldLayoutId_to_master: max(used+[2147483647])+1 — right floor by
  luck, no uint32 ceiling, no exhaustion handling.
- _renumber_sldLayoutIds: right floor, no ceiling guard in its loop.

Both now: floor at _OOXML_LAYOUT_ID_FLOOR (explicit, not magic 2147483647),
new shared _UINT32_MAX ceiling, scan-fallback on exhaustion — matching
CT_SlideLayoutIdList._next_id. Closes the defect class, not just the
instance the failing screenshot exposed.

Trinity still green: pytest 3708, ruff clean, behave 0 failed;
append_from/port/layout paths (304 tests) green.

Refs #19
@MHoroszowski MHoroszowski merged commit fed7e45 into master May 17, 2026
18 checks passed
@MHoroszowski MHoroszowski deleted the feature/masters-layouts-potx branch May 17, 2026 03:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add textbox to layout [Epic] Slide Masters, Layouts & .potx Templates

1 participant