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
@@ -0,0 +1,288 @@
1
+ """lxml custom element classes for core properties-related XML elements."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import datetime as dt
6
+ import re
7
+ from typing import Callable, cast
8
+
9
+ from lxml.etree import _Element # pyright: ignore[reportPrivateUsage]
10
+
11
+ from pptx2.oxml import parse_xml
12
+ from pptx2.oxml.ns import nsdecls, qn
13
+ from pptx2.oxml.xmlchemy import BaseOxmlElement, ZeroOrOne
14
+
15
+
16
+ class CT_CoreProperties(BaseOxmlElement):
17
+ """`cp:coreProperties` element.
18
+
19
+ The root element of the Core Properties part stored as `/docProps/core.xml`. Implements many
20
+ of the Dublin Core document metadata elements. String elements resolve to an empty string ('')
21
+ if the element is not present in the XML. String elements are limited in length to 255 unicode
22
+ characters.
23
+ """
24
+
25
+ get_or_add_revision: Callable[[], _Element]
26
+
27
+ category = ZeroOrOne("cp:category", successors=())
28
+ contentStatus = ZeroOrOne("cp:contentStatus", successors=())
29
+ created = ZeroOrOne("dcterms:created", successors=())
30
+ creator = ZeroOrOne("dc:creator", successors=())
31
+ description = ZeroOrOne("dc:description", successors=())
32
+ identifier = ZeroOrOne("dc:identifier", successors=())
33
+ keywords = ZeroOrOne("cp:keywords", successors=())
34
+ language = ZeroOrOne("dc:language", successors=())
35
+ lastModifiedBy = ZeroOrOne("cp:lastModifiedBy", successors=())
36
+ lastPrinted = ZeroOrOne("cp:lastPrinted", successors=())
37
+ modified = ZeroOrOne("dcterms:modified", successors=())
38
+ revision: _Element | None = ZeroOrOne( # pyright: ignore[reportAssignmentType]
39
+ "cp:revision", successors=()
40
+ )
41
+ subject = ZeroOrOne("dc:subject", successors=())
42
+ title = ZeroOrOne("dc:title", successors=())
43
+ version = ZeroOrOne("cp:version", successors=())
44
+
45
+ _coreProperties_tmpl = "<cp:coreProperties %s/>\n" % nsdecls("cp", "dc", "dcterms")
46
+
47
+ @staticmethod
48
+ def new_coreProperties() -> CT_CoreProperties:
49
+ """Return a new `cp:coreProperties` element"""
50
+ return cast(CT_CoreProperties, parse_xml(CT_CoreProperties._coreProperties_tmpl))
51
+
52
+ @property
53
+ def author_text(self) -> str:
54
+ return self._text_of_element("creator")
55
+
56
+ @author_text.setter
57
+ def author_text(self, value: str):
58
+ self._set_element_text("creator", value)
59
+
60
+ @property
61
+ def category_text(self) -> str:
62
+ return self._text_of_element("category")
63
+
64
+ @category_text.setter
65
+ def category_text(self, value: str):
66
+ self._set_element_text("category", value)
67
+
68
+ @property
69
+ def comments_text(self) -> str:
70
+ return self._text_of_element("description")
71
+
72
+ @comments_text.setter
73
+ def comments_text(self, value: str):
74
+ self._set_element_text("description", value)
75
+
76
+ @property
77
+ def contentStatus_text(self) -> str:
78
+ return self._text_of_element("contentStatus")
79
+
80
+ @contentStatus_text.setter
81
+ def contentStatus_text(self, value: str):
82
+ self._set_element_text("contentStatus", value)
83
+
84
+ @property
85
+ def created_datetime(self):
86
+ return self._datetime_of_element("created")
87
+
88
+ @created_datetime.setter
89
+ def created_datetime(self, value: dt.datetime):
90
+ self._set_element_datetime("created", value)
91
+
92
+ @property
93
+ def identifier_text(self) -> str:
94
+ return self._text_of_element("identifier")
95
+
96
+ @identifier_text.setter
97
+ def identifier_text(self, value: str):
98
+ self._set_element_text("identifier", value)
99
+
100
+ @property
101
+ def keywords_text(self) -> str:
102
+ return self._text_of_element("keywords")
103
+
104
+ @keywords_text.setter
105
+ def keywords_text(self, value: str):
106
+ self._set_element_text("keywords", value)
107
+
108
+ @property
109
+ def language_text(self) -> str:
110
+ return self._text_of_element("language")
111
+
112
+ @language_text.setter
113
+ def language_text(self, value: str):
114
+ self._set_element_text("language", value)
115
+
116
+ @property
117
+ def lastModifiedBy_text(self) -> str:
118
+ return self._text_of_element("lastModifiedBy")
119
+
120
+ @lastModifiedBy_text.setter
121
+ def lastModifiedBy_text(self, value: str):
122
+ self._set_element_text("lastModifiedBy", value)
123
+
124
+ @property
125
+ def lastPrinted_datetime(self):
126
+ return self._datetime_of_element("lastPrinted")
127
+
128
+ @lastPrinted_datetime.setter
129
+ def lastPrinted_datetime(self, value: dt.datetime):
130
+ self._set_element_datetime("lastPrinted", value)
131
+
132
+ @property
133
+ def modified_datetime(self):
134
+ return self._datetime_of_element("modified")
135
+
136
+ @modified_datetime.setter
137
+ def modified_datetime(self, value: dt.datetime):
138
+ self._set_element_datetime("modified", value)
139
+
140
+ @property
141
+ def revision_number(self) -> int:
142
+ """Integer value of revision property."""
143
+ revision = self.revision
144
+ if revision is None:
145
+ return 0
146
+ revision_str = revision.text
147
+ if revision_str is None:
148
+ return 0
149
+ try:
150
+ revision = int(revision_str)
151
+ except ValueError:
152
+ # -- non-integer revision strings also resolve to 0 --
153
+ return 0
154
+ # -- as do negative integers --
155
+ if revision < 0:
156
+ return 0
157
+ return revision
158
+
159
+ @revision_number.setter
160
+ def revision_number(self, value: int):
161
+ """Set revision property to string value of integer `value`."""
162
+ if not isinstance(value, int) or value < 1: # pyright: ignore[reportUnnecessaryIsInstance]
163
+ tmpl = "revision property requires positive int, got '%s'"
164
+ raise ValueError(tmpl % value)
165
+ revision = self.get_or_add_revision()
166
+ revision.text = str(value)
167
+
168
+ @property
169
+ def subject_text(self) -> str:
170
+ return self._text_of_element("subject")
171
+
172
+ @subject_text.setter
173
+ def subject_text(self, value: str):
174
+ self._set_element_text("subject", value)
175
+
176
+ @property
177
+ def title_text(self) -> str:
178
+ return self._text_of_element("title")
179
+
180
+ @title_text.setter
181
+ def title_text(self, value: str):
182
+ self._set_element_text("title", value)
183
+
184
+ @property
185
+ def version_text(self) -> str:
186
+ return self._text_of_element("version")
187
+
188
+ @version_text.setter
189
+ def version_text(self, value: str):
190
+ self._set_element_text("version", value)
191
+
192
+ def _datetime_of_element(self, property_name: str) -> dt.datetime | None:
193
+ element = cast("_Element | None", getattr(self, property_name))
194
+ if element is None:
195
+ return None
196
+ datetime_str = element.text
197
+ if datetime_str is None:
198
+ return None
199
+ try:
200
+ return self._parse_W3CDTF_to_datetime(datetime_str)
201
+ except ValueError:
202
+ # invalid datetime strings are ignored
203
+ return None
204
+
205
+ def _get_or_add(self, prop_name: str):
206
+ """Return element returned by 'get_or_add_' method for `prop_name`."""
207
+ get_or_add_method_name = "get_or_add_%s" % prop_name
208
+ get_or_add_method = getattr(self, get_or_add_method_name)
209
+ element = get_or_add_method()
210
+ return element
211
+
212
+ @classmethod
213
+ def _offset_dt(cls, datetime: dt.datetime, offset_str: str):
214
+ """Return |datetime| instance offset from `datetime` by offset specified in `offset_str`.
215
+
216
+ `offset_str` is a string like `'-07:00'`.
217
+ """
218
+ match = cls._offset_pattern.match(offset_str)
219
+ if match is None:
220
+ raise ValueError(f"{repr(offset_str)} is not a valid offset string")
221
+ sign, hours_str, minutes_str = match.groups()
222
+ sign_factor = -1 if sign == "+" else 1
223
+ hours = int(hours_str) * sign_factor
224
+ minutes = int(minutes_str) * sign_factor
225
+ td = dt.timedelta(hours=hours, minutes=minutes)
226
+ return datetime + td
227
+
228
+ _offset_pattern = re.compile(r"([+-])(\d\d):(\d\d)")
229
+
230
+ @classmethod
231
+ def _parse_W3CDTF_to_datetime(cls, w3cdtf_str: str) -> dt.datetime:
232
+ # valid W3CDTF date cases:
233
+ # yyyy e.g. '2003'
234
+ # yyyy-mm e.g. '2003-12'
235
+ # yyyy-mm-dd e.g. '2003-12-31'
236
+ # UTC timezone e.g. '2003-12-31T10:14:55Z'
237
+ # numeric timezone e.g. '2003-12-31T10:14:55-08:00'
238
+ templates = ("%Y-%m-%dT%H:%M:%S", "%Y-%m-%d", "%Y-%m", "%Y")
239
+ # strptime isn't smart enough to parse literal timezone offsets like
240
+ # '-07:30', so we have to do it ourselves
241
+ parseable_part = w3cdtf_str[:19]
242
+ offset_str = w3cdtf_str[19:]
243
+ timestamp = None
244
+ for tmpl in templates:
245
+ try:
246
+ timestamp = dt.datetime.strptime(parseable_part, tmpl)
247
+ except ValueError:
248
+ continue
249
+ if timestamp is None:
250
+ tmpl = "could not parse W3CDTF datetime string '%s'"
251
+ raise ValueError(tmpl % w3cdtf_str)
252
+ if len(offset_str) == 6:
253
+ return cls._offset_dt(timestamp, offset_str)
254
+ return timestamp
255
+
256
+ def _set_element_datetime(self, prop_name: str, value: dt.datetime) -> None:
257
+ """Set date/time value of child element having `prop_name` to `value`."""
258
+ if not isinstance(value, dt.datetime): # pyright: ignore[reportUnnecessaryIsInstance]
259
+ tmpl = "property requires <type 'datetime.datetime'> object, got %s"
260
+ raise ValueError(tmpl % type(value))
261
+ element = self._get_or_add(prop_name)
262
+ dt_str = value.strftime("%Y-%m-%dT%H:%M:%SZ")
263
+ element.text = dt_str
264
+ if prop_name in ("created", "modified"):
265
+ # These two require an explicit 'xsi:type="dcterms:W3CDTF"'
266
+ # attribute. The first and last line are a hack required to add
267
+ # the xsi namespace to the root element rather than each child
268
+ # element in which it is referenced
269
+ self.set(qn("xsi:foo"), "bar")
270
+ element.set(qn("xsi:type"), "dcterms:W3CDTF")
271
+ del self.attrib[qn("xsi:foo")]
272
+
273
+ def _set_element_text(self, prop_name: str, value: str) -> None:
274
+ """Set string value of `name` property to `value`."""
275
+ value = str(value)
276
+ if len(value) > 255:
277
+ tmpl = "exceeded 255 char limit for property, got:\n\n'%s'"
278
+ raise ValueError(tmpl % value)
279
+ element = self._get_or_add(prop_name)
280
+ element.text = value
281
+
282
+ def _text_of_element(self, property_name: str) -> str:
283
+ element = getattr(self, property_name)
284
+ if element is None:
285
+ return ""
286
+ if element.text is None:
287
+ return ""
288
+ return element.text
File without changes
@@ -0,0 +1,135 @@
1
+ """lxml custom element classes for DrawingML-related XML elements."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pptx2.enum.dml import MSO_THEME_COLOR
6
+ from pptx2.oxml.simpletypes import ST_HexColorRGB, ST_Percentage, ST_PositiveFixedPercentage
7
+ from pptx2.oxml.xmlchemy import (
8
+ BaseOxmlElement,
9
+ Choice,
10
+ RequiredAttribute,
11
+ ZeroOrOne,
12
+ ZeroOrOneChoice,
13
+ )
14
+
15
+
16
+ class _BaseColorElement(BaseOxmlElement):
17
+ """
18
+ Base class for <a:srgbClr> and <a:schemeClr> elements.
19
+ """
20
+
21
+ lumMod = ZeroOrOne("a:lumMod")
22
+ lumOff = ZeroOrOne("a:lumOff")
23
+ alpha = ZeroOrOne("a:alpha")
24
+
25
+ def add_lumMod(self, value):
26
+ """
27
+ Return a newly added <a:lumMod> child element.
28
+ """
29
+ lumMod = self._add_lumMod()
30
+ lumMod.val = value
31
+ return lumMod
32
+
33
+ def add_lumOff(self, value):
34
+ """
35
+ Return a newly added <a:lumOff> child element.
36
+ """
37
+ lumOff = self._add_lumOff()
38
+ lumOff.val = value
39
+ return lumOff
40
+
41
+ def add_alpha(self, value):
42
+ """Return a newly added `<a:alpha>` child element with `val` attribute set to `value`.
43
+
44
+ `value` is a float in the range [0.0, 1.0] where 1.0 is fully opaque.
45
+ """
46
+ alpha = self._add_alpha()
47
+ alpha.val = value
48
+ return alpha
49
+
50
+ def clear_alpha(self):
51
+ """Return self after removing any `<a:alpha>` child element."""
52
+ self._remove_alpha()
53
+ return self
54
+
55
+ def clear_lum(self):
56
+ """
57
+ Return self after removing any <a:lumMod> and <a:lumOff> child
58
+ elements.
59
+ """
60
+ self._remove_lumMod()
61
+ self._remove_lumOff()
62
+ return self
63
+
64
+
65
+ class CT_Color(BaseOxmlElement):
66
+ """Custom element class for `a:fgClr`, `a:bgClr` and perhaps others."""
67
+
68
+ eg_colorChoice = ZeroOrOneChoice(
69
+ (
70
+ Choice("a:scrgbClr"),
71
+ Choice("a:srgbClr"),
72
+ Choice("a:hslClr"),
73
+ Choice("a:sysClr"),
74
+ Choice("a:schemeClr"),
75
+ Choice("a:prstClr"),
76
+ ),
77
+ successors=(),
78
+ )
79
+
80
+
81
+ class CT_HslColor(_BaseColorElement):
82
+ """
83
+ Custom element class for <a:hslClr> element.
84
+ """
85
+
86
+
87
+ class CT_Percentage(BaseOxmlElement):
88
+ """
89
+ Custom element class for <a:lumMod> and <a:lumOff> elements.
90
+ """
91
+
92
+ val = RequiredAttribute("val", ST_Percentage)
93
+
94
+
95
+ class CT_PositiveFixedPercentage(BaseOxmlElement):
96
+ """Custom element class for `<a:alpha>` element.
97
+
98
+ `val` is a float in the closed interval [0.0, 1.0] where 1.0 is fully opaque.
99
+ """
100
+
101
+ val = RequiredAttribute("val", ST_PositiveFixedPercentage)
102
+
103
+
104
+ class CT_PresetColor(_BaseColorElement):
105
+ """
106
+ Custom element class for <a:prstClr> element.
107
+ """
108
+
109
+
110
+ class CT_SchemeColor(_BaseColorElement):
111
+ """
112
+ Custom element class for <a:schemeClr> element.
113
+ """
114
+
115
+ val = RequiredAttribute("val", MSO_THEME_COLOR)
116
+
117
+
118
+ class CT_ScRgbColor(_BaseColorElement):
119
+ """
120
+ Custom element class for <a:scrgbClr> element.
121
+ """
122
+
123
+
124
+ class CT_SRgbColor(_BaseColorElement):
125
+ """
126
+ Custom element class for <a:srgbClr> element.
127
+ """
128
+
129
+ val = RequiredAttribute("val", ST_HexColorRGB)
130
+
131
+
132
+ class CT_SystemColor(_BaseColorElement):
133
+ """
134
+ Custom element class for <a:sysClr> element.
135
+ """
@@ -0,0 +1,213 @@
1
+ """lxml custom element classes for DrawingML visual-effect elements."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pptx2.enum.dml import MSO_PRESET_SHADOW
6
+ from pptx2.oxml.ns import qn
7
+ from pptx2.oxml.simpletypes import (
8
+ ST_FixedAngle,
9
+ ST_Percentage,
10
+ ST_PositiveCoordinate,
11
+ ST_PositiveFixedAngle,
12
+ ST_PositiveFixedPercentage,
13
+ XsdBoolean,
14
+ XsdStringEnumeration,
15
+ )
16
+ from pptx2.oxml.xmlchemy import (
17
+ BaseOxmlElement,
18
+ Choice,
19
+ OptionalAttribute,
20
+ RequiredAttribute,
21
+ ZeroOrOne,
22
+ ZeroOrOneChoice,
23
+ )
24
+
25
+
26
+ class ST_RectAlignment(XsdStringEnumeration):
27
+ """Valid values for `a:reflection@algn`.
28
+
29
+ The nine-point alignment used by the reflection effect to anchor its
30
+ bounding box relative to the source shape.
31
+ """
32
+
33
+ TL = "tl"
34
+ T = "t"
35
+ TR = "tr"
36
+ L = "l"
37
+ CTR = "ctr"
38
+ R = "r"
39
+ BL = "bl"
40
+ B = "b"
41
+ BR = "br"
42
+
43
+ _members = (TL, T, TR, L, CTR, R, BL, B, BR)
44
+
45
+
46
+ _COLOR_TAGS = frozenset(
47
+ qn(t)
48
+ for t in (
49
+ "a:scrgbClr",
50
+ "a:srgbClr",
51
+ "a:hslClr",
52
+ "a:sysClr",
53
+ "a:schemeClr",
54
+ "a:prstClr",
55
+ )
56
+ )
57
+
58
+ _COLOR_CHOICES = (
59
+ Choice("a:scrgbClr"),
60
+ Choice("a:srgbClr"),
61
+ Choice("a:hslClr"),
62
+ Choice("a:sysClr"),
63
+ Choice("a:schemeClr"),
64
+ Choice("a:prstClr"),
65
+ )
66
+
67
+
68
+ class CT_EffectList(BaseOxmlElement):
69
+ """`<a:effectLst>` custom element class — container for shape visual effects."""
70
+
71
+ _tag_seq = (
72
+ "a:blur",
73
+ "a:fillOverlay",
74
+ "a:glow",
75
+ "a:innerShdw",
76
+ "a:outerShdw",
77
+ "a:prstShdw",
78
+ "a:reflection",
79
+ "a:softEdge",
80
+ )
81
+ blur: CT_BlurEffect | None = ZeroOrOne( # pyright: ignore[reportAssignmentType]
82
+ "a:blur", successors=_tag_seq[1:]
83
+ )
84
+ glow: CT_GlowEffect | None = ZeroOrOne( # pyright: ignore[reportAssignmentType]
85
+ "a:glow", successors=_tag_seq[3:]
86
+ )
87
+ innerShdw: CT_InnerShadowEffect | None = ZeroOrOne( # pyright: ignore[reportAssignmentType]
88
+ "a:innerShdw", successors=_tag_seq[4:]
89
+ )
90
+ outerShdw: CT_OuterShadowEffect | None = ZeroOrOne( # pyright: ignore[reportAssignmentType]
91
+ "a:outerShdw", successors=_tag_seq[5:]
92
+ )
93
+ prstShdw: CT_PresetShadowEffect | None = ZeroOrOne( # pyright: ignore[reportAssignmentType]
94
+ "a:prstShdw", successors=_tag_seq[6:]
95
+ )
96
+ reflection: CT_ReflectionEffect | None = ZeroOrOne( # pyright: ignore[reportAssignmentType]
97
+ "a:reflection", successors=_tag_seq[7:]
98
+ )
99
+ softEdge: CT_SoftEdgesEffect | None = ZeroOrOne( # pyright: ignore[reportAssignmentType]
100
+ "a:softEdge", successors=_tag_seq[8:]
101
+ )
102
+ del _tag_seq
103
+
104
+
105
+ class CT_GlowEffect(BaseOxmlElement):
106
+ """`<a:glow>` custom element class.
107
+
108
+ Specifies a glow effect around the shape edges. `rad` is the glow radius in EMU.
109
+ """
110
+
111
+ eg_colorChoice = ZeroOrOneChoice(_COLOR_CHOICES, successors=())
112
+ rad = OptionalAttribute("rad", ST_PositiveCoordinate)
113
+
114
+
115
+ class CT_OuterShadowEffect(BaseOxmlElement):
116
+ """`<a:outerShdw>` custom element class.
117
+
118
+ Outer shadow effect. All read attributes return None when the attribute is
119
+ absent; writes are non-mutating only when the value is explicitly None.
120
+ """
121
+
122
+ eg_colorChoice = ZeroOrOneChoice(_COLOR_CHOICES, successors=())
123
+ blurRad = OptionalAttribute("blurRad", ST_PositiveCoordinate)
124
+ dist = OptionalAttribute("dist", ST_PositiveCoordinate)
125
+ dir = OptionalAttribute("dir", ST_PositiveFixedAngle)
126
+ rotWithShape = OptionalAttribute("rotWithShape", XsdBoolean)
127
+
128
+
129
+ class CT_SoftEdgesEffect(BaseOxmlElement):
130
+ """`<a:softEdge>` custom element class.
131
+
132
+ Specifies a soft-edge blur at the shape perimeter. `rad` is the blur radius in EMU.
133
+ """
134
+
135
+ rad = OptionalAttribute("rad", ST_PositiveCoordinate)
136
+
137
+
138
+ class CT_BlurEffect(BaseOxmlElement):
139
+ """`<a:blur>` custom element class.
140
+
141
+ Applies a Gaussian blur to the entire shape. `rad` is the blur radius in
142
+ EMU; `grow` controls whether the bounding box expands to accommodate the
143
+ blur (default True per the OOXML schema).
144
+ """
145
+
146
+ rad = OptionalAttribute("rad", ST_PositiveCoordinate)
147
+ grow = OptionalAttribute("grow", XsdBoolean)
148
+
149
+
150
+ class CT_InnerShadowEffect(BaseOxmlElement):
151
+ """`<a:innerShdw>` custom element class.
152
+
153
+ Inner shadow effect. Mirrors the attribute set of the outer-shadow
154
+ element minus the outer-only `rotWithShape` flag. All read attributes
155
+ return None when the underlying attribute is absent.
156
+ """
157
+
158
+ eg_colorChoice = ZeroOrOneChoice(_COLOR_CHOICES, successors=())
159
+ blurRad = OptionalAttribute("blurRad", ST_PositiveCoordinate)
160
+ dist = OptionalAttribute("dist", ST_PositiveCoordinate)
161
+ dir = OptionalAttribute("dir", ST_PositiveFixedAngle)
162
+
163
+
164
+ class CT_PresetShadowEffect(BaseOxmlElement):
165
+ """`<a:prstShdw>` custom element class.
166
+
167
+ Preset shadow effect. The ``prst`` attribute (one of ``shdw1`` ..
168
+ ``shdw20``) is *required* by the OOXML schema, so it is declared as a
169
+ ``RequiredAttribute`` — omitting it (or writing the element without it)
170
+ makes PowerPoint flag the deck as broken. ``dist`` / ``dir`` are optional
171
+ and a single ``EG_ColorChoice`` child is required.
172
+ """
173
+
174
+ eg_colorChoice = ZeroOrOneChoice(_COLOR_CHOICES, successors=())
175
+ prst = RequiredAttribute("prst", MSO_PRESET_SHADOW)
176
+ dist = OptionalAttribute("dist", ST_PositiveCoordinate)
177
+ dir = OptionalAttribute("dir", ST_PositiveFixedAngle)
178
+
179
+
180
+ class CT_ReflectionEffect(BaseOxmlElement):
181
+ """`<a:reflection>` custom element class.
182
+
183
+ Reflection effect placed beneath the shape. Exposes the attributes most
184
+ users actually want — blur radius, offset distance, direction, start/end
185
+ alpha, and alignment. Attributes are optional; reads return None when
186
+ absent so theme inheritance is preserved.
187
+ """
188
+
189
+ blurRad = OptionalAttribute("blurRad", ST_PositiveCoordinate)
190
+ stA = OptionalAttribute("stA", ST_PositiveFixedPercentage)
191
+ stPos = OptionalAttribute("stPos", ST_PositiveFixedPercentage)
192
+ endA = OptionalAttribute("endA", ST_PositiveFixedPercentage)
193
+ endPos = OptionalAttribute("endPos", ST_PositiveFixedPercentage)
194
+ dist = OptionalAttribute("dist", ST_PositiveCoordinate)
195
+ dir = OptionalAttribute("dir", ST_PositiveFixedAngle)
196
+ fadeDir = OptionalAttribute("fadeDir", ST_PositiveFixedAngle)
197
+ sx = OptionalAttribute("sx", ST_Percentage)
198
+ sy = OptionalAttribute("sy", ST_Percentage)
199
+ kx = OptionalAttribute("kx", ST_FixedAngle)
200
+ ky = OptionalAttribute("ky", ST_FixedAngle)
201
+ algn = OptionalAttribute("algn", ST_RectAlignment)
202
+ rotWithShape = OptionalAttribute("rotWithShape", XsdBoolean)
203
+
204
+
205
+ # `<a:prstShdw>` is a post-fork addition; register its custom element class here
206
+ # (rather than in `pptx2.oxml.__init__`) so the lxml parser maps the tag to
207
+ # `CT_PresetShadowEffect` and the `CT_EffectList.prstShdw` accessor returns a
208
+ # typed element with a working `prst` attribute. `register_element_cls` is
209
+ # defined before this module is imported by `pptx2.oxml.__init__`, so this
210
+ # is safe despite the partial-import ordering.
211
+ from pptx2.oxml import register_element_cls # noqa: E402
212
+
213
+ register_element_cls("a:prstShdw", CT_PresetShadowEffect)