aboutsummaryrefslogtreecommitdiff
path: root/.venv/lib/python3.12/site-packages/pptx/slide.py
diff options
context:
space:
mode:
authorS. Solomon Darnell2025-03-28 21:52:21 -0500
committerS. Solomon Darnell2025-03-28 21:52:21 -0500
commit4a52a71956a8d46fcb7294ac71734504bb09bcc2 (patch)
treeee3dc5af3b6313e921cd920906356f5d4febc4ed /.venv/lib/python3.12/site-packages/pptx/slide.py
parentcc961e04ba734dd72309fb548a2f97d67d578813 (diff)
downloadgn-ai-master.tar.gz
two version of R2R are hereHEADmaster
Diffstat (limited to '.venv/lib/python3.12/site-packages/pptx/slide.py')
-rw-r--r--.venv/lib/python3.12/site-packages/pptx/slide.py498
1 files changed, 498 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/pptx/slide.py b/.venv/lib/python3.12/site-packages/pptx/slide.py
new file mode 100644
index 00000000..3b1b65d8
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pptx/slide.py
@@ -0,0 +1,498 @@
+"""Slide-related objects, including masters, layouts, and notes."""
+
+from __future__ import annotations
+
+from typing import TYPE_CHECKING, Iterator, cast
+
+from pptx.dml.fill import FillFormat
+from pptx.enum.shapes import PP_PLACEHOLDER
+from pptx.shapes.shapetree import (
+ LayoutPlaceholders,
+ LayoutShapes,
+ MasterPlaceholders,
+ MasterShapes,
+ NotesSlidePlaceholders,
+ NotesSlideShapes,
+ SlidePlaceholders,
+ SlideShapes,
+)
+from pptx.shared import ElementProxy, ParentedElementProxy, PartElementProxy
+from pptx.util import lazyproperty
+
+if TYPE_CHECKING:
+ from pptx.oxml.presentation import CT_SlideIdList, CT_SlideMasterIdList
+ from pptx.oxml.slide import (
+ CT_CommonSlideData,
+ CT_NotesSlide,
+ CT_Slide,
+ CT_SlideLayoutIdList,
+ CT_SlideMaster,
+ )
+ from pptx.parts.presentation import PresentationPart
+ from pptx.parts.slide import SlideLayoutPart, SlideMasterPart, SlidePart
+ from pptx.presentation import Presentation
+ from pptx.shapes.placeholder import LayoutPlaceholder, MasterPlaceholder
+ from pptx.shapes.shapetree import NotesSlidePlaceholder
+ from pptx.text.text import TextFrame
+
+
+class _BaseSlide(PartElementProxy):
+ """Base class for slide objects, including masters, layouts and notes."""
+
+ _element: CT_Slide
+
+ @lazyproperty
+ def background(self) -> _Background:
+ """|_Background| object providing slide background properties.
+
+ This property returns a |_Background| object whether or not the
+ slide, master, or layout has an explicitly defined background.
+
+ The same |_Background| object is returned on every call for the same
+ slide object.
+ """
+ return _Background(self._element.cSld)
+
+ @property
+ def name(self) -> str:
+ """String representing the internal name of this slide.
+
+ Returns an empty string (`''`) if no name is assigned. Assigning an empty string or |None|
+ to this property causes any name to be removed.
+ """
+ return self._element.cSld.name
+
+ @name.setter
+ def name(self, value: str | None):
+ new_value = "" if value is None else value
+ self._element.cSld.name = new_value
+
+
+class _BaseMaster(_BaseSlide):
+ """Base class for master objects such as |SlideMaster| and |NotesMaster|.
+
+ Provides access to placeholders and regular shapes.
+ """
+
+ @lazyproperty
+ def placeholders(self) -> MasterPlaceholders:
+ """|MasterPlaceholders| collection of placeholder shapes in this master.
+
+ Sequence sorted in `idx` order.
+ """
+ return MasterPlaceholders(self._element.spTree, self)
+
+ @lazyproperty
+ def shapes(self):
+ """
+ Instance of |MasterShapes| containing sequence of shape objects
+ appearing on this slide.
+ """
+ return MasterShapes(self._element.spTree, self)
+
+
+class NotesMaster(_BaseMaster):
+ """Proxy for the notes master XML document.
+
+ Provides access to shapes, the most commonly used of which are placeholders.
+ """
+
+
+class NotesSlide(_BaseSlide):
+ """Notes slide object.
+
+ Provides access to slide notes placeholder and other shapes on the notes handout
+ page.
+ """
+
+ element: CT_NotesSlide # pyright: ignore[reportIncompatibleMethodOverride]
+
+ def clone_master_placeholders(self, notes_master: NotesMaster) -> None:
+ """Selectively add placeholder shape elements from `notes_master`.
+
+ Selected placeholder shape elements from `notes_master` are added to the shapes
+ collection of this notes slide. Z-order of placeholders is preserved. Certain
+ placeholders (header, date, footer) are not cloned.
+ """
+
+ def iter_cloneable_placeholders() -> Iterator[MasterPlaceholder]:
+ """Generate a reference to each cloneable placeholder in `notes_master`.
+
+ These are the placeholders that should be cloned to a notes slide when the a new notes
+ slide is created.
+ """
+ cloneable = (
+ PP_PLACEHOLDER.SLIDE_IMAGE,
+ PP_PLACEHOLDER.BODY,
+ PP_PLACEHOLDER.SLIDE_NUMBER,
+ )
+ for placeholder in notes_master.placeholders:
+ if placeholder.element.ph_type in cloneable:
+ yield placeholder
+
+ shapes = self.shapes
+ for placeholder in iter_cloneable_placeholders():
+ shapes.clone_placeholder(cast("LayoutPlaceholder", placeholder))
+
+ @property
+ def notes_placeholder(self) -> NotesSlidePlaceholder | None:
+ """the notes placeholder on this notes slide, the shape that contains the actual notes text.
+
+ Return |None| if no notes placeholder is present; while this is probably uncommon, it can
+ happen if the notes master does not have a body placeholder, or if the notes placeholder
+ has been deleted from the notes slide.
+ """
+ for placeholder in self.placeholders:
+ if placeholder.placeholder_format.type == PP_PLACEHOLDER.BODY:
+ return placeholder
+ return None
+
+ @property
+ def notes_text_frame(self) -> TextFrame | None:
+ """The text frame of the notes placeholder on this notes slide.
+
+ |None| if there is no notes placeholder. This is a shortcut to accommodate the common case
+ of simply adding "notes" text to the notes "page".
+ """
+ notes_placeholder = self.notes_placeholder
+ if notes_placeholder is None:
+ return None
+ return notes_placeholder.text_frame
+
+ @lazyproperty
+ def placeholders(self) -> NotesSlidePlaceholders:
+ """Instance of |NotesSlidePlaceholders| for this notes-slide.
+
+ Contains the sequence of placeholder shapes in this notes slide.
+ """
+ return NotesSlidePlaceholders(self.element.spTree, self)
+
+ @lazyproperty
+ def shapes(self) -> NotesSlideShapes:
+ """Sequence of shape objects appearing on this notes slide."""
+ return NotesSlideShapes(self._element.spTree, self)
+
+
+class Slide(_BaseSlide):
+ """Slide object. Provides access to shapes and slide-level properties."""
+
+ part: SlidePart # pyright: ignore[reportIncompatibleMethodOverride]
+
+ @property
+ def follow_master_background(self):
+ """|True| if this slide inherits the slide master background.
+
+ Assigning |False| causes background inheritance from the master to be
+ interrupted; if there is no custom background for this slide,
+ a default background is added. If a custom background already exists
+ for this slide, assigning |False| has no effect.
+
+ Assigning |True| causes any custom background for this slide to be
+ deleted and inheritance from the master restored.
+ """
+ return self._element.bg is None
+
+ @property
+ def has_notes_slide(self) -> bool:
+ """`True` if this slide has a notes slide, `False` otherwise.
+
+ A notes slide is created by :attr:`.notes_slide` when one doesn't exist; use this property
+ to test for a notes slide without the possible side effect of creating one.
+ """
+ return self.part.has_notes_slide
+
+ @property
+ def notes_slide(self) -> NotesSlide:
+ """The |NotesSlide| instance for this slide.
+
+ If the slide does not have a notes slide, one is created. The same single instance is
+ returned on each call.
+ """
+ return self.part.notes_slide
+
+ @lazyproperty
+ def placeholders(self) -> SlidePlaceholders:
+ """Sequence of placeholder shapes in this slide."""
+ return SlidePlaceholders(self._element.spTree, self)
+
+ @lazyproperty
+ def shapes(self) -> SlideShapes:
+ """Sequence of shape objects appearing on this slide."""
+ return SlideShapes(self._element.spTree, self)
+
+ @property
+ def slide_id(self) -> int:
+ """Integer value that uniquely identifies this slide within this presentation.
+
+ The slide id does not change if the position of this slide in the slide sequence is changed
+ by adding, rearranging, or deleting slides.
+ """
+ return self.part.slide_id
+
+ @property
+ def slide_layout(self) -> SlideLayout:
+ """|SlideLayout| object this slide inherits appearance from."""
+ return self.part.slide_layout
+
+
+class Slides(ParentedElementProxy):
+ """Sequence of slides belonging to an instance of |Presentation|.
+
+ Has list semantics for access to individual slides. Supports indexed access, len(), and
+ iteration.
+ """
+
+ part: PresentationPart # pyright: ignore[reportIncompatibleMethodOverride]
+
+ def __init__(self, sldIdLst: CT_SlideIdList, prs: Presentation):
+ super(Slides, self).__init__(sldIdLst, prs)
+ self._sldIdLst = sldIdLst
+
+ def __getitem__(self, idx: int) -> Slide:
+ """Provide indexed access, (e.g. 'slides[0]')."""
+ try:
+ sldId = self._sldIdLst.sldId_lst[idx]
+ except IndexError:
+ raise IndexError("slide index out of range")
+ return self.part.related_slide(sldId.rId)
+
+ def __iter__(self) -> Iterator[Slide]:
+ """Support iteration, e.g. `for slide in slides:`."""
+ for sldId in self._sldIdLst.sldId_lst:
+ yield self.part.related_slide(sldId.rId)
+
+ def __len__(self) -> int:
+ """Support len() built-in function, e.g. `len(slides) == 4`."""
+ return len(self._sldIdLst)
+
+ def add_slide(self, slide_layout: SlideLayout) -> Slide:
+ """Return a newly added slide that inherits layout from `slide_layout`."""
+ rId, slide = self.part.add_slide(slide_layout)
+ slide.shapes.clone_layout_placeholders(slide_layout)
+ self._sldIdLst.add_sldId(rId)
+ return slide
+
+ def get(self, slide_id: int, default: Slide | None = None) -> Slide | None:
+ """Return the slide identified by int `slide_id` in this presentation.
+
+ Returns `default` if not found.
+ """
+ slide = self.part.get_slide(slide_id)
+ if slide is None:
+ return default
+ return slide
+
+ def index(self, slide: Slide) -> int:
+ """Map `slide` to its zero-based position in this slide sequence.
+
+ Raises |ValueError| on *slide* not present.
+ """
+ for idx, this_slide in enumerate(self):
+ if this_slide == slide:
+ return idx
+ raise ValueError("%s is not in slide collection" % slide)
+
+
+class SlideLayout(_BaseSlide):
+ """Slide layout object.
+
+ Provides access to placeholders, regular shapes, and slide layout-level properties.
+ """
+
+ part: SlideLayoutPart # pyright: ignore[reportIncompatibleMethodOverride]
+
+ def iter_cloneable_placeholders(self) -> Iterator[LayoutPlaceholder]:
+ """Generate layout-placeholders on this slide-layout that should be cloned to a new slide.
+
+ Used when creating a new slide from this slide-layout.
+ """
+ latent_ph_types = (
+ PP_PLACEHOLDER.DATE,
+ PP_PLACEHOLDER.FOOTER,
+ PP_PLACEHOLDER.SLIDE_NUMBER,
+ )
+ for ph in self.placeholders:
+ if ph.element.ph_type not in latent_ph_types:
+ yield ph
+
+ @lazyproperty
+ def placeholders(self) -> LayoutPlaceholders:
+ """Sequence of placeholder shapes in this slide layout.
+
+ Placeholders appear in `idx` order.
+ """
+ return LayoutPlaceholders(self._element.spTree, self)
+
+ @lazyproperty
+ def shapes(self) -> LayoutShapes:
+ """Sequence of shapes appearing on this slide layout."""
+ return LayoutShapes(self._element.spTree, self)
+
+ @property
+ def slide_master(self) -> SlideMaster:
+ """Slide master from which this slide-layout inherits properties."""
+ return self.part.slide_master
+
+ @property
+ def used_by_slides(self):
+ """Tuple of slide objects based on this slide layout."""
+ # ---getting Slides collection requires going around the horn a bit---
+ slides = self.part.package.presentation_part.presentation.slides
+ return tuple(s for s in slides if s.slide_layout == self)
+
+
+class SlideLayouts(ParentedElementProxy):
+ """Sequence of slide layouts belonging to a slide-master.
+
+ Supports indexed access, len(), iteration, index() and remove().
+ """
+
+ part: SlideMasterPart # pyright: ignore[reportIncompatibleMethodOverride]
+
+ def __init__(self, sldLayoutIdLst: CT_SlideLayoutIdList, parent: SlideMaster):
+ super(SlideLayouts, self).__init__(sldLayoutIdLst, parent)
+ self._sldLayoutIdLst = sldLayoutIdLst
+
+ def __getitem__(self, idx: int) -> SlideLayout:
+ """Provides indexed access, e.g. `slide_layouts[2]`."""
+ try:
+ sldLayoutId = self._sldLayoutIdLst.sldLayoutId_lst[idx]
+ except IndexError:
+ raise IndexError("slide layout index out of range")
+ return self.part.related_slide_layout(sldLayoutId.rId)
+
+ def __iter__(self) -> Iterator[SlideLayout]:
+ """Generate each |SlideLayout| in the collection, in sequence."""
+ for sldLayoutId in self._sldLayoutIdLst.sldLayoutId_lst:
+ yield self.part.related_slide_layout(sldLayoutId.rId)
+
+ def __len__(self) -> int:
+ """Support len() built-in function, e.g. `len(slides) == 4`."""
+ return len(self._sldLayoutIdLst)
+
+ def get_by_name(self, name: str, default: SlideLayout | None = None) -> SlideLayout | None:
+ """Return SlideLayout object having `name`, or `default` if not found."""
+ for slide_layout in self:
+ if slide_layout.name == name:
+ return slide_layout
+ return default
+
+ def index(self, slide_layout: SlideLayout) -> int:
+ """Return zero-based index of `slide_layout` in this collection.
+
+ Raises `ValueError` if `slide_layout` is not present in this collection.
+ """
+ for idx, this_layout in enumerate(self):
+ if slide_layout == this_layout:
+ return idx
+ raise ValueError("layout not in this SlideLayouts collection")
+
+ def remove(self, slide_layout: SlideLayout) -> None:
+ """Remove `slide_layout` from the collection.
+
+ Raises ValueError when `slide_layout` is in use; a slide layout which is the basis for one
+ or more slides cannot be removed.
+ """
+ # ---raise if layout is in use---
+ if slide_layout.used_by_slides:
+ raise ValueError("cannot remove slide-layout in use by one or more slides")
+
+ # ---target layout is identified by its index in this collection---
+ target_idx = self.index(slide_layout)
+
+ # --remove layout from p:sldLayoutIds of its master
+ # --this stops layout from showing up, but doesn't remove it from package
+ target_sldLayoutId = self._sldLayoutIdLst.sldLayoutId_lst[target_idx]
+ self._sldLayoutIdLst.remove(target_sldLayoutId)
+
+ # --drop relationship from master to layout
+ # --this removes layout from package, along with everything (only) it refers to,
+ # --including images (not used elsewhere) and hyperlinks
+ slide_layout.slide_master.part.drop_rel(target_sldLayoutId.rId)
+
+
+class SlideMaster(_BaseMaster):
+ """Slide master object.
+
+ Provides access to slide layouts. Access to placeholders, regular shapes, and slide master-level
+ properties is inherited from |_BaseMaster|.
+ """
+
+ _element: CT_SlideMaster # pyright: ignore[reportIncompatibleVariableOverride]
+
+ @lazyproperty
+ def slide_layouts(self) -> SlideLayouts:
+ """|SlideLayouts| object providing access to this slide-master's layouts."""
+ return SlideLayouts(self._element.get_or_add_sldLayoutIdLst(), self)
+
+
+class SlideMasters(ParentedElementProxy):
+ """Sequence of |SlideMaster| objects belonging to a presentation.
+
+ Has list access semantics, supporting indexed access, len(), and iteration.
+ """
+
+ part: PresentationPart # pyright: ignore[reportIncompatibleMethodOverride]
+
+ def __init__(self, sldMasterIdLst: CT_SlideMasterIdList, parent: Presentation):
+ super(SlideMasters, self).__init__(sldMasterIdLst, parent)
+ self._sldMasterIdLst = sldMasterIdLst
+
+ def __getitem__(self, idx: int) -> SlideMaster:
+ """Provides indexed access, e.g. `slide_masters[2]`."""
+ try:
+ sldMasterId = self._sldMasterIdLst.sldMasterId_lst[idx]
+ except IndexError:
+ raise IndexError("slide master index out of range")
+ return self.part.related_slide_master(sldMasterId.rId)
+
+ def __iter__(self):
+ """Generate each |SlideMaster| instance in the collection, in sequence."""
+ for smi in self._sldMasterIdLst.sldMasterId_lst:
+ yield self.part.related_slide_master(smi.rId)
+
+ def __len__(self):
+ """Support len() built-in function, e.g. `len(slide_masters) == 4`."""
+ return len(self._sldMasterIdLst)
+
+
+class _Background(ElementProxy):
+ """Provides access to slide background properties.
+
+ Note that the presence of this object does not by itself imply an
+ explicitly-defined background; a slide with an inherited background still
+ has a |_Background| object.
+ """
+
+ def __init__(self, cSld: CT_CommonSlideData):
+ super(_Background, self).__init__(cSld)
+ self._cSld = cSld
+
+ @lazyproperty
+ def fill(self):
+ """|FillFormat| instance for this background.
+
+ This |FillFormat| object is used to interrogate or specify the fill
+ of the slide background.
+
+ Note that accessing this property is potentially destructive. A slide
+ background can also be specified by a background style reference and
+ accessing this property will remove that reference, if present, and
+ replace it with NoFill. This is frequently the case for a slide
+ master background.
+
+ This is also the case when there is no explicitly defined background
+ (background is inherited); merely accessing this property will cause
+ the background to be set to NoFill and the inheritance link will be
+ interrupted. This is frequently the case for a slide background.
+
+ Of course, if you are accessing this property in order to set the
+ fill, then these changes are of no consequence, but the existing
+ background cannot be reliably interrogated using this property unless
+ you have already established it is an explicit fill.
+
+ If the background is already a fill, then accessing this property
+ makes no changes to the current background.
+ """
+ bgPr = self._cSld.get_or_add_bgPr()
+ return FillFormat.from_fill_parent(bgPr)