python-pptx2 2.13.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (175) hide show
  1. pptx2/__init__.py +152 -0
  2. pptx2/_color.py +75 -0
  3. pptx2/_slide_importer.py +597 -0
  4. pptx2/_svg.py +155 -0
  5. pptx2/_template_applier.py +292 -0
  6. pptx2/_textstyle.py +187 -0
  7. pptx2/accessibility.py +365 -0
  8. pptx2/action.py +270 -0
  9. pptx2/animation.py +2237 -0
  10. pptx2/api.py +49 -0
  11. pptx2/audit.py +258 -0
  12. pptx2/chart/__init__.py +0 -0
  13. pptx2/chart/analytics.py +381 -0
  14. pptx2/chart/axis.py +543 -0
  15. pptx2/chart/category.py +200 -0
  16. pptx2/chart/chart.py +670 -0
  17. pptx2/chart/data.py +864 -0
  18. pptx2/chart/datalabel.py +406 -0
  19. pptx2/chart/legend.py +86 -0
  20. pptx2/chart/marker.py +70 -0
  21. pptx2/chart/palettes.py +129 -0
  22. pptx2/chart/plot.py +462 -0
  23. pptx2/chart/point.py +101 -0
  24. pptx2/chart/quick_layouts.py +325 -0
  25. pptx2/chart/series.py +334 -0
  26. pptx2/chart/xlsx.py +272 -0
  27. pptx2/chart/xmlwriter.py +1845 -0
  28. pptx2/compose/__init__.py +28 -0
  29. pptx2/compose/from_spec.py +1094 -0
  30. pptx2/design/__init__.py +8 -0
  31. pptx2/design/components.py +607 -0
  32. pptx2/design/figures.py +389 -0
  33. pptx2/design/layout.py +370 -0
  34. pptx2/design/recipes.py +1967 -0
  35. pptx2/design/style.py +209 -0
  36. pptx2/design/tokens.py +915 -0
  37. pptx2/diagrams.py +754 -0
  38. pptx2/dml/__init__.py +0 -0
  39. pptx2/dml/chtfmt.py +40 -0
  40. pptx2/dml/color.py +496 -0
  41. pptx2/dml/effect.py +909 -0
  42. pptx2/dml/fill.py +691 -0
  43. pptx2/dml/line.py +287 -0
  44. pptx2/dml/picture.py +212 -0
  45. pptx2/dml/three_d.py +381 -0
  46. pptx2/enum/__init__.py +0 -0
  47. pptx2/enum/action.py +71 -0
  48. pptx2/enum/animation.py +31 -0
  49. pptx2/enum/base.py +218 -0
  50. pptx2/enum/chart.py +574 -0
  51. pptx2/enum/dml.py +740 -0
  52. pptx2/enum/lang.py +685 -0
  53. pptx2/enum/presentation.py +133 -0
  54. pptx2/enum/shapes.py +1029 -0
  55. pptx2/enum/text.py +230 -0
  56. pptx2/exc.py +42 -0
  57. pptx2/formats.py +139 -0
  58. pptx2/geometry.py +420 -0
  59. pptx2/inherit.py +109 -0
  60. pptx2/lint.py +2256 -0
  61. pptx2/math.py +177 -0
  62. pptx2/media.py +197 -0
  63. pptx2/opc/__init__.py +0 -0
  64. pptx2/opc/constants.py +332 -0
  65. pptx2/opc/oxml.py +188 -0
  66. pptx2/opc/package.py +762 -0
  67. pptx2/opc/packuri.py +109 -0
  68. pptx2/opc/serialized.py +296 -0
  69. pptx2/opc/shared.py +20 -0
  70. pptx2/opc/spec.py +45 -0
  71. pptx2/oxml/__init__.py +555 -0
  72. pptx2/oxml/action.py +53 -0
  73. pptx2/oxml/chart/__init__.py +0 -0
  74. pptx2/oxml/chart/axis.py +337 -0
  75. pptx2/oxml/chart/chart.py +481 -0
  76. pptx2/oxml/chart/datalabel.py +253 -0
  77. pptx2/oxml/chart/legend.py +72 -0
  78. pptx2/oxml/chart/marker.py +61 -0
  79. pptx2/oxml/chart/plot.py +365 -0
  80. pptx2/oxml/chart/series.py +425 -0
  81. pptx2/oxml/chart/shared.py +220 -0
  82. pptx2/oxml/coreprops.py +288 -0
  83. pptx2/oxml/dml/__init__.py +0 -0
  84. pptx2/oxml/dml/color.py +135 -0
  85. pptx2/oxml/dml/effect.py +213 -0
  86. pptx2/oxml/dml/fill.py +316 -0
  87. pptx2/oxml/dml/line.py +12 -0
  88. pptx2/oxml/dml/three_d.py +110 -0
  89. pptx2/oxml/ns.py +135 -0
  90. pptx2/oxml/presentation.py +313 -0
  91. pptx2/oxml/shapes/__init__.py +19 -0
  92. pptx2/oxml/shapes/autoshape.py +467 -0
  93. pptx2/oxml/shapes/connector.py +107 -0
  94. pptx2/oxml/shapes/graphfrm.py +347 -0
  95. pptx2/oxml/shapes/groupshape.py +329 -0
  96. pptx2/oxml/shapes/picture.py +270 -0
  97. pptx2/oxml/shapes/shared.py +577 -0
  98. pptx2/oxml/simpletypes.py +1027 -0
  99. pptx2/oxml/slide.py +563 -0
  100. pptx2/oxml/table.py +650 -0
  101. pptx2/oxml/text.py +815 -0
  102. pptx2/oxml/theme.py +36 -0
  103. pptx2/oxml/xmlchemy.py +717 -0
  104. pptx2/package.py +222 -0
  105. pptx2/parts/__init__.py +0 -0
  106. pptx2/parts/chart.py +95 -0
  107. pptx2/parts/coreprops.py +167 -0
  108. pptx2/parts/diagram.py +37 -0
  109. pptx2/parts/embeddedpackage.py +93 -0
  110. pptx2/parts/image.py +275 -0
  111. pptx2/parts/media.py +37 -0
  112. pptx2/parts/presentation.py +136 -0
  113. pptx2/parts/slide.py +371 -0
  114. pptx2/presentation.py +408 -0
  115. pptx2/py.typed +0 -0
  116. pptx2/render.py +586 -0
  117. pptx2/section.py +272 -0
  118. pptx2/shapes/__init__.py +26 -0
  119. pptx2/shapes/autoshape.py +442 -0
  120. pptx2/shapes/base.py +1078 -0
  121. pptx2/shapes/connector.py +297 -0
  122. pptx2/shapes/freeform.py +337 -0
  123. pptx2/shapes/graphfrm.py +316 -0
  124. pptx2/shapes/group.py +264 -0
  125. pptx2/shapes/picture.py +422 -0
  126. pptx2/shapes/placeholder.py +468 -0
  127. pptx2/shapes/shapetree.py +2027 -0
  128. pptx2/shared.py +82 -0
  129. pptx2/skill/SKILL.md +450 -0
  130. pptx2/skill/__init__.py +78 -0
  131. pptx2/skill/__main__.py +64 -0
  132. pptx2/skill/references/animations.md +189 -0
  133. pptx2/skill/references/basics.md +421 -0
  134. pptx2/skill/references/charts.md +254 -0
  135. pptx2/skill/references/compose.md +234 -0
  136. pptx2/skill/references/design.md +366 -0
  137. pptx2/skill/references/effects.md +249 -0
  138. pptx2/skill/references/end-to-end-deck.md +231 -0
  139. pptx2/skill/references/geometry-and-arrows.md +334 -0
  140. pptx2/skill/references/lint.md +275 -0
  141. pptx2/skill/references/math.md +86 -0
  142. pptx2/skill/references/picture-effects.md +129 -0
  143. pptx2/skill/references/render.md +151 -0
  144. pptx2/skill/references/smart-art.md +75 -0
  145. pptx2/skill/references/space-aware-authoring.md +249 -0
  146. pptx2/skill/references/tables.md +244 -0
  147. pptx2/skill/references/theme.md +127 -0
  148. pptx2/skill/references/three-d.md +109 -0
  149. pptx2/skill/references/transitions.md +100 -0
  150. pptx2/slide.py +1244 -0
  151. pptx2/smart_art.py +220 -0
  152. pptx2/spec.py +633 -0
  153. pptx2/table.py +1181 -0
  154. pptx2/table_styles.py +184 -0
  155. pptx2/templates/default.pptx +0 -0
  156. pptx2/templates/docx-icon.emf +0 -0
  157. pptx2/templates/generic-icon.emf +0 -0
  158. pptx2/templates/notes.xml +23 -0
  159. pptx2/templates/notesMaster.xml +352 -0
  160. pptx2/templates/pptx-icon.emf +0 -0
  161. pptx2/templates/theme.xml +321 -0
  162. pptx2/templates/xlsx-icon.emf +0 -0
  163. pptx2/text/__init__.py +0 -0
  164. pptx2/text/fonts.py +482 -0
  165. pptx2/text/layout.py +374 -0
  166. pptx2/text/text.py +1272 -0
  167. pptx2/theme.py +721 -0
  168. pptx2/types.py +36 -0
  169. pptx2/util.py +263 -0
  170. python_pptx2-2.13.0.dist-info/METADATA +351 -0
  171. python_pptx2-2.13.0.dist-info/RECORD +175 -0
  172. python_pptx2-2.13.0.dist-info/WHEEL +5 -0
  173. python_pptx2-2.13.0.dist-info/entry_points.txt +3 -0
  174. python_pptx2-2.13.0.dist-info/licenses/LICENSE +22 -0
  175. python_pptx2-2.13.0.dist-info/top_level.txt +1 -0
