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.
- pptx2/__init__.py +152 -0
- pptx2/_color.py +75 -0
- pptx2/_slide_importer.py +597 -0
- pptx2/_svg.py +155 -0
- pptx2/_template_applier.py +292 -0
- pptx2/_textstyle.py +187 -0
- pptx2/accessibility.py +365 -0
- pptx2/action.py +270 -0
- pptx2/animation.py +2237 -0
- pptx2/api.py +49 -0
- pptx2/audit.py +258 -0
- pptx2/chart/__init__.py +0 -0
- pptx2/chart/analytics.py +381 -0
- pptx2/chart/axis.py +543 -0
- pptx2/chart/category.py +200 -0
- pptx2/chart/chart.py +670 -0
- pptx2/chart/data.py +864 -0
- pptx2/chart/datalabel.py +406 -0
- pptx2/chart/legend.py +86 -0
- pptx2/chart/marker.py +70 -0
- pptx2/chart/palettes.py +129 -0
- pptx2/chart/plot.py +462 -0
- pptx2/chart/point.py +101 -0
- pptx2/chart/quick_layouts.py +325 -0
- pptx2/chart/series.py +334 -0
- pptx2/chart/xlsx.py +272 -0
- pptx2/chart/xmlwriter.py +1845 -0
- pptx2/compose/__init__.py +28 -0
- pptx2/compose/from_spec.py +1094 -0
- pptx2/design/__init__.py +8 -0
- pptx2/design/components.py +607 -0
- pptx2/design/figures.py +389 -0
- pptx2/design/layout.py +370 -0
- pptx2/design/recipes.py +1967 -0
- pptx2/design/style.py +209 -0
- pptx2/design/tokens.py +915 -0
- pptx2/diagrams.py +754 -0
- pptx2/dml/__init__.py +0 -0
- pptx2/dml/chtfmt.py +40 -0
- pptx2/dml/color.py +496 -0
- pptx2/dml/effect.py +909 -0
- pptx2/dml/fill.py +691 -0
- pptx2/dml/line.py +287 -0
- pptx2/dml/picture.py +212 -0
- pptx2/dml/three_d.py +381 -0
- pptx2/enum/__init__.py +0 -0
- pptx2/enum/action.py +71 -0
- pptx2/enum/animation.py +31 -0
- pptx2/enum/base.py +218 -0
- pptx2/enum/chart.py +574 -0
- pptx2/enum/dml.py +740 -0
- pptx2/enum/lang.py +685 -0
- pptx2/enum/presentation.py +133 -0
- pptx2/enum/shapes.py +1029 -0
- pptx2/enum/text.py +230 -0
- pptx2/exc.py +42 -0
- pptx2/formats.py +139 -0
- pptx2/geometry.py +420 -0
- pptx2/inherit.py +109 -0
- pptx2/lint.py +2256 -0
- pptx2/math.py +177 -0
- pptx2/media.py +197 -0
- pptx2/opc/__init__.py +0 -0
- pptx2/opc/constants.py +332 -0
- pptx2/opc/oxml.py +188 -0
- pptx2/opc/package.py +762 -0
- pptx2/opc/packuri.py +109 -0
- pptx2/opc/serialized.py +296 -0
- pptx2/opc/shared.py +20 -0
- pptx2/opc/spec.py +45 -0
- pptx2/oxml/__init__.py +555 -0
- pptx2/oxml/action.py +53 -0
- pptx2/oxml/chart/__init__.py +0 -0
- pptx2/oxml/chart/axis.py +337 -0
- pptx2/oxml/chart/chart.py +481 -0
- pptx2/oxml/chart/datalabel.py +253 -0
- pptx2/oxml/chart/legend.py +72 -0
- pptx2/oxml/chart/marker.py +61 -0
- pptx2/oxml/chart/plot.py +365 -0
- pptx2/oxml/chart/series.py +425 -0
- pptx2/oxml/chart/shared.py +220 -0
- pptx2/oxml/coreprops.py +288 -0
- pptx2/oxml/dml/__init__.py +0 -0
- pptx2/oxml/dml/color.py +135 -0
- pptx2/oxml/dml/effect.py +213 -0
- pptx2/oxml/dml/fill.py +316 -0
- pptx2/oxml/dml/line.py +12 -0
- pptx2/oxml/dml/three_d.py +110 -0
- pptx2/oxml/ns.py +135 -0
- pptx2/oxml/presentation.py +313 -0
- pptx2/oxml/shapes/__init__.py +19 -0
- pptx2/oxml/shapes/autoshape.py +467 -0
- pptx2/oxml/shapes/connector.py +107 -0
- pptx2/oxml/shapes/graphfrm.py +347 -0
- pptx2/oxml/shapes/groupshape.py +329 -0
- pptx2/oxml/shapes/picture.py +270 -0
- pptx2/oxml/shapes/shared.py +577 -0
- pptx2/oxml/simpletypes.py +1027 -0
- pptx2/oxml/slide.py +563 -0
- pptx2/oxml/table.py +650 -0
- pptx2/oxml/text.py +815 -0
- pptx2/oxml/theme.py +36 -0
- pptx2/oxml/xmlchemy.py +717 -0
- pptx2/package.py +222 -0
- pptx2/parts/__init__.py +0 -0
- pptx2/parts/chart.py +95 -0
- pptx2/parts/coreprops.py +167 -0
- pptx2/parts/diagram.py +37 -0
- pptx2/parts/embeddedpackage.py +93 -0
- pptx2/parts/image.py +275 -0
- pptx2/parts/media.py +37 -0
- pptx2/parts/presentation.py +136 -0
- pptx2/parts/slide.py +371 -0
- pptx2/presentation.py +408 -0
- pptx2/py.typed +0 -0
- pptx2/render.py +586 -0
- pptx2/section.py +272 -0
- pptx2/shapes/__init__.py +26 -0
- pptx2/shapes/autoshape.py +442 -0
- pptx2/shapes/base.py +1078 -0
- pptx2/shapes/connector.py +297 -0
- pptx2/shapes/freeform.py +337 -0
- pptx2/shapes/graphfrm.py +316 -0
- pptx2/shapes/group.py +264 -0
- pptx2/shapes/picture.py +422 -0
- pptx2/shapes/placeholder.py +468 -0
- pptx2/shapes/shapetree.py +2027 -0
- pptx2/shared.py +82 -0
- pptx2/skill/SKILL.md +450 -0
- pptx2/skill/__init__.py +78 -0
- pptx2/skill/__main__.py +64 -0
- pptx2/skill/references/animations.md +189 -0
- pptx2/skill/references/basics.md +421 -0
- pptx2/skill/references/charts.md +254 -0
- pptx2/skill/references/compose.md +234 -0
- pptx2/skill/references/design.md +366 -0
- pptx2/skill/references/effects.md +249 -0
- pptx2/skill/references/end-to-end-deck.md +231 -0
- pptx2/skill/references/geometry-and-arrows.md +334 -0
- pptx2/skill/references/lint.md +275 -0
- pptx2/skill/references/math.md +86 -0
- pptx2/skill/references/picture-effects.md +129 -0
- pptx2/skill/references/render.md +151 -0
- pptx2/skill/references/smart-art.md +75 -0
- pptx2/skill/references/space-aware-authoring.md +249 -0
- pptx2/skill/references/tables.md +244 -0
- pptx2/skill/references/theme.md +127 -0
- pptx2/skill/references/three-d.md +109 -0
- pptx2/skill/references/transitions.md +100 -0
- pptx2/slide.py +1244 -0
- pptx2/smart_art.py +220 -0
- pptx2/spec.py +633 -0
- pptx2/table.py +1181 -0
- pptx2/table_styles.py +184 -0
- pptx2/templates/default.pptx +0 -0
- pptx2/templates/docx-icon.emf +0 -0
- pptx2/templates/generic-icon.emf +0 -0
- pptx2/templates/notes.xml +23 -0
- pptx2/templates/notesMaster.xml +352 -0
- pptx2/templates/pptx-icon.emf +0 -0
- pptx2/templates/theme.xml +321 -0
- pptx2/templates/xlsx-icon.emf +0 -0
- pptx2/text/__init__.py +0 -0
- pptx2/text/fonts.py +482 -0
- pptx2/text/layout.py +374 -0
- pptx2/text/text.py +1272 -0
- pptx2/theme.py +721 -0
- pptx2/types.py +36 -0
- pptx2/util.py +263 -0
- python_pptx2-2.13.0.dist-info/METADATA +351 -0
- python_pptx2-2.13.0.dist-info/RECORD +175 -0
- python_pptx2-2.13.0.dist-info/WHEEL +5 -0
- python_pptx2-2.13.0.dist-info/entry_points.txt +3 -0
- python_pptx2-2.13.0.dist-info/licenses/LICENSE +22 -0
- python_pptx2-2.13.0.dist-info/top_level.txt +1 -0
pptx2/types.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""Abstract types used by `python-pptx`."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
|
+
|
|
7
|
+
from typing_extensions import Protocol
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from pptx2.opc.package import XmlPart
|
|
11
|
+
from pptx2.util import Length
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ProvidesExtents(Protocol):
|
|
15
|
+
"""An object that has width and height."""
|
|
16
|
+
|
|
17
|
+
@property
|
|
18
|
+
def height(self) -> Length:
|
|
19
|
+
"""Distance between top and bottom extents of shape in EMUs."""
|
|
20
|
+
...
|
|
21
|
+
|
|
22
|
+
@property
|
|
23
|
+
def width(self) -> Length:
|
|
24
|
+
"""Distance between left and right extents of shape in EMUs."""
|
|
25
|
+
...
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class ProvidesPart(Protocol):
|
|
29
|
+
"""An object that provides access to its XmlPart.
|
|
30
|
+
|
|
31
|
+
This type is for objects that need access to their part, possibly because they need access to
|
|
32
|
+
the package or related parts.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
@property
|
|
36
|
+
def part(self) -> XmlPart: ...
|
pptx2/util.py
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
"""Utility functions and classes."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import functools
|
|
6
|
+
from typing import Any, Callable, Generic, TypeVar, cast
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def _coerce_emu(value):
|
|
10
|
+
"""Internal: coerce a coordinate value to integer EMU.
|
|
11
|
+
|
|
12
|
+
Accepts int / Length passes through unchanged, floats are rounded
|
|
13
|
+
half-to-even, and ``None`` is passed through (callers may use ``None``
|
|
14
|
+
for "don't set"). ``bool`` is rejected — booleans are an int subclass
|
|
15
|
+
in Python but a boolean coordinate is always a programming error.
|
|
16
|
+
|
|
17
|
+
OOXML's ``CT_Point2D`` (``<a:off>``) requires ``x``/``y`` to be
|
|
18
|
+
``xs:long`` and ``CT_PositiveSize2D`` (``<a:ext>``) requires
|
|
19
|
+
``cx``/``cy`` to be ``xs:nonNegativeInteger``. Float-valued strings
|
|
20
|
+
in those attributes are schema-invalid; PowerPoint's strict
|
|
21
|
+
open-time validator rejects them with the "Repair?" dialog even
|
|
22
|
+
though python-pptx, the OOXML XSDs, and LibreOffice all accept
|
|
23
|
+
them silently. Coercing at constructor entry catches the common
|
|
24
|
+
case of ``(Inches(N) - gutter) / 2`` producing a float.
|
|
25
|
+
"""
|
|
26
|
+
if value is None:
|
|
27
|
+
return None
|
|
28
|
+
if isinstance(value, bool):
|
|
29
|
+
raise TypeError("bool is not a valid EMU coordinate")
|
|
30
|
+
if isinstance(value, int):
|
|
31
|
+
return value
|
|
32
|
+
# Reject str/bytes explicitly — they're convertible via float() but
|
|
33
|
+
# passing a coordinate as a string is always a programming error,
|
|
34
|
+
# not a unit-conversion case we want to silently accept.
|
|
35
|
+
if isinstance(value, (str, bytes, bytearray)):
|
|
36
|
+
raise TypeError(
|
|
37
|
+
f"Expected int, float, or Emu-derived length; got "
|
|
38
|
+
f"{type(value).__name__}: {value!r}"
|
|
39
|
+
)
|
|
40
|
+
if isinstance(value, float):
|
|
41
|
+
try:
|
|
42
|
+
return int(round(value))
|
|
43
|
+
except (OverflowError, ValueError) as exc:
|
|
44
|
+
# NaN → ValueError, ±inf → OverflowError. Normalise to
|
|
45
|
+
# TypeError so callers get a single, informative exception.
|
|
46
|
+
raise TypeError(
|
|
47
|
+
f"Cannot coerce non-finite float to EMU: {value!r}"
|
|
48
|
+
) from exc
|
|
49
|
+
try:
|
|
50
|
+
return int(round(float(value)))
|
|
51
|
+
except (TypeError, ValueError, OverflowError):
|
|
52
|
+
raise TypeError(
|
|
53
|
+
f"Expected int, float, or Emu-derived length; got "
|
|
54
|
+
f"{type(value).__name__}: {value!r}"
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class Length(int):
|
|
59
|
+
"""Base class for length classes Inches, Emu, Cm, Mm, and Pt.
|
|
60
|
+
|
|
61
|
+
Provides properties for converting length values to convenient units.
|
|
62
|
+
"""
|
|
63
|
+
|
|
64
|
+
_EMUS_PER_INCH = 914400
|
|
65
|
+
_EMUS_PER_CENTIPOINT = 127
|
|
66
|
+
_EMUS_PER_CM = 360000
|
|
67
|
+
_EMUS_PER_MM = 36000
|
|
68
|
+
_EMUS_PER_PT = 12700
|
|
69
|
+
|
|
70
|
+
def __new__(cls, emu: int):
|
|
71
|
+
return int.__new__(cls, emu)
|
|
72
|
+
|
|
73
|
+
@property
|
|
74
|
+
def inches(self) -> float:
|
|
75
|
+
"""Floating point length in inches."""
|
|
76
|
+
return self / float(self._EMUS_PER_INCH)
|
|
77
|
+
|
|
78
|
+
@property
|
|
79
|
+
def centipoints(self) -> int:
|
|
80
|
+
"""Integer length in hundredths of a point (1/7200 inch).
|
|
81
|
+
|
|
82
|
+
Used internally because PowerPoint stores font size in centipoints.
|
|
83
|
+
"""
|
|
84
|
+
return self // self._EMUS_PER_CENTIPOINT
|
|
85
|
+
|
|
86
|
+
@property
|
|
87
|
+
def cm(self) -> float:
|
|
88
|
+
"""Floating point length in centimeters."""
|
|
89
|
+
return self / float(self._EMUS_PER_CM)
|
|
90
|
+
|
|
91
|
+
@property
|
|
92
|
+
def emu(self) -> int:
|
|
93
|
+
"""Integer length in English Metric Units."""
|
|
94
|
+
return self
|
|
95
|
+
|
|
96
|
+
@property
|
|
97
|
+
def mm(self) -> float:
|
|
98
|
+
"""Floating point length in millimeters."""
|
|
99
|
+
return self / float(self._EMUS_PER_MM)
|
|
100
|
+
|
|
101
|
+
@property
|
|
102
|
+
def pt(self) -> float:
|
|
103
|
+
"""Floating point length in points."""
|
|
104
|
+
return self / float(self._EMUS_PER_PT)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class Inches(Length):
|
|
108
|
+
"""Convenience constructor for length in inches."""
|
|
109
|
+
|
|
110
|
+
def __new__(cls, inches: float):
|
|
111
|
+
emu = int(inches * Length._EMUS_PER_INCH)
|
|
112
|
+
return Length.__new__(cls, emu)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class Centipoints(Length):
|
|
116
|
+
"""Convenience constructor for length in hundredths of a point."""
|
|
117
|
+
|
|
118
|
+
def __new__(cls, centipoints: int):
|
|
119
|
+
emu = int(centipoints * Length._EMUS_PER_CENTIPOINT)
|
|
120
|
+
return Length.__new__(cls, emu)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
class Cm(Length):
|
|
124
|
+
"""Convenience constructor for length in centimeters."""
|
|
125
|
+
|
|
126
|
+
def __new__(cls, cm: float):
|
|
127
|
+
emu = int(cm * Length._EMUS_PER_CM)
|
|
128
|
+
return Length.__new__(cls, emu)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
class Emu(Length):
|
|
132
|
+
"""Convenience constructor for length in english metric units."""
|
|
133
|
+
|
|
134
|
+
def __new__(cls, emu: int):
|
|
135
|
+
return Length.__new__(cls, int(emu))
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
class Mm(Length):
|
|
139
|
+
"""Convenience constructor for length in millimeters."""
|
|
140
|
+
|
|
141
|
+
def __new__(cls, mm: float):
|
|
142
|
+
emu = int(mm * Length._EMUS_PER_MM)
|
|
143
|
+
return Length.__new__(cls, emu)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
class Pt(Length):
|
|
147
|
+
"""Convenience value class for specifying a length in points."""
|
|
148
|
+
|
|
149
|
+
def __new__(cls, points: float):
|
|
150
|
+
emu = int(points * Length._EMUS_PER_PT)
|
|
151
|
+
return Length.__new__(cls, emu)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
_T = TypeVar("_T")
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
class lazyproperty(Generic[_T]):
|
|
158
|
+
"""Decorator like @property, but evaluated only on first access.
|
|
159
|
+
|
|
160
|
+
Like @property, this can only be used to decorate methods having only a `self` parameter, and
|
|
161
|
+
is accessed like an attribute on an instance, i.e. trailing parentheses are not used. Unlike
|
|
162
|
+
@property, the decorated method is only evaluated on first access; the resulting value is
|
|
163
|
+
cached and that same value returned on second and later access without re-evaluation of the
|
|
164
|
+
method.
|
|
165
|
+
|
|
166
|
+
Like @property, this class produces a *data descriptor* object, which is stored in the __dict__
|
|
167
|
+
of the *class* under the name of the decorated method ('fget' nominally). The cached value is
|
|
168
|
+
stored in the __dict__ of the *instance* under that same name.
|
|
169
|
+
|
|
170
|
+
Because it is a data descriptor (as opposed to a *non-data descriptor*), its `__get__()` method
|
|
171
|
+
is executed on each access of the decorated attribute; the __dict__ item of the same name is
|
|
172
|
+
"shadowed" by the descriptor.
|
|
173
|
+
|
|
174
|
+
While this may represent a performance improvement over a property, its greater benefit may be
|
|
175
|
+
its other characteristics. One common use is to construct collaborator objects, removing that
|
|
176
|
+
"real work" from the constructor, while still only executing once. It also de-couples client
|
|
177
|
+
code from any sequencing considerations; if it's accessed from more than one location, it's
|
|
178
|
+
assured it will be ready whenever needed.
|
|
179
|
+
|
|
180
|
+
Loosely based on: https://stackoverflow.com/a/6849299/1902513.
|
|
181
|
+
|
|
182
|
+
A lazyproperty is read-only. There is no counterpart to the optional "setter" (or deleter)
|
|
183
|
+
behavior of an @property. This is critically important to maintaining its immutability and
|
|
184
|
+
idempotence guarantees. Attempting to assign to a lazyproperty raises AttributeError
|
|
185
|
+
unconditionally.
|
|
186
|
+
|
|
187
|
+
The parameter names in the methods below correspond to this usage example::
|
|
188
|
+
|
|
189
|
+
class Obj(object)
|
|
190
|
+
|
|
191
|
+
@lazyproperty
|
|
192
|
+
def fget(self):
|
|
193
|
+
return 'some result'
|
|
194
|
+
|
|
195
|
+
obj = Obj()
|
|
196
|
+
|
|
197
|
+
Not suitable for wrapping a function (as opposed to a method) because it is not callable.
|
|
198
|
+
"""
|
|
199
|
+
|
|
200
|
+
def __init__(self, fget: Callable[..., _T]) -> None:
|
|
201
|
+
"""*fget* is the decorated method (a "getter" function).
|
|
202
|
+
|
|
203
|
+
A lazyproperty is read-only, so there is only an *fget* function (a regular
|
|
204
|
+
@property can also have an fset and fdel function). This name was chosen for
|
|
205
|
+
consistency with Python's `property` class which uses this name for the
|
|
206
|
+
corresponding parameter.
|
|
207
|
+
"""
|
|
208
|
+
# --- maintain a reference to the wrapped getter method
|
|
209
|
+
self._fget = fget
|
|
210
|
+
# --- and store the name of that decorated method
|
|
211
|
+
self._name = fget.__name__
|
|
212
|
+
# --- adopt fget's __name__, __doc__, and other attributes
|
|
213
|
+
functools.update_wrapper(self, fget) # pyright: ignore
|
|
214
|
+
|
|
215
|
+
def __get__(self, obj: Any, type: Any = None) -> _T:
|
|
216
|
+
"""Called on each access of 'fget' attribute on class or instance.
|
|
217
|
+
|
|
218
|
+
*self* is this instance of a lazyproperty descriptor "wrapping" the property
|
|
219
|
+
method it decorates (`fget`, nominally).
|
|
220
|
+
|
|
221
|
+
*obj* is the "host" object instance when the attribute is accessed from an
|
|
222
|
+
object instance, e.g. `obj = Obj(); obj.fget`. *obj* is None when accessed on
|
|
223
|
+
the class, e.g. `Obj.fget`.
|
|
224
|
+
|
|
225
|
+
*type* is the class hosting the decorated getter method (`fget`) on both class
|
|
226
|
+
and instance attribute access.
|
|
227
|
+
"""
|
|
228
|
+
# --- when accessed on class, e.g. Obj.fget, just return this descriptor
|
|
229
|
+
# --- instance (patched above to look like fget).
|
|
230
|
+
if obj is None:
|
|
231
|
+
return self # type: ignore
|
|
232
|
+
|
|
233
|
+
# --- when accessed on instance, start by checking instance __dict__ for
|
|
234
|
+
# --- item with key matching the wrapped function's name
|
|
235
|
+
value = obj.__dict__.get(self._name)
|
|
236
|
+
if value is None:
|
|
237
|
+
# --- on first access, the __dict__ item will be absent. Evaluate fget()
|
|
238
|
+
# --- and store that value in the (otherwise unused) host-object
|
|
239
|
+
# --- __dict__ value of same name ('fget' nominally)
|
|
240
|
+
value = self._fget(obj)
|
|
241
|
+
obj.__dict__[self._name] = value
|
|
242
|
+
return cast(_T, value)
|
|
243
|
+
|
|
244
|
+
def __set__(self, obj: Any, value: Any) -> None:
|
|
245
|
+
"""Raises unconditionally, to preserve read-only behavior.
|
|
246
|
+
|
|
247
|
+
This decorator is intended to implement immutable (and idempotent) object
|
|
248
|
+
attributes. For that reason, assignment to this property must be explicitly
|
|
249
|
+
prevented.
|
|
250
|
+
|
|
251
|
+
If this __set__ method was not present, this descriptor would become a
|
|
252
|
+
*non-data descriptor*. That would be nice because the cached value would be
|
|
253
|
+
accessed directly once set (__dict__ attrs have precedence over non-data
|
|
254
|
+
descriptors on instance attribute lookup). The problem is, there would be
|
|
255
|
+
nothing to stop assignment to the cached value, which would overwrite the result
|
|
256
|
+
of `fget()` and break both the immutability and idempotence guarantees of this
|
|
257
|
+
decorator.
|
|
258
|
+
|
|
259
|
+
The performance with this __set__() method in place was roughly 0.4 usec per
|
|
260
|
+
access when measured on a 2.8GHz development machine; so quite snappy and
|
|
261
|
+
probably not a rich target for optimization efforts.
|
|
262
|
+
"""
|
|
263
|
+
raise AttributeError("can't set attribute")
|
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: python-pptx2
|
|
3
|
+
Version: 2.13.0
|
|
4
|
+
Summary: Create, read, and update PowerPoint 2007+ (.pptx) files. Fork of power-pptx / python-pptx, published as python-pptx2.
|
|
5
|
+
Author: Matěj Štágl
|
|
6
|
+
Author-email: stagl@wattlescript.org
|
|
7
|
+
Maintainer: Matěj Štágl
|
|
8
|
+
Maintainer-email: stagl@wattlescript.org
|
|
9
|
+
License: MIT
|
|
10
|
+
Project-URL: Changelog, https://github.com/lofcz/python-pptx2/blob/master/HISTORY.rst
|
|
11
|
+
Project-URL: Documentation, https://github.com/lofcz/python-pptx2
|
|
12
|
+
Project-URL: Homepage, https://github.com/lofcz/python-pptx2
|
|
13
|
+
Project-URL: Issues, https://github.com/lofcz/python-pptx2/issues
|
|
14
|
+
Project-URL: Repository, https://github.com/lofcz/python-pptx2
|
|
15
|
+
Project-URL: Roadmap, https://github.com/lofcz/python-pptx2/blob/master/ROADMAP.md
|
|
16
|
+
Project-URL: ParentFork, https://github.com/CodeHalwell/power-pptx
|
|
17
|
+
Project-URL: Upstream, https://github.com/scanny/python-pptx
|
|
18
|
+
Project-URL: UpstreamDocumentation, https://python-pptx.readthedocs.io/en/latest/
|
|
19
|
+
Keywords: powerpoint,ppt,pptx,openxml,office,presentation
|
|
20
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
21
|
+
Classifier: Environment :: Console
|
|
22
|
+
Classifier: Intended Audience :: Developers
|
|
23
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
24
|
+
Classifier: Operating System :: OS Independent
|
|
25
|
+
Classifier: Programming Language :: Python
|
|
26
|
+
Classifier: Programming Language :: Python :: 3
|
|
27
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
28
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
29
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
30
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
31
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
32
|
+
Classifier: Topic :: Office/Business :: Office Suites
|
|
33
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
34
|
+
Requires-Python: >=3.9
|
|
35
|
+
Description-Content-Type: text/x-rst
|
|
36
|
+
License-File: LICENSE
|
|
37
|
+
Requires-Dist: Pillow>=3.3.2
|
|
38
|
+
Requires-Dist: XlsxWriter>=0.5.7
|
|
39
|
+
Requires-Dist: lxml>=3.1.0
|
|
40
|
+
Requires-Dist: typing_extensions>=4.9.0
|
|
41
|
+
Provides-Extra: math
|
|
42
|
+
Requires-Dist: latex2mathml>=3.0; extra == "math"
|
|
43
|
+
Requires-Dist: mathml2omml>=0.0.2; extra == "math"
|
|
44
|
+
Dynamic: license-file
|
|
45
|
+
|
|
46
|
+
python-pptx2
|
|
47
|
+
=============
|
|
48
|
+
|
|
49
|
+
|PyPI| |PyPI - Python Versions| |CI| |License| |Documentation|
|
|
50
|
+
|
|
51
|
+
.. |PyPI| image:: https://img.shields.io/pypi/v/python-pptx2.svg
|
|
52
|
+
:target: https://pypi.org/project/python-pptx2/
|
|
53
|
+
:alt: PyPI
|
|
54
|
+
|
|
55
|
+
.. |PyPI - Python Versions| image:: https://img.shields.io/pypi/pyversions/python-pptx2.svg
|
|
56
|
+
:target: https://pypi.org/project/python-pptx2/
|
|
57
|
+
:alt: Python 3.9 – 3.13
|
|
58
|
+
|
|
59
|
+
.. |CI| image:: https://github.com/lofcz/python-pptx2/actions/workflows/ci.yml/badge.svg
|
|
60
|
+
:target: https://github.com/lofcz/python-pptx2/actions/workflows/ci.yml
|
|
61
|
+
:alt: CI status
|
|
62
|
+
|
|
63
|
+
.. |License| image:: https://img.shields.io/badge/license-MIT-blue.svg
|
|
64
|
+
:target: https://github.com/lofcz/python-pptx2/blob/master/LICENSE
|
|
65
|
+
:alt: MIT License
|
|
66
|
+
|
|
67
|
+
.. |Documentation| image:: https://img.shields.io/badge/docs-github.com%2Flofcz%2Fpython--pptx2-blue.svg
|
|
68
|
+
:target: https://github.com/lofcz/python-pptx2
|
|
69
|
+
:alt: Documentation
|
|
70
|
+
|
|
71
|
+
**PowerPoint decks from Python, that actually fit.**
|
|
72
|
+
|
|
73
|
+
*python-pptx2* is a fork of `power-pptx`_ (Daniel Halwell) and, through
|
|
74
|
+
it, of `python-pptx`_ by `Steve Canny`_. It is a Python library for
|
|
75
|
+
creating, reading, and updating PowerPoint (.pptx) files, plus native
|
|
76
|
+
LaTeX equations.
|
|
77
|
+
|
|
78
|
+
+----------------+----------------------------------------------------------+
|
|
79
|
+
| **Package** | ``python-pptx2`` on PyPI (imports as ``pptx2``) |
|
|
80
|
+
+----------------+----------------------------------------------------------+
|
|
81
|
+
| **Python** | 3.9 – 3.13 |
|
|
82
|
+
+----------------+----------------------------------------------------------+
|
|
83
|
+
| **License** | MIT |
|
|
84
|
+
+----------------+----------------------------------------------------------+
|
|
85
|
+
| **Source** | https://github.com/lofcz/python-pptx2 |
|
|
86
|
+
+----------------+----------------------------------------------------------+
|
|
87
|
+
|
|
88
|
+
.. _`power-pptx`: https://github.com/CodeHalwell/power-pptx
|
|
89
|
+
|
|
90
|
+
A typical use is generating a PowerPoint presentation from dynamic
|
|
91
|
+
content such as a database query, an analytics output, an LLM payload,
|
|
92
|
+
or a JSON spec — and downloading the generated .pptx file. It runs on
|
|
93
|
+
any Python-capable platform (macOS, Linux, Windows) and does not
|
|
94
|
+
require Microsoft PowerPoint to be installed or licensed.
|
|
95
|
+
|
|
96
|
+
**Why this fork exists: space-aware authoring.** The headline
|
|
97
|
+
proposition is that text doesn't overflow its container and shapes
|
|
98
|
+
don't slide off the edges of the slide. Three layered tools used
|
|
99
|
+
together catch ~all real-world layout issues:
|
|
100
|
+
|
|
101
|
+
1. ``TextFrame.fit_text(...)`` measures with Pillow font metrics and
|
|
102
|
+
bakes a fitting size into the XML *before* save.
|
|
103
|
+
2. ``text_frame.auto_size = MSO_AUTO_SIZE.TEXT_TO_FIT_SHAPE`` lets
|
|
104
|
+
PowerPoint shrink at render time as a fallback.
|
|
105
|
+
3. ``slide.lint()`` catches what slipped through; ``auto_fix()`` (or
|
|
106
|
+
the one-call ``slide.tidy()``) nudges off-slide shapes back inside.
|
|
107
|
+
|
|
108
|
+
Reach for python-pptx2 whenever the deck is generated dynamically and
|
|
109
|
+
has to look right without manual cleanup.
|
|
110
|
+
|
|
111
|
+
Installation
|
|
112
|
+
------------
|
|
113
|
+
|
|
114
|
+
Install from PyPI::
|
|
115
|
+
|
|
116
|
+
pip install python-pptx2
|
|
117
|
+
|
|
118
|
+
Then in Python::
|
|
119
|
+
|
|
120
|
+
from pptx2 import Presentation
|
|
121
|
+
|
|
122
|
+
``python-pptx2`` imports as ``pptx2`` so it can sit beside upstream
|
|
123
|
+
``python-pptx`` (``pptx``) and the parent fork ``power-pptx``
|
|
124
|
+
(``power_pptx``). To migrate from those packages, replace
|
|
125
|
+
``from pptx import`` / ``from power_pptx import`` with
|
|
126
|
+
``from pptx2 import``.
|
|
127
|
+
|
|
128
|
+
Optional dependencies:
|
|
129
|
+
|
|
130
|
+
* ``cairosvg`` — install only if you want ``add_svg_picture(...)`` to
|
|
131
|
+
auto-rasterise the PNG fallback.
|
|
132
|
+
* ``pyyaml`` — install only if you want ``DesignTokens.from_yaml``.
|
|
133
|
+
* ``python-pptx2[math]`` (``latex2mathml`` + ``mathml2omml``) — required
|
|
134
|
+
for ``slide.shapes.add_equation(...)`` / ``paragraph.add_math(...)``.
|
|
135
|
+
* ``soffice`` (LibreOffice) on PATH — required for
|
|
136
|
+
``Presentation.render_thumbnails()``.
|
|
137
|
+
* ``pdftoppm`` (Poppler) or ``pypdfium2`` — required for the
|
|
138
|
+
PDF→PNG split path in the thumbnail renderer.
|
|
139
|
+
|
|
140
|
+
Claude Code skill
|
|
141
|
+
-----------------
|
|
142
|
+
|
|
143
|
+
python-pptx2 ships a Claude Code skill alongside the library — pip-install
|
|
144
|
+
the package and the skill files are already on disk inside it. Install
|
|
145
|
+
the skill into your local Claude Code skills directory with::
|
|
146
|
+
|
|
147
|
+
python -m pptx2.skill install
|
|
148
|
+
|
|
149
|
+
This copies ``SKILL.md`` and the ``references/`` directory into
|
|
150
|
+
``~/.claude/skills/python-pptx2/``. Claude Code (and any compatible
|
|
151
|
+
Claude Agent SDK harness) will pick it up automatically the next time
|
|
152
|
+
it starts.
|
|
153
|
+
|
|
154
|
+
Other useful commands::
|
|
155
|
+
|
|
156
|
+
# Print the skill source path inside the installed package
|
|
157
|
+
python -m pptx2.skill path
|
|
158
|
+
|
|
159
|
+
# Install into a custom directory
|
|
160
|
+
python -m pptx2.skill install --target /path/to/skills/python-pptx2
|
|
161
|
+
|
|
162
|
+
# Refuse to overwrite an existing install
|
|
163
|
+
python -m pptx2.skill install --no-overwrite
|
|
164
|
+
|
|
165
|
+
The skill documents the headline space-aware-authoring workflow, the
|
|
166
|
+
``BBox`` value object, the one-call ``add_text`` / ``add_arrow``
|
|
167
|
+
helpers, the diagram recipes (``horizontal_pipeline``,
|
|
168
|
+
``hub_and_spoke``, ``cycle``, ``decision_tree``,
|
|
169
|
+
``comparison_columns``), and 16 focused reference docs covering
|
|
170
|
+
effects, animations, transitions, theming, charts, tables, 3D,
|
|
171
|
+
SmartArt, and rendering. It also includes an *anti-patterns* section
|
|
172
|
+
calling out the mistakes LLMs commonly make (mis-comparing wrapper
|
|
173
|
+
objects, assuming ``add_connector`` puts an arrowhead on the line,
|
|
174
|
+
sizing a diagram to a broken picture's bbox rather than its enclosing
|
|
175
|
+
card, …).
|
|
176
|
+
|
|
177
|
+
Quick start
|
|
178
|
+
-----------
|
|
179
|
+
|
|
180
|
+
A minimal end-to-end deck-generation pattern::
|
|
181
|
+
|
|
182
|
+
from pptx2 import Presentation, BBox, audit
|
|
183
|
+
from pptx2.diagrams import horizontal_pipeline
|
|
184
|
+
from pptx2.util import Inches
|
|
185
|
+
|
|
186
|
+
prs = Presentation()
|
|
187
|
+
slide = prs.slides.add_slide(prs.slide_layouts[5])
|
|
188
|
+
slide.shapes.title.text = "Pipeline overview"
|
|
189
|
+
|
|
190
|
+
horizontal_pipeline(
|
|
191
|
+
slide,
|
|
192
|
+
BBox.from_inches(0.5, 2.5, 9, 2.2),
|
|
193
|
+
steps=["Extract", "Classify", "Enrich", "Output"],
|
|
194
|
+
accent="#0B5CFF",
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
slide.shapes.add_text(
|
|
198
|
+
BBox.from_inches(0.5, 5.5, 9, 1),
|
|
199
|
+
text="Four-stage data pipeline.",
|
|
200
|
+
align="center", size_pt=14, color="#666666",
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
# Lint + safe auto-fixes
|
|
204
|
+
slide.tidy()
|
|
205
|
+
|
|
206
|
+
# Optional: full-deck audit
|
|
207
|
+
print(audit(prs).markdown())
|
|
208
|
+
|
|
209
|
+
prs.save("out.pptx")
|
|
210
|
+
|
|
211
|
+
What's new in the fork
|
|
212
|
+
----------------------
|
|
213
|
+
|
|
214
|
+
The fork extends the 1.0.2 surface with features the upstream roadmap
|
|
215
|
+
did not cover. All additions are drop-in compatible — existing
|
|
216
|
+
scripts keep working — and every new feature ships with a round-trip
|
|
217
|
+
regression test.
|
|
218
|
+
|
|
219
|
+
* **Space-aware authoring** — ``TextFrame.fit_text`` bakes a fitting
|
|
220
|
+
size before save; ``auto_size`` flags shrink at render time; the
|
|
221
|
+
layout linter reports text overflow / off-slide shapes /
|
|
222
|
+
collisions. Three-tier safety so generated decks look right
|
|
223
|
+
without manual cleanup.
|
|
224
|
+
|
|
225
|
+
* **Geometry and convenience helpers (v2.8)** — first-class
|
|
226
|
+
``BBox`` value object with ``inset`` / ``split_h`` / ``split_v`` /
|
|
227
|
+
``grid`` / ``contains`` / ``intersection``. One-call
|
|
228
|
+
``slide.shapes.add_text(bb, text=..., color="#0B5CFF",
|
|
229
|
+
align="center")`` collapses the historical seven-line styling
|
|
230
|
+
ritual. Hex-string shortcuts (``shape.fill_hex("#0B5CFF")``,
|
|
231
|
+
``shape.line_hex(...)``). ``shape.set_text_preserving_format(new)``
|
|
232
|
+
for templated placeholders.
|
|
233
|
+
|
|
234
|
+
* **Real arrows** —
|
|
235
|
+
``slide.shapes.add_arrow(start=a, end=b, head="triangle",
|
|
236
|
+
color="#0B5CFF", inset_pt=6)`` produces a connector with an
|
|
237
|
+
arrowhead and auto-routed endpoints (mid-edge of target shape,
|
|
238
|
+
pulled back by ``inset_pt``). No XML required.
|
|
239
|
+
|
|
240
|
+
* **Diagram recipes** — ``horizontal_pipeline``, ``vertical_pipeline``,
|
|
241
|
+
``hub_and_spoke``, ``cycle``, ``decision_tree``,
|
|
242
|
+
``comparison_columns`` from ``pptx2.diagrams`` cover ~80% of
|
|
243
|
+
architecture-deck patterns. Each takes a slide, a ``BBox``, and a
|
|
244
|
+
content spec.
|
|
245
|
+
|
|
246
|
+
* **Picture and slide helpers** — ``picture.replace_with(builder,
|
|
247
|
+
padding=...)`` deletes a broken / sub-quality picture and calls a
|
|
248
|
+
builder in its place. ``picture.enclosing_container()`` finds the
|
|
249
|
+
surrounding card so the rebuild fills the right area.
|
|
250
|
+
``slide.tidy()`` is the one-call lint + safe auto-fix.
|
|
251
|
+
``slide.find_empty_region(...)`` returns an unused area for
|
|
252
|
+
greenfield placement.
|
|
253
|
+
|
|
254
|
+
* **Whole-deck audit** — ``pptx2.audit(prs)`` returns an
|
|
255
|
+
``AuditReport`` with lint issues, broken pictures, empty slides,
|
|
256
|
+
uncommon-font warnings, and oversized-picture warnings. Markdown
|
|
257
|
+
output for chat replies.
|
|
258
|
+
|
|
259
|
+
* **Visual effects** — outer shadow, glow, soft edges, blur, and
|
|
260
|
+
reflection exposed as non-mutating proxies on every shape;
|
|
261
|
+
alpha-tinted colours (``RGBColor.alpha``); gradient fills with
|
|
262
|
+
``linear`` / ``radial`` / ``rectangular`` / ``shape`` kinds and
|
|
263
|
+
mutable stops; line ends, caps, joins, and compound lines.
|
|
264
|
+
|
|
265
|
+
* **Animations and transitions** — preset entrance / exit / emphasis
|
|
266
|
+
effects; motion-path presets; per-paragraph reveal; sequencing
|
|
267
|
+
context manager; per-slide and deck-wide transitions including
|
|
268
|
+
Morph and the other ``p14:`` extension transitions.
|
|
269
|
+
|
|
270
|
+
* **JSON authoring** — ``pptx2.compose.from_spec(...)`` builds a
|
|
271
|
+
deck from a JSON-shaped spec; ``import_slide`` and
|
|
272
|
+
``apply_template`` cover cross-presentation operations.
|
|
273
|
+
|
|
274
|
+
* **Theme reader and writer** — read theme colours and fonts; write
|
|
275
|
+
fresh ``<a:srgbClr>`` values into the clrScheme; apply a theme
|
|
276
|
+
imported from a ``.potx``.
|
|
277
|
+
|
|
278
|
+
* **Picture effects** — transparency, brightness, contrast, recolor
|
|
279
|
+
(grayscale, sepia, washout, duotone); native SVG embedding with
|
|
280
|
+
PNG fallback.
|
|
281
|
+
|
|
282
|
+
* **Design-system layer** — ``DesignTokens`` (palette, typography,
|
|
283
|
+
shadows, radii, spacings) loadable from a dict, YAML, or a
|
|
284
|
+
``.pptx``; a token-resolving ``shape.style`` facade; ``Grid`` /
|
|
285
|
+
``Stack`` layout primitives; opinionated slide recipes
|
|
286
|
+
(``title``, ``bullet``, ``kpi``, ``quote``, ``image_hero``); a
|
|
287
|
+
starter pack of three example token sets.
|
|
288
|
+
|
|
289
|
+
* **Shape-level building blocks** — ``add_kpi_card``,
|
|
290
|
+
``add_progress_bar``, ``add_gauge``, ``add_status_pill``,
|
|
291
|
+
``add_stat_strip``, ``add_article_card``: token-driven cards that
|
|
292
|
+
return small dataclasses exposing the constituent shapes for
|
|
293
|
+
further tweaks.
|
|
294
|
+
|
|
295
|
+
* **Charting** — chart palette presets independent of
|
|
296
|
+
``chart_style``; ten quick-layout presets; per-series gradient
|
|
297
|
+
and pattern fills.
|
|
298
|
+
|
|
299
|
+
* **3D primitives and SmartArt text substitution** — bevel and
|
|
300
|
+
extrusion via ``shape.three_d``;
|
|
301
|
+
``slide.smart_art[i].set_text([...])``.
|
|
302
|
+
|
|
303
|
+
* **Slide thumbnails** — ``Presentation.render_thumbnails()`` or
|
|
304
|
+
``pptx2.render.render_slides(prs, slides=[0, 1, 2],
|
|
305
|
+
name_template="slide-{:02d}.png")`` shells out to LibreOffice for
|
|
306
|
+
PNG previews.
|
|
307
|
+
|
|
308
|
+
See ``HISTORY.rst`` for the full changelog and ``ROADMAP.md`` for the
|
|
309
|
+
broader plan.
|
|
310
|
+
|
|
311
|
+
Attribution
|
|
312
|
+
-----------
|
|
313
|
+
|
|
314
|
+
This project is a fork of `scanny/python-pptx`_, originally created and
|
|
315
|
+
maintained by Steve Canny under the MIT License. The original
|
|
316
|
+
copyright notice is preserved in ``LICENSE``. Sincere thanks to Steve
|
|
317
|
+
and to all the upstream contributors whose work this project builds
|
|
318
|
+
on.
|
|
319
|
+
|
|
320
|
+
The fork was created to continue development of features the upstream
|
|
321
|
+
roadmap did not cover (notably effects, transitions, animations, theme
|
|
322
|
+
customization, and a higher-level design layer). See ``HISTORY.rst``
|
|
323
|
+
for the divergence point and changelog from there forward.
|
|
324
|
+
|
|
325
|
+
This project is **not** affiliated with or endorsed by Microsoft.
|
|
326
|
+
"PowerPoint" is a trademark of Microsoft Corporation; it is used here
|
|
327
|
+
only descriptively to identify the file format the library reads and
|
|
328
|
+
writes.
|
|
329
|
+
|
|
330
|
+
Documentation
|
|
331
|
+
-------------
|
|
332
|
+
|
|
333
|
+
**Project site:** https://github.com/lofcz/python-pptx2 — the
|
|
334
|
+
Astro/React documentation site (source in ``site/``), plus the
|
|
335
|
+
Sphinx docs under ``docs/``.
|
|
336
|
+
|
|
337
|
+
The Sphinx documentation lives under ``docs/`` and covers both the
|
|
338
|
+
inherited 1.0.2 API and every feature added by the fork. Browse
|
|
339
|
+
`examples with screenshots`_ to get a quick idea what you can do.
|
|
340
|
+
|
|
341
|
+
The bundled Claude Code skill (``python -m pptx2.skill install``)
|
|
342
|
+
is the most up-to-date entry point for using the post-fork APIs.
|
|
343
|
+
|
|
344
|
+
.. _`python-pptx`:
|
|
345
|
+
https://github.com/scanny/python-pptx
|
|
346
|
+
.. _`scanny/python-pptx`:
|
|
347
|
+
https://github.com/scanny/python-pptx
|
|
348
|
+
.. _`Steve Canny`:
|
|
349
|
+
https://github.com/scanny
|
|
350
|
+
.. _`examples with screenshots`:
|
|
351
|
+
https://python-pptx.readthedocs.org/en/latest/user/quickstart.html
|