Skip to content

Commit 404f923

Browse files
MHoroszowskiclaude
andcommitted
feature: add Slide.is_hidden read/write property
Add the ability to get and set whether a slide is hidden from the presentation. Maps to the `show` attribute on the `<p:sld>` element, where show="0" means the slide is hidden. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 278b47b commit 404f923

6 files changed

Lines changed: 84 additions & 2 deletions

File tree

features/sld-slide.feature

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,22 @@ Feature: slide properties
1414
| an overridden |
1515

1616

17+
Scenario Outline: Slide.is_hidden
18+
Given a slide having <hidden-or-visible> visibility
19+
Then slide.is_hidden is <value>
20+
21+
Examples: Slide.is_hidden cases
22+
| hidden-or-visible | value |
23+
| visible | False |
24+
| hidden | True |
25+
26+
27+
Scenario: Slide.is_hidden setter
28+
Given a slide having visible visibility
29+
When I assign True to slide.is_hidden
30+
Then slide.is_hidden is True
31+
32+
1733
Scenario Outline: Slide.follow_master_background
1834
Given a Slide object having <default-or-overridden> background as slide
1935
Then slide.follow_master_background is <value>

features/steps/slide.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from __future__ import annotations
44

5-
from behave import given, then
5+
from behave import given, then, when
66
from helpers import test_pptx
77

88
from pptx import Presentation
@@ -28,6 +28,12 @@ def given_a_slide(context):
2828
context.slide = presentation.slides[0]
2929

3030

31+
@given("a slide having {visibility} visibility")
32+
def given_a_slide_having_visibility(context, visibility):
33+
slide_idx = {"visible": 0, "hidden": 1}[visibility]
34+
context.slide = Presentation(test_pptx("sld-slide-hidden")).slides[slide_idx]
35+
36+
3137
@given("a slide having a notes slide")
3238
def given_a_slide_having_a_notes_slide(context):
3339
context.slide = Presentation(test_pptx("sld-notes")).slides[0]
@@ -96,6 +102,14 @@ def given_a_SlideMaster_object_as_slide(context):
96102
context.slide = context.slide_master = prs.slide_masters[0]
97103

98104

105+
# when ====================================================
106+
107+
108+
@when("I assign {value} to slide.is_hidden")
109+
def when_I_assign_value_to_slide_is_hidden(context, value):
110+
context.slide.is_hidden = {"True": True, "False": False}[value]
111+
112+
99113
# then ====================================================
100114

101115

@@ -136,6 +150,13 @@ def then_slide_background_is_a_Background_object(context):
136150
assert cls_name == "_Background", "slide.background is a %s object" % cls_name
137151

138152

153+
@then("slide.is_hidden is {value}")
154+
def then_slide_is_hidden_is_value(context, value):
155+
expected_value = {"True": True, "False": False}[value]
156+
actual_value = context.slide.is_hidden
157+
assert actual_value is expected_value, "slide.is_hidden is %s" % actual_value
158+
159+
139160
@then("slide.follow_master_background is {value}")
140161
def then_slide_follow_master_background_is_value(context, value):
141162
expected_value = {"True": True, "False": False}[value]
28.4 KB
Binary file not shown.

src/pptx/oxml/slide.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from pptx.oxml import parse_from_template, parse_xml
88
from pptx.oxml.dml.fill import CT_GradientFillProperties
99
from pptx.oxml.ns import nsdecls
10-
from pptx.oxml.simpletypes import XsdString
10+
from pptx.oxml.simpletypes import XsdBoolean, XsdString
1111
from pptx.oxml.xmlchemy import (
1212
BaseOxmlElement,
1313
Choice,
@@ -164,6 +164,9 @@ class CT_Slide(_BaseSlideElement):
164164
clrMapOvr = ZeroOrOne("p:clrMapOvr", successors=_tag_seq[2:])
165165
timing = ZeroOrOne("p:timing", successors=_tag_seq[4:])
166166
del _tag_seq
167+
show: bool = OptionalAttribute( # pyright: ignore[reportAssignmentType]
168+
"show", XsdBoolean, default=True
169+
)
167170

168171
@classmethod
169172
def new(cls) -> CT_Slide:

src/pptx/slide.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,18 @@ class Slide(_BaseSlide):
178178

179179
part: SlidePart # pyright: ignore[reportIncompatibleMethodOverride]
180180

181+
@property
182+
def is_hidden(self) -> bool:
183+
"""`True` if this slide is hidden from the presentation, `False` otherwise.
184+
185+
Assigning `True` causes the slide to be hidden. Assigning `False` makes the slide visible.
186+
"""
187+
return not self._element.show
188+
189+
@is_hidden.setter
190+
def is_hidden(self, value: bool) -> None:
191+
self._element.show = not value
192+
181193
@property
182194
def follow_master_background(self):
183195
"""|True| if this slide inherits the slide master background.

tests/test_slide.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,36 @@ def it_provides_access_to_its_background(self, background_fixture):
309309
_BaseSlide_background_.assert_called_once_with()
310310
assert background is background_
311311

312+
@pytest.mark.parametrize(
313+
("sld_cxml", "expected_value"),
314+
[
315+
("p:sld/p:cSld", False),
316+
("p:sld{show=1}/p:cSld", False),
317+
("p:sld{show=0}/p:cSld", True),
318+
("p:sld{show=false}/p:cSld", True),
319+
("p:sld{show=true}/p:cSld", False),
320+
],
321+
)
322+
def it_knows_whether_it_is_hidden(self, sld_cxml: str, expected_value: bool):
323+
slide = Slide(element(sld_cxml), None)
324+
assert slide.is_hidden is expected_value
325+
326+
@pytest.mark.parametrize(
327+
("sld_cxml", "new_value", "expected_cxml"),
328+
[
329+
("p:sld/p:cSld", True, "p:sld{show=0}/p:cSld"),
330+
("p:sld/p:cSld", False, "p:sld/p:cSld"),
331+
("p:sld{show=0}/p:cSld", False, "p:sld/p:cSld"),
332+
("p:sld{show=0}/p:cSld", True, "p:sld{show=0}/p:cSld"),
333+
],
334+
)
335+
def it_can_change_whether_it_is_hidden(
336+
self, sld_cxml: str, new_value: bool, expected_cxml: str
337+
):
338+
slide = Slide(element(sld_cxml), None)
339+
slide.is_hidden = new_value
340+
assert slide._element.xml == xml(expected_cxml)
341+
312342
def it_knows_whether_it_follows_the_mstr_bkgd(self, follow_get_fixture):
313343
slide, expected_value = follow_get_fixture
314344
follows = slide.follow_master_background

0 commit comments

Comments
 (0)