pptx2/section.py ADDED
@@ -0,0 +1,272 @@
1
+ """Sections API — named groupings of slides in the slide-sorter/outline pane.
2
+
3
+ Sections are stored as a PowerPoint-2010 extension on the presentation part
4
+ (``p:presentation/p:extLst/p:ext[@uri="{521415D9-...}"]/p14:sectionLst``). A
5
+ section references its member slides by their numeric ``p:sldId/@id`` value
6
+ (not the relationship id).
7
+
8
+ The public entry point is :attr:`pptx2.presentation.Presentation.sections`,
9
+ which returns a :class:`Sections` collection. Typical use::
10
+
11
+ prs.sections.add("Intro", start_slide_index=0)
12
+ prs.sections.add("Body", start_slide_index=2)
13
+ for section in prs.sections:
14
+ print(section.name, [s.slide_id for s in section.slides])
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ import re
20
+ from typing import TYPE_CHECKING, Iterator
21
+
22
+ from pptx2.oxml.ns import qn
23
+ from pptx2.shared import ParentedElementProxy
24
+
25
+ if TYPE_CHECKING:
26
+ from pptx2.oxml.presentation import (
27
+ CT_Presentation,
28
+ CT_Section,
29
+ )
30
+ from pptx2.parts.presentation import PresentationPart
31
+ from pptx2.presentation import Presentation
32
+ from pptx2.slide import Slide
33
+
34
+ # -- brace-wrapped GUID, the lexical form ST_Guid requires for `p14:section/@id` --
35
+ _GUID_RE = re.compile(
36
+ r"^\{[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}"
37
+ r"-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}\}$"
38
+ )
39
+
40
+
41
+ def _remove_section_element(section_elm: CT_Section) -> None:
42
+ """Remove *section_elm*, keeping the section list a complete partition.
43
+
44
+ PowerPoint keeps every slide in exactly one section whenever a section
45
+ list exists, so the removed section's member slides are merged into the
46
+ previous section (or the next one when the first section is removed) —
47
+ the same behaviour as PowerPoint's own "Remove Section" command.
48
+ Removing the *only* section drops the whole `p14:sectionLst` extension
49
+ instead: an empty `<p14:sectionLst/>` violates CT_SectionList
50
+ (`minOccurs="1"` on `section`) and the deck simply becomes unsectioned.
51
+ """
52
+ sectionLst = section_elm.getparent()
53
+ if sectionLst is None:
54
+ return
55
+ siblings = list(sectionLst)
56
+ idx = siblings.index(section_elm)
57
+ member_ids = [sldId.id for sldId in section_elm.sldId_lst]
58
+
59
+ if len(siblings) == 1:
60
+ ext = sectionLst.getparent() # the `p:ext` carrying the extension
61
+ extLst = ext.getparent() if ext is not None else None
62
+ if ext is not None and extLst is not None:
63
+ extLst.remove(ext)
64
+ if len(extLst) == 0:
65
+ prs_elm = extLst.getparent()
66
+ if prs_elm is not None:
67
+ prs_elm.remove(extLst)
68
+ return
69
+
70
+ sectionLst.remove(section_elm)
71
+ if not member_ids:
72
+ return
73
+ if idx > 0:
74
+ # Merge into the previous section: its slides now precede these.
75
+ for slide_id in member_ids:
76
+ siblings[idx - 1].add_sldId(slide_id)
77
+ else:
78
+ # The first section was removed: its slides precede the (new) first
79
+ # section's members, so prepend in order.
80
+ target_lst = siblings[1].get_or_add_sldIdLst()
81
+ for pos, slide_id in enumerate(member_ids):
82
+ entry = target_lst.makeelement(qn("p14:sldId"), {"id": str(slide_id)})
83
+ target_lst.insert(pos, entry)
84
+
85
+
86
+ class Sections(ParentedElementProxy):
87
+ """Sequence of |Section| objects belonging to a |Presentation|.
88
+
89
+ Supports ``len()``, indexed access, and iteration. Reading the
90
+ collection never modifies the deck; the underlying PowerPoint-2010
91
+ extension element is created only when the first section is added.
92
+ """
93
+
94
+ part: PresentationPart # pyright: ignore[reportIncompatibleMethodOverride]
95
+
96
+ def __init__(self, prs_elm: CT_Presentation, prs: Presentation):
97
+ super(Sections, self).__init__(prs_elm, prs)
98
+ self._prs_elm = prs_elm
99
+ self._prs = prs
100
+
101
+ @property
102
+ def _section_elms(self) -> list[CT_Section]:
103
+ """The `p14:section` elements, or an empty list when unsectioned."""
104
+ sectionLst = self._prs_elm.sectionLst
105
+ if sectionLst is None:
106
+ return []
107
+ return sectionLst.section_lst
108
+
109
+ def __getitem__(self, idx: int) -> Section:
110
+ """Provide indexed access, e.g. ``prs.sections[0]``."""
111
+ try:
112
+ section = self._section_elms[idx]
113
+ except IndexError:
114
+ raise IndexError("section index out of range")
115
+ return Section(section, self._prs)
116
+
117
+ def __iter__(self) -> Iterator[Section]:
118
+ """Support iteration, e.g. ``for section in prs.sections:``."""
119
+ for section in self._section_elms:
120
+ yield Section(section, self._prs)
121
+
122
+ def __len__(self) -> int:
123
+ """Support ``len()`` built-in, e.g. ``len(prs.sections)``."""
124
+ return len(self._section_elms)
125
+
126
+ def add(
127
+ self,
128
+ name: str,
129
+ start_slide_index: int | None = None,
130
+ *,
131
+ id: str | None = None,
132
+ ) -> Section:
133
+ """Append a new |Section| named `name` and return it.
134
+
135
+ When `start_slide_index` is given, every slide from that zero-based
136
+ position to the end of the deck becomes a member of the new section
137
+ (the natural PowerPoint behaviour for a section that begins at a given
138
+ slide). PowerPoint sections are contiguous and non-overlapping, so
139
+ those slides are also *removed* from any earlier section that claimed
140
+ them — a new section beginning at slide N truncates the prior section
141
+ at N-1. When the *first* section of the deck starts beyond slide 0,
142
+ the slides before it are grouped into an auto-created "Default
143
+ Section" (mirroring PowerPoint, which never leaves a slide outside
144
+ every section). When `start_slide_index` is omitted, the section is
145
+ created empty.
146
+
147
+ `id` optionally fixes the section's brace-wrapped GUID; supplying it
148
+ keeps output deterministic for tests. A random GUID is generated
149
+ otherwise. A malformed or already-used id raises |ValueError| —
150
+ `p14:section/@id` is an ST_Guid and PowerPoint repairs decks whose
151
+ section ids are not unique GUIDs.
152
+ """
153
+ if id is not None:
154
+ if not _GUID_RE.match(id):
155
+ raise ValueError(
156
+ "section id must be a brace-wrapped GUID like "
157
+ "'{3E86B4F5-40E6-4F32-8B4D-BE3E1E4C8A27}'; got %r" % (id,)
158
+ )
159
+ if any(s.id.lower() == id.lower() for s in self._section_elms):
160
+ raise ValueError("section id %s is already used in this deck" % id)
161
+
162
+ was_unsectioned = not self._section_elms
163
+ sectionLst = self._prs_elm.get_or_add_sectionLst()
164
+ section_elm = sectionLst.add_section(name, section_id=id)
165
+ section = Section(section_elm, self._prs)
166
+ if start_slide_index is not None:
167
+ slides = list(self._prs.slides)
168
+ claimed = slides[start_slide_index:]
169
+ # Sections don't overlap: take the claimed slides away from any
170
+ # earlier section before assigning them to the new one.
171
+ for other in self:
172
+ if other._element is section_elm:
173
+ continue
174
+ for slide in claimed:
175
+ other.remove_slide(slide)
176
+ for slide in claimed:
177
+ section.add_slide(slide)
178
+ # First section of the deck starting beyond slide 0: cover the
179
+ # preceding slides so the section list partitions the whole deck.
180
+ if was_unsectioned and start_slide_index > 0:
181
+ default_elm = sectionLst.add_section("Default Section")
182
+ section_elm.addprevious(default_elm)
183
+ default = Section(default_elm, self._prs)
184
+ for slide in slides[:start_slide_index]:
185
+ default.add_slide(slide)
186
+ return section
187
+
188
+ def remove(self, section: Section) -> None:
189
+ """Remove `section` from this collection.
190
+
191
+ Slides referenced by the section are not deleted from the deck; they
192
+ are merged into the neighbouring section (previous when one exists,
193
+ else next), matching PowerPoint's "Remove Section" command. Removing
194
+ the only section removes the section grouping entirely.
195
+ """
196
+ _remove_section_element(section._element)
197
+
198
+
199
+ class Section(ParentedElementProxy):
200
+ """A single named section grouping a contiguous run of slides."""
201
+
202
+ part: PresentationPart # pyright: ignore[reportIncompatibleMethodOverride]
203
+
204
+ def __init__(self, section: CT_Section, prs: Presentation):
205
+ super(Section, self).__init__(section, prs)
206
+ self._section = section
207
+ self._prs = prs
208
+
209
+ @property
210
+ def id(self) -> str:
211
+ """The section's brace-wrapped GUID identifier (read-only)."""
212
+ return self._section.id
213
+
214
+ @property
215
+ def name(self) -> str:
216
+ """The user-visible section name. Read/write."""
217
+ return self._section.name
218
+
219
+ @name.setter
220
+ def name(self, value: str) -> None:
221
+ self._section.name = value
222
+
223
+ @property
224
+ def slide_ids(self) -> list[int]:
225
+ """List of numeric slide ids (``p:sldId/@id``) belonging to this section."""
226
+ return [sldId.id for sldId in self._section.sldId_lst]
227
+
228
+ @property
229
+ def slides(self) -> tuple[Slide, ...]:
230
+ """Tuple of |Slide| objects belonging to this section.
231
+
232
+ Member references whose slide is no longer present in the deck are
233
+ silently skipped.
234
+ """
235
+ result: list[Slide] = []
236
+ for slide_id in self.slide_ids:
237
+ slide = self.part.get_slide(slide_id)
238
+ if slide is not None:
239
+ result.append(slide)
240
+ return tuple(result)
241
+
242
+ def add_slide(self, slide: Slide) -> None:
243
+ """Add `slide` to this section's membership (idempotent).
244
+
245
+ Sections are non-overlapping — PowerPoint repairs a deck whose
246
+ section list references one slide twice — so the slide is first
247
+ removed from any other section that claims it.
248
+ """
249
+ slide_id = slide.slide_id
250
+ if slide_id in self.slide_ids:
251
+ return
252
+ sectionLst = self._section.getparent()
253
+ if sectionLst is not None:
254
+ for sibling in sectionLst:
255
+ if sibling is self._section:
256
+ continue
257
+ sibling.remove_sldId(slide_id)
258
+ self._section.add_sldId(slide_id)
259
+
260
+ def remove_slide(self, slide: Slide) -> None:
261
+ """Remove `slide` from this section's membership (no-op if absent)."""
262
+ self._section.remove_sldId(slide.slide_id)
263
+
264
+ def delete(self) -> None:
265
+ """Remove this section from the presentation.
266
+
267
+ The member slides themselves are left in the deck; they are merged
268
+ into the neighbouring section (previous when one exists, else next)
269
+ so the section list stays a complete partition. Deleting the only
270
+ section removes the section grouping entirely.
271
+ """
272
+ _remove_section_element(self._section)
@@ -0,0 +1,26 @@
1
+ """Objects used across sub-package."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING
6
+
7
+ if TYPE_CHECKING:
8
+ from pptx2.opc.package import XmlPart
9
+ from pptx2.types import ProvidesPart
10
+
11
+
12
+ class Subshape(object):
13
+ """Provides access to the containing part for drawing elements that occur below a shape.
14
+
15
+ Access to the part is required for example to add or drop a relationship. Provides
16
+ `self._parent` attribute to subclasses.
17
+ """
18
+
19
+ def __init__(self, parent: ProvidesPart):
20
+ super(Subshape, self).__init__()
21
+ self._parent = parent
22
+
23
+ @property
24
+ def part(self) -> XmlPart:
25
+ """The package part containing this object."""
26
+ return self._parent.part