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/package.py
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
"""Overall .pptx package."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import IO, Iterator
|
|
6
|
+
|
|
7
|
+
from pptx2.opc.constants import RELATIONSHIP_TYPE as RT
|
|
8
|
+
from pptx2.opc.package import OpcPackage
|
|
9
|
+
from pptx2.opc.packuri import PackURI
|
|
10
|
+
from pptx2.parts.coreprops import CorePropertiesPart
|
|
11
|
+
from pptx2.parts.image import Image, ImagePart
|
|
12
|
+
from pptx2.parts.media import MediaPart
|
|
13
|
+
from pptx2.util import lazyproperty
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class Package(OpcPackage):
|
|
17
|
+
"""An overall .pptx package."""
|
|
18
|
+
|
|
19
|
+
@lazyproperty
|
|
20
|
+
def core_properties(self) -> CorePropertiesPart:
|
|
21
|
+
"""Instance of |CoreProperties| holding read/write Dublin Core doc properties.
|
|
22
|
+
|
|
23
|
+
Creates a default core properties part if one is not present (not common).
|
|
24
|
+
"""
|
|
25
|
+
try:
|
|
26
|
+
return self.part_related_by(RT.CORE_PROPERTIES)
|
|
27
|
+
except KeyError:
|
|
28
|
+
core_props = CorePropertiesPart.default(self)
|
|
29
|
+
self.relate_to(core_props, RT.CORE_PROPERTIES)
|
|
30
|
+
return core_props
|
|
31
|
+
|
|
32
|
+
def get_or_add_image_part(self, image_file: str | IO[bytes]):
|
|
33
|
+
"""
|
|
34
|
+
Return an |ImagePart| object containing the image in *image_file*. If
|
|
35
|
+
the image part already exists in this package, it is reused,
|
|
36
|
+
otherwise a new one is created.
|
|
37
|
+
"""
|
|
38
|
+
return self._image_parts.get_or_add_image_part(image_file)
|
|
39
|
+
|
|
40
|
+
def get_or_add_media_part(self, media):
|
|
41
|
+
"""Return a |MediaPart| object containing the media in *media*.
|
|
42
|
+
|
|
43
|
+
If a media part for this media bytestream ("file") is already present
|
|
44
|
+
in this package, it is reused, otherwise a new one is created.
|
|
45
|
+
"""
|
|
46
|
+
return self._media_parts.get_or_add_media_part(media)
|
|
47
|
+
|
|
48
|
+
def next_image_partname(self, ext: str) -> PackURI:
|
|
49
|
+
"""Return a |PackURI| instance representing the next available image partname.
|
|
50
|
+
|
|
51
|
+
Partname uses the next available sequence number. *ext* is used as the extention on the
|
|
52
|
+
returned partname.
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
def first_available_image_idx():
|
|
56
|
+
image_idxs = sorted(
|
|
57
|
+
[
|
|
58
|
+
part.partname.idx
|
|
59
|
+
for part in self.iter_parts()
|
|
60
|
+
if (
|
|
61
|
+
part.partname.startswith("/ppt/media/image")
|
|
62
|
+
and part.partname.idx is not None
|
|
63
|
+
)
|
|
64
|
+
]
|
|
65
|
+
)
|
|
66
|
+
for i, image_idx in enumerate(image_idxs):
|
|
67
|
+
idx = i + 1
|
|
68
|
+
if idx < image_idx:
|
|
69
|
+
return idx
|
|
70
|
+
return len(image_idxs) + 1
|
|
71
|
+
|
|
72
|
+
idx = first_available_image_idx()
|
|
73
|
+
return PackURI("/ppt/media/image%d.%s" % (idx, ext))
|
|
74
|
+
|
|
75
|
+
def next_media_partname(self, ext):
|
|
76
|
+
"""Return |PackURI| instance for next available media partname.
|
|
77
|
+
|
|
78
|
+
Partname is first available, starting at sequence number 1. Empty
|
|
79
|
+
sequence numbers are reused. *ext* is used as the extension on the
|
|
80
|
+
returned partname.
|
|
81
|
+
"""
|
|
82
|
+
|
|
83
|
+
def first_available_media_idx():
|
|
84
|
+
media_idxs = sorted(
|
|
85
|
+
[
|
|
86
|
+
part.partname.idx
|
|
87
|
+
for part in self.iter_parts()
|
|
88
|
+
if part.partname.startswith("/ppt/media/media")
|
|
89
|
+
]
|
|
90
|
+
)
|
|
91
|
+
for i, media_idx in enumerate(media_idxs):
|
|
92
|
+
idx = i + 1
|
|
93
|
+
if idx < media_idx:
|
|
94
|
+
return idx
|
|
95
|
+
return len(media_idxs) + 1
|
|
96
|
+
|
|
97
|
+
idx = first_available_media_idx()
|
|
98
|
+
return PackURI("/ppt/media/media%d.%s" % (idx, ext))
|
|
99
|
+
|
|
100
|
+
@property
|
|
101
|
+
def presentation_part(self):
|
|
102
|
+
"""
|
|
103
|
+
Reference to the |Presentation| instance contained in this package.
|
|
104
|
+
"""
|
|
105
|
+
return self.main_document_part
|
|
106
|
+
|
|
107
|
+
@lazyproperty
|
|
108
|
+
def _image_parts(self):
|
|
109
|
+
"""
|
|
110
|
+
|_ImageParts| object providing access to the image parts in this
|
|
111
|
+
package.
|
|
112
|
+
"""
|
|
113
|
+
return _ImageParts(self)
|
|
114
|
+
|
|
115
|
+
@lazyproperty
|
|
116
|
+
def _media_parts(self):
|
|
117
|
+
"""Return |_MediaParts| object for this package.
|
|
118
|
+
|
|
119
|
+
The media parts object provides access to all the media parts in this
|
|
120
|
+
package.
|
|
121
|
+
"""
|
|
122
|
+
return _MediaParts(self)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
class _ImageParts(object):
|
|
126
|
+
"""Provides access to the image parts in a package."""
|
|
127
|
+
|
|
128
|
+
def __init__(self, package):
|
|
129
|
+
super(_ImageParts, self).__init__()
|
|
130
|
+
self._package = package
|
|
131
|
+
|
|
132
|
+
def __iter__(self) -> Iterator[ImagePart]:
|
|
133
|
+
"""Generate a reference to each |ImagePart| object in the package."""
|
|
134
|
+
image_parts = []
|
|
135
|
+
for rel in self._package.iter_rels():
|
|
136
|
+
if rel.is_external:
|
|
137
|
+
continue
|
|
138
|
+
if rel.reltype != RT.IMAGE:
|
|
139
|
+
continue
|
|
140
|
+
image_part = rel.target_part
|
|
141
|
+
if image_part in image_parts:
|
|
142
|
+
continue
|
|
143
|
+
image_parts.append(image_part)
|
|
144
|
+
yield image_part
|
|
145
|
+
|
|
146
|
+
def get_or_add_image_part(self, image_file: str | IO[bytes]) -> ImagePart:
|
|
147
|
+
"""Return |ImagePart| object containing the image in `image_file`.
|
|
148
|
+
|
|
149
|
+
`image_file` can be either a path to an image file or a file-like object
|
|
150
|
+
containing an image. If an image part containing this same image already exists,
|
|
151
|
+
that instance is returned, otherwise a new image part is created.
|
|
152
|
+
"""
|
|
153
|
+
image = Image.from_file(image_file)
|
|
154
|
+
image_part = self._find_by_sha1(image.sha1)
|
|
155
|
+
return image_part if image_part else ImagePart.new(self._package, image)
|
|
156
|
+
|
|
157
|
+
def _find_by_sha1(self, sha1: str) -> ImagePart | None:
|
|
158
|
+
"""
|
|
159
|
+
Return an |ImagePart| object belonging to this package or |None| if
|
|
160
|
+
no matching image part is found. The image part is identified by the
|
|
161
|
+
SHA1 hash digest of the image binary it contains.
|
|
162
|
+
"""
|
|
163
|
+
for image_part in self:
|
|
164
|
+
# ---skip unknown/unsupported image types, like SVG---
|
|
165
|
+
if not hasattr(image_part, "sha1"):
|
|
166
|
+
continue
|
|
167
|
+
if image_part.sha1 == sha1:
|
|
168
|
+
return image_part
|
|
169
|
+
return None
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
class _MediaParts(object):
|
|
173
|
+
"""Provides access to the media parts in a package.
|
|
174
|
+
|
|
175
|
+
Supports iteration and :meth:`get()` using the media object SHA1 hash as
|
|
176
|
+
its key.
|
|
177
|
+
"""
|
|
178
|
+
|
|
179
|
+
def __init__(self, package):
|
|
180
|
+
super(_MediaParts, self).__init__()
|
|
181
|
+
self._package = package
|
|
182
|
+
|
|
183
|
+
def __iter__(self):
|
|
184
|
+
"""Generate a reference to each |MediaPart| object in the package."""
|
|
185
|
+
# A media part can appear in more than one relationship (and commonly
|
|
186
|
+
# does in the case of video). Use media_parts to keep track of those
|
|
187
|
+
# that have been "yielded"; they can be skipped if they occur again.
|
|
188
|
+
media_parts = []
|
|
189
|
+
for rel in self._package.iter_rels():
|
|
190
|
+
if rel.is_external:
|
|
191
|
+
continue
|
|
192
|
+
if rel.reltype not in (RT.MEDIA, RT.VIDEO):
|
|
193
|
+
continue
|
|
194
|
+
media_part = rel.target_part
|
|
195
|
+
if media_part in media_parts:
|
|
196
|
+
continue
|
|
197
|
+
media_parts.append(media_part)
|
|
198
|
+
yield media_part
|
|
199
|
+
|
|
200
|
+
def get_or_add_media_part(self, media):
|
|
201
|
+
"""Return a |MediaPart| object containing the media in *media*.
|
|
202
|
+
|
|
203
|
+
If this package already contains a media part for the same
|
|
204
|
+
bytestream, that instance is returned, otherwise a new media part is
|
|
205
|
+
created.
|
|
206
|
+
"""
|
|
207
|
+
media_part = self._find_by_sha1(media.sha1)
|
|
208
|
+
if media_part is None:
|
|
209
|
+
media_part = MediaPart.new(self._package, media)
|
|
210
|
+
return media_part
|
|
211
|
+
|
|
212
|
+
def _find_by_sha1(self, sha1):
|
|
213
|
+
"""Return |MediaPart| object having *sha1* hash or None if not found.
|
|
214
|
+
|
|
215
|
+
All media parts belonging to this package are considered. A media
|
|
216
|
+
part is identified by the SHA1 hash digest of its bytestream
|
|
217
|
+
("file").
|
|
218
|
+
"""
|
|
219
|
+
for media_part in self:
|
|
220
|
+
if media_part.sha1 == sha1:
|
|
221
|
+
return media_part
|
|
222
|
+
return None
|
pptx2/parts/__init__.py
ADDED
|
File without changes
|
pptx2/parts/chart.py
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"""Chart part objects, including Chart and Charts."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
|
+
|
|
7
|
+
from pptx2.chart.chart import Chart
|
|
8
|
+
from pptx2.opc.constants import CONTENT_TYPE as CT
|
|
9
|
+
from pptx2.opc.constants import RELATIONSHIP_TYPE as RT
|
|
10
|
+
from pptx2.opc.package import XmlPart
|
|
11
|
+
from pptx2.parts.embeddedpackage import EmbeddedXlsxPart
|
|
12
|
+
from pptx2.util import lazyproperty
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from pptx2.chart.data import ChartData
|
|
16
|
+
from pptx2.enum.chart import XL_CHART_TYPE
|
|
17
|
+
from pptx2.package import Package
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class ChartPart(XmlPart):
|
|
21
|
+
"""A chart part.
|
|
22
|
+
|
|
23
|
+
Corresponds to parts having partnames matching ppt/charts/chart[1-9][0-9]*.xml
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
partname_template = "/ppt/charts/chart%d.xml"
|
|
27
|
+
|
|
28
|
+
@classmethod
|
|
29
|
+
def new(cls, chart_type: XL_CHART_TYPE, chart_data: ChartData, package: Package):
|
|
30
|
+
"""Return new |ChartPart| instance added to `package`.
|
|
31
|
+
|
|
32
|
+
Returned chart-part contains a chart of `chart_type` depicting `chart_data`.
|
|
33
|
+
"""
|
|
34
|
+
chart_part = cls.load(
|
|
35
|
+
package.next_partname(cls.partname_template),
|
|
36
|
+
CT.DML_CHART,
|
|
37
|
+
package,
|
|
38
|
+
chart_data.xml_bytes(chart_type),
|
|
39
|
+
)
|
|
40
|
+
chart_part.chart_workbook.update_from_xlsx_blob(chart_data.xlsx_blob)
|
|
41
|
+
return chart_part
|
|
42
|
+
|
|
43
|
+
@lazyproperty
|
|
44
|
+
def chart(self):
|
|
45
|
+
"""|Chart| object representing the chart in this part."""
|
|
46
|
+
return Chart(self._element, self)
|
|
47
|
+
|
|
48
|
+
@lazyproperty
|
|
49
|
+
def chart_workbook(self):
|
|
50
|
+
"""
|
|
51
|
+
The |ChartWorkbook| object providing access to the external chart
|
|
52
|
+
data in a linked or embedded Excel workbook.
|
|
53
|
+
"""
|
|
54
|
+
return ChartWorkbook(self._element, self)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class ChartWorkbook(object):
|
|
58
|
+
"""Provides access to external chart data in a linked or embedded Excel workbook."""
|
|
59
|
+
|
|
60
|
+
def __init__(self, chartSpace, chart_part):
|
|
61
|
+
super(ChartWorkbook, self).__init__()
|
|
62
|
+
self._chartSpace = chartSpace
|
|
63
|
+
self._chart_part = chart_part
|
|
64
|
+
|
|
65
|
+
def update_from_xlsx_blob(self, xlsx_blob):
|
|
66
|
+
"""
|
|
67
|
+
Replace the Excel spreadsheet in the related |EmbeddedXlsxPart| with
|
|
68
|
+
the Excel binary in *xlsx_blob*, adding a new |EmbeddedXlsxPart| if
|
|
69
|
+
there isn't one.
|
|
70
|
+
"""
|
|
71
|
+
xlsx_part = self.xlsx_part
|
|
72
|
+
if xlsx_part is None:
|
|
73
|
+
self.xlsx_part = EmbeddedXlsxPart.new(xlsx_blob, self._chart_part.package)
|
|
74
|
+
return
|
|
75
|
+
xlsx_part.blob = xlsx_blob
|
|
76
|
+
|
|
77
|
+
@property
|
|
78
|
+
def xlsx_part(self):
|
|
79
|
+
"""Optional |EmbeddedXlsxPart| object containing data for this chart.
|
|
80
|
+
|
|
81
|
+
This related part has its rId at `c:chartSpace/c:externalData/@rId`. This value
|
|
82
|
+
is |None| if there is no `<c:externalData>` element.
|
|
83
|
+
"""
|
|
84
|
+
xlsx_part_rId = self._chartSpace.xlsx_part_rId
|
|
85
|
+
return None if xlsx_part_rId is None else self._chart_part.related_part(xlsx_part_rId)
|
|
86
|
+
|
|
87
|
+
@xlsx_part.setter
|
|
88
|
+
def xlsx_part(self, xlsx_part):
|
|
89
|
+
"""
|
|
90
|
+
Set the related |EmbeddedXlsxPart| to *xlsx_part*. Assume one does
|
|
91
|
+
not already exist.
|
|
92
|
+
"""
|
|
93
|
+
rId = self._chart_part.relate_to(xlsx_part, RT.PACKAGE)
|
|
94
|
+
externalData = self._chartSpace.get_or_add_externalData()
|
|
95
|
+
externalData.rId = rId
|
pptx2/parts/coreprops.py
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"""Core properties part, corresponds to ``/docProps/core.xml`` part in package."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import datetime as dt
|
|
6
|
+
from typing import TYPE_CHECKING
|
|
7
|
+
|
|
8
|
+
from pptx2.opc.constants import CONTENT_TYPE as CT
|
|
9
|
+
from pptx2.opc.package import XmlPart
|
|
10
|
+
from pptx2.opc.packuri import PackURI
|
|
11
|
+
from pptx2.oxml.coreprops import CT_CoreProperties
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from pptx2.package import Package
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class CorePropertiesPart(XmlPart):
|
|
18
|
+
"""Corresponds to part named `/docProps/core.xml`.
|
|
19
|
+
|
|
20
|
+
Contains the core document properties for this document package.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
_element: CT_CoreProperties
|
|
24
|
+
|
|
25
|
+
@classmethod
|
|
26
|
+
def default(cls, package: Package):
|
|
27
|
+
"""Return default new |CorePropertiesPart| instance suitable as starting point.
|
|
28
|
+
|
|
29
|
+
This provides a base for adding core-properties to a package that doesn't yet
|
|
30
|
+
have any.
|
|
31
|
+
"""
|
|
32
|
+
core_props = cls._new(package)
|
|
33
|
+
core_props.title = "PowerPoint Presentation"
|
|
34
|
+
core_props.last_modified_by = "python-pptx"
|
|
35
|
+
core_props.revision = 1
|
|
36
|
+
core_props.modified = dt.datetime.now(dt.timezone.utc).replace(tzinfo=None)
|
|
37
|
+
return core_props
|
|
38
|
+
|
|
39
|
+
@property
|
|
40
|
+
def author(self) -> str:
|
|
41
|
+
return self._element.author_text
|
|
42
|
+
|
|
43
|
+
@author.setter
|
|
44
|
+
def author(self, value: str):
|
|
45
|
+
self._element.author_text = value
|
|
46
|
+
|
|
47
|
+
@property
|
|
48
|
+
def category(self) -> str:
|
|
49
|
+
return self._element.category_text
|
|
50
|
+
|
|
51
|
+
@category.setter
|
|
52
|
+
def category(self, value: str):
|
|
53
|
+
self._element.category_text = value
|
|
54
|
+
|
|
55
|
+
@property
|
|
56
|
+
def comments(self) -> str:
|
|
57
|
+
return self._element.comments_text
|
|
58
|
+
|
|
59
|
+
@comments.setter
|
|
60
|
+
def comments(self, value: str):
|
|
61
|
+
self._element.comments_text = value
|
|
62
|
+
|
|
63
|
+
@property
|
|
64
|
+
def content_status(self) -> str:
|
|
65
|
+
return self._element.contentStatus_text
|
|
66
|
+
|
|
67
|
+
@content_status.setter
|
|
68
|
+
def content_status(self, value: str):
|
|
69
|
+
self._element.contentStatus_text = value
|
|
70
|
+
|
|
71
|
+
@property
|
|
72
|
+
def created(self):
|
|
73
|
+
return self._element.created_datetime
|
|
74
|
+
|
|
75
|
+
@created.setter
|
|
76
|
+
def created(self, value: dt.datetime):
|
|
77
|
+
self._element.created_datetime = value
|
|
78
|
+
|
|
79
|
+
@property
|
|
80
|
+
def identifier(self) -> str:
|
|
81
|
+
return self._element.identifier_text
|
|
82
|
+
|
|
83
|
+
@identifier.setter
|
|
84
|
+
def identifier(self, value: str):
|
|
85
|
+
self._element.identifier_text = value
|
|
86
|
+
|
|
87
|
+
@property
|
|
88
|
+
def keywords(self) -> str:
|
|
89
|
+
return self._element.keywords_text
|
|
90
|
+
|
|
91
|
+
@keywords.setter
|
|
92
|
+
def keywords(self, value: str):
|
|
93
|
+
self._element.keywords_text = value
|
|
94
|
+
|
|
95
|
+
@property
|
|
96
|
+
def language(self) -> str:
|
|
97
|
+
return self._element.language_text
|
|
98
|
+
|
|
99
|
+
@language.setter
|
|
100
|
+
def language(self, value: str):
|
|
101
|
+
self._element.language_text = value
|
|
102
|
+
|
|
103
|
+
@property
|
|
104
|
+
def last_modified_by(self) -> str:
|
|
105
|
+
return self._element.lastModifiedBy_text
|
|
106
|
+
|
|
107
|
+
@last_modified_by.setter
|
|
108
|
+
def last_modified_by(self, value: str):
|
|
109
|
+
self._element.lastModifiedBy_text = value
|
|
110
|
+
|
|
111
|
+
@property
|
|
112
|
+
def last_printed(self):
|
|
113
|
+
return self._element.lastPrinted_datetime
|
|
114
|
+
|
|
115
|
+
@last_printed.setter
|
|
116
|
+
def last_printed(self, value: dt.datetime):
|
|
117
|
+
self._element.lastPrinted_datetime = value
|
|
118
|
+
|
|
119
|
+
@property
|
|
120
|
+
def modified(self):
|
|
121
|
+
return self._element.modified_datetime
|
|
122
|
+
|
|
123
|
+
@modified.setter
|
|
124
|
+
def modified(self, value: dt.datetime):
|
|
125
|
+
self._element.modified_datetime = value
|
|
126
|
+
|
|
127
|
+
@property
|
|
128
|
+
def revision(self):
|
|
129
|
+
return self._element.revision_number
|
|
130
|
+
|
|
131
|
+
@revision.setter
|
|
132
|
+
def revision(self, value: int):
|
|
133
|
+
self._element.revision_number = value
|
|
134
|
+
|
|
135
|
+
@property
|
|
136
|
+
def subject(self) -> str:
|
|
137
|
+
return self._element.subject_text
|
|
138
|
+
|
|
139
|
+
@subject.setter
|
|
140
|
+
def subject(self, value: str):
|
|
141
|
+
self._element.subject_text = value
|
|
142
|
+
|
|
143
|
+
@property
|
|
144
|
+
def title(self) -> str:
|
|
145
|
+
return self._element.title_text
|
|
146
|
+
|
|
147
|
+
@title.setter
|
|
148
|
+
def title(self, value: str):
|
|
149
|
+
self._element.title_text = value
|
|
150
|
+
|
|
151
|
+
@property
|
|
152
|
+
def version(self) -> str:
|
|
153
|
+
return self._element.version_text
|
|
154
|
+
|
|
155
|
+
@version.setter
|
|
156
|
+
def version(self, value: str):
|
|
157
|
+
self._element.version_text = value
|
|
158
|
+
|
|
159
|
+
@classmethod
|
|
160
|
+
def _new(cls, package: Package) -> CorePropertiesPart:
|
|
161
|
+
"""Return new empty |CorePropertiesPart| instance."""
|
|
162
|
+
return CorePropertiesPart(
|
|
163
|
+
PackURI("/docProps/core.xml"),
|
|
164
|
+
CT.OPC_CORE_PROPERTIES,
|
|
165
|
+
package,
|
|
166
|
+
CT_CoreProperties.new_coreProperties(),
|
|
167
|
+
)
|
pptx2/parts/diagram.py
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""Diagram part objects for SmartArt diagrams."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pptx2.opc.package import XmlPart
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class DiagramDataPart(XmlPart):
|
|
9
|
+
"""Part wrapping a ``diagrams/data#.xml`` file (SmartArt data model).
|
|
10
|
+
|
|
11
|
+
Content-type:
|
|
12
|
+
``application/vnd.openxmlformats-officedocument.drawingml.diagramData+xml``
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class DiagramLayoutPart(XmlPart):
|
|
17
|
+
"""Part wrapping a ``diagrams/layout#.xml`` file (SmartArt layout definition).
|
|
18
|
+
|
|
19
|
+
Content-type:
|
|
20
|
+
``application/vnd.openxmlformats-officedocument.drawingml.diagramLayout+xml``
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class DiagramStylePart(XmlPart):
|
|
25
|
+
"""Part wrapping a ``diagrams/quickStyle#.xml`` file (SmartArt quick-style).
|
|
26
|
+
|
|
27
|
+
Content-type:
|
|
28
|
+
``application/vnd.openxmlformats-officedocument.drawingml.diagramStyle+xml``
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class DiagramColorsPart(XmlPart):
|
|
33
|
+
"""Part wrapping a ``diagrams/colors#.xml`` file (SmartArt color style).
|
|
34
|
+
|
|
35
|
+
Content-type:
|
|
36
|
+
``application/vnd.openxmlformats-officedocument.drawingml.diagramColors+xml``
|
|
37
|
+
"""
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"""Embedded Package part objects.
|
|
2
|
+
|
|
3
|
+
"Package" in this context means another OPC package, i.e. a DOCX, PPTX, or XLSX "file".
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from typing import TYPE_CHECKING
|
|
9
|
+
|
|
10
|
+
from pptx2.enum.shapes import PROG_ID
|
|
11
|
+
from pptx2.opc.constants import CONTENT_TYPE as CT
|
|
12
|
+
from pptx2.opc.package import Part
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from pptx2.package import Package
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class EmbeddedPackagePart(Part):
|
|
19
|
+
"""A distinct OPC package, e.g. an Excel file, embedded in this PPTX package.
|
|
20
|
+
|
|
21
|
+
Has a partname like: `ppt/embeddings/Microsoft_Excel_Sheet1.xlsx`.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
@classmethod
|
|
25
|
+
def factory(cls, prog_id: PROG_ID | str, object_blob: bytes, package: Package):
|
|
26
|
+
"""Return a new |EmbeddedPackagePart| subclass instance added to *package*.
|
|
27
|
+
|
|
28
|
+
The subclass is determined by `prog_id` which corresponds to the "application"
|
|
29
|
+
used to open the "file-type" of `object_blob`. The returned part contains the
|
|
30
|
+
bytes of `object_blob` and has the content-type also determined by `prog_id`.
|
|
31
|
+
"""
|
|
32
|
+
# --- a generic OLE object has no subclass ---
|
|
33
|
+
if not isinstance(prog_id, PROG_ID):
|
|
34
|
+
return cls(
|
|
35
|
+
package.next_partname("/ppt/embeddings/oleObject%d.bin"),
|
|
36
|
+
CT.OFC_OLE_OBJECT,
|
|
37
|
+
package,
|
|
38
|
+
object_blob,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
# --- A Microsoft Office file-type is a distinguished package object ---
|
|
42
|
+
EmbeddedPartCls = {
|
|
43
|
+
PROG_ID.DOCX: EmbeddedDocxPart,
|
|
44
|
+
PROG_ID.PPTX: EmbeddedPptxPart,
|
|
45
|
+
PROG_ID.XLSX: EmbeddedXlsxPart,
|
|
46
|
+
}[prog_id]
|
|
47
|
+
|
|
48
|
+
return EmbeddedPartCls.new(object_blob, package)
|
|
49
|
+
|
|
50
|
+
@classmethod
|
|
51
|
+
def new(cls, blob: bytes, package: Package):
|
|
52
|
+
"""Return new |EmbeddedPackagePart| subclass object.
|
|
53
|
+
|
|
54
|
+
The returned part object contains `blob` and is added to `package`.
|
|
55
|
+
"""
|
|
56
|
+
return cls(
|
|
57
|
+
package.next_partname(cls.partname_template),
|
|
58
|
+
cls.content_type,
|
|
59
|
+
package,
|
|
60
|
+
blob,
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class EmbeddedDocxPart(EmbeddedPackagePart):
|
|
65
|
+
"""A Word .docx file stored in a part.
|
|
66
|
+
|
|
67
|
+
This part-type arises when a Word document appears as an embedded OLE-object shape.
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
partname_template = "/ppt/embeddings/Microsoft_Word_Document%d.docx"
|
|
71
|
+
content_type = CT.WML_DOCUMENT
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class EmbeddedPptxPart(EmbeddedPackagePart):
|
|
75
|
+
"""A PowerPoint file stored in a part.
|
|
76
|
+
|
|
77
|
+
This part-type arises when a PowerPoint presentation (.pptx file) appears as an
|
|
78
|
+
embedded OLE-object shape.
|
|
79
|
+
"""
|
|
80
|
+
|
|
81
|
+
partname_template = "/ppt/embeddings/Microsoft_PowerPoint_Presentation%d.pptx"
|
|
82
|
+
content_type = CT.PML_PRESENTATION
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class EmbeddedXlsxPart(EmbeddedPackagePart):
|
|
86
|
+
"""An Excel file stored in a part.
|
|
87
|
+
|
|
88
|
+
This part-type arises as the data source for a chart, but may also be the OLE-object
|
|
89
|
+
for an embedded object shape.
|
|
90
|
+
"""
|
|
91
|
+
|
|
92
|
+
partname_template = "/ppt/embeddings/Microsoft_Excel_Sheet%d.xlsx"
|
|
93
|
+
content_type = CT.SML_SHEET
|