ps-python-pptx 1.1.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 (117) hide show
  1. pptx/__init__.py +84 -0
  2. pptx/action.py +270 -0
  3. pptx/api.py +49 -0
  4. pptx/chart/__init__.py +0 -0
  5. pptx/chart/axis.py +523 -0
  6. pptx/chart/category.py +200 -0
  7. pptx/chart/chart.py +280 -0
  8. pptx/chart/data.py +864 -0
  9. pptx/chart/datalabel.py +288 -0
  10. pptx/chart/legend.py +79 -0
  11. pptx/chart/marker.py +70 -0
  12. pptx/chart/plot.py +412 -0
  13. pptx/chart/point.py +101 -0
  14. pptx/chart/series.py +258 -0
  15. pptx/chart/xlsx.py +272 -0
  16. pptx/chart/xmlwriter.py +1840 -0
  17. pptx/dml/__init__.py +0 -0
  18. pptx/dml/chtfmt.py +40 -0
  19. pptx/dml/color.py +301 -0
  20. pptx/dml/effect.py +41 -0
  21. pptx/dml/fill.py +468 -0
  22. pptx/dml/line.py +100 -0
  23. pptx/enum/__init__.py +0 -0
  24. pptx/enum/action.py +71 -0
  25. pptx/enum/base.py +175 -0
  26. pptx/enum/chart.py +492 -0
  27. pptx/enum/dml.py +405 -0
  28. pptx/enum/lang.py +685 -0
  29. pptx/enum/shapes.py +1029 -0
  30. pptx/enum/text.py +371 -0
  31. pptx/exc.py +23 -0
  32. pptx/media.py +197 -0
  33. pptx/opc/__init__.py +0 -0
  34. pptx/opc/constants.py +331 -0
  35. pptx/opc/oxml.py +188 -0
  36. pptx/opc/package.py +762 -0
  37. pptx/opc/packuri.py +109 -0
  38. pptx/opc/serialized.py +296 -0
  39. pptx/opc/shared.py +20 -0
  40. pptx/opc/spec.py +44 -0
  41. pptx/oxml/__init__.py +492 -0
  42. pptx/oxml/action.py +53 -0
  43. pptx/oxml/chart/__init__.py +0 -0
  44. pptx/oxml/chart/axis.py +297 -0
  45. pptx/oxml/chart/chart.py +282 -0
  46. pptx/oxml/chart/datalabel.py +252 -0
  47. pptx/oxml/chart/legend.py +72 -0
  48. pptx/oxml/chart/marker.py +61 -0
  49. pptx/oxml/chart/plot.py +345 -0
  50. pptx/oxml/chart/series.py +254 -0
  51. pptx/oxml/chart/shared.py +219 -0
  52. pptx/oxml/coreprops.py +288 -0
  53. pptx/oxml/dml/__init__.py +0 -0
  54. pptx/oxml/dml/color.py +111 -0
  55. pptx/oxml/dml/fill.py +197 -0
  56. pptx/oxml/dml/line.py +12 -0
  57. pptx/oxml/ns.py +129 -0
  58. pptx/oxml/presentation.py +130 -0
  59. pptx/oxml/shapes/__init__.py +19 -0
  60. pptx/oxml/shapes/autoshape.py +455 -0
  61. pptx/oxml/shapes/connector.py +107 -0
  62. pptx/oxml/shapes/graphfrm.py +342 -0
  63. pptx/oxml/shapes/groupshape.py +280 -0
  64. pptx/oxml/shapes/picture.py +270 -0
  65. pptx/oxml/shapes/shared.py +523 -0
  66. pptx/oxml/simpletypes.py +740 -0
  67. pptx/oxml/slide.py +347 -0
  68. pptx/oxml/table.py +588 -0
  69. pptx/oxml/text.py +748 -0
  70. pptx/oxml/theme.py +29 -0
  71. pptx/oxml/xmlchemy.py +717 -0
  72. pptx/package.py +222 -0
  73. pptx/parts/__init__.py +0 -0
  74. pptx/parts/chart.py +95 -0
  75. pptx/parts/coreprops.py +167 -0
  76. pptx/parts/embeddedpackage.py +93 -0
  77. pptx/parts/image.py +275 -0
  78. pptx/parts/media.py +37 -0
  79. pptx/parts/presentation.py +126 -0
  80. pptx/parts/slide.py +297 -0
  81. pptx/parts/theme.py +13 -0
  82. pptx/presentation.py +113 -0
  83. pptx/py.typed +0 -0
  84. pptx/shapes/__init__.py +26 -0
  85. pptx/shapes/autoshape.py +355 -0
  86. pptx/shapes/base.py +293 -0
  87. pptx/shapes/connector.py +297 -0
  88. pptx/shapes/freeform.py +337 -0
  89. pptx/shapes/graphfrm.py +166 -0
  90. pptx/shapes/group.py +69 -0
  91. pptx/shapes/picture.py +203 -0
  92. pptx/shapes/placeholder.py +407 -0
  93. pptx/shapes/shapetree.py +1190 -0
  94. pptx/shared.py +82 -0
  95. pptx/slide.py +577 -0
  96. pptx/spec.py +632 -0
  97. pptx/table.py +520 -0
  98. pptx/templates/default.pptx +0 -0
  99. pptx/templates/docx-icon.emf +0 -0
  100. pptx/templates/generic-icon.emf +0 -0
  101. pptx/templates/notes.xml +23 -0
  102. pptx/templates/notesMaster.xml +352 -0
  103. pptx/templates/pptx-icon.emf +0 -0
  104. pptx/templates/theme.xml +321 -0
  105. pptx/templates/xlsx-icon.emf +0 -0
  106. pptx/text/__init__.py +0 -0
  107. pptx/text/fonts.py +399 -0
  108. pptx/text/layout.py +325 -0
  109. pptx/text/text.py +770 -0
  110. pptx/theme.py +135 -0
  111. pptx/types.py +36 -0
  112. pptx/util.py +284 -0
  113. ps_python_pptx-1.1.0.dist-info/METADATA +75 -0
  114. ps_python_pptx-1.1.0.dist-info/RECORD +117 -0
  115. ps_python_pptx-1.1.0.dist-info/WHEEL +5 -0
  116. ps_python_pptx-1.1.0.dist-info/licenses/LICENSE +20 -0
  117. ps_python_pptx-1.1.0.dist-info/top_level.txt +1 -0
pptx/chart/category.py ADDED
@@ -0,0 +1,200 @@
1
+ """Category-related objects.
2
+
3
+ The |category.Categories| object is returned by ``Plot.categories`` and contains zero or
4
+ more |category.Category| objects, each representing one of the category labels
5
+ associated with the plot. Categories can be hierarchical, so there are members allowing
6
+ discovery of the depth of that hierarchy and providing means to navigate it.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from collections.abc import Sequence
12
+
13
+
14
+ class Categories(Sequence):
15
+ """
16
+ A sequence of |category.Category| objects, each representing a category
17
+ label on the chart. Provides properties for dealing with hierarchical
18
+ categories.
19
+ """
20
+
21
+ def __init__(self, xChart):
22
+ super(Categories, self).__init__()
23
+ self._xChart = xChart
24
+
25
+ def __getitem__(self, idx):
26
+ pt = self._xChart.cat_pts[idx]
27
+ return Category(pt, idx)
28
+
29
+ def __iter__(self):
30
+ cat_pts = self._xChart.cat_pts
31
+ for idx, pt in enumerate(cat_pts):
32
+ yield Category(pt, idx)
33
+
34
+ def __len__(self):
35
+ # a category can be "null", meaning the Excel cell for it is empty.
36
+ # In this case, there is no c:pt element for it. The "empty" category
37
+ # will, however, be accounted for in c:cat//c:ptCount/@val, which
38
+ # reflects the true length of the categories collection.
39
+ return self._xChart.cat_pt_count
40
+
41
+ @property
42
+ def depth(self):
43
+ """
44
+ Return an integer representing the number of hierarchical levels in
45
+ this category collection. Returns 1 for non-hierarchical categories
46
+ and 0 if no categories are present (generally meaning no series are
47
+ present).
48
+ """
49
+ cat = self._xChart.cat
50
+ if cat is None:
51
+ return 0
52
+ if cat.multiLvlStrRef is None:
53
+ return 1
54
+ return len(cat.lvls)
55
+
56
+ @property
57
+ def flattened_labels(self):
58
+ """
59
+ Return a sequence of tuples, each containing the flattened hierarchy
60
+ of category labels for a leaf category. Each tuple is in parent ->
61
+ child order, e.g. ``('US', 'CA', 'San Francisco')``, with the leaf
62
+ category appearing last. If this categories collection is
63
+ non-hierarchical, each tuple will contain only a leaf category label.
64
+ If the plot has no series (and therefore no categories), an empty
65
+ tuple is returned.
66
+ """
67
+ cat = self._xChart.cat
68
+ if cat is None:
69
+ return ()
70
+
71
+ if cat.multiLvlStrRef is None:
72
+ return tuple([(category.label,) for category in self])
73
+
74
+ return tuple(
75
+ [
76
+ tuple([category.label for category in reversed(flat_cat)])
77
+ for flat_cat in self._iter_flattened_categories()
78
+ ]
79
+ )
80
+
81
+ @property
82
+ def levels(self):
83
+ """
84
+ Return a sequence of |CategoryLevel| objects representing the
85
+ hierarchy of this category collection. The sequence is empty when the
86
+ category collection is not hierarchical, that is, contains only
87
+ leaf-level categories. The levels are ordered from the leaf level to
88
+ the root level; so the first level will contain the same categories
89
+ as this category collection.
90
+ """
91
+ cat = self._xChart.cat
92
+ if cat is None:
93
+ return []
94
+ return [CategoryLevel(lvl) for lvl in cat.lvls]
95
+
96
+ def _iter_flattened_categories(self):
97
+ """
98
+ Generate a ``tuple`` object for each leaf category in this
99
+ collection, containing the leaf category followed by its "parent"
100
+ categories, e.g. ``('San Francisco', 'CA', 'USA'). Each tuple will be
101
+ the same length as the number of levels (excepting certain edge
102
+ cases which I believe always indicate a chart construction error).
103
+ """
104
+ levels = self.levels
105
+ if not levels:
106
+ return
107
+ leaf_level, remaining_levels = levels[0], levels[1:]
108
+ for category in leaf_level:
109
+ yield self._parentage((category,), remaining_levels)
110
+
111
+ def _parentage(self, categories, levels):
112
+ """
113
+ Return a tuple formed by recursively concatenating *categories* with
114
+ its next ancestor from *levels*. The idx value of the first category
115
+ in *categories* determines parentage in all levels. The returned
116
+ sequence is in child -> parent order. A parent category is the
117
+ Category object in a next level having the maximum idx value not
118
+ exceeding that of the leaf category.
119
+ """
120
+ # exhausting levels is the expected recursion termination condition
121
+ if not levels:
122
+ return tuple(categories)
123
+
124
+ # guard against edge case where next level is present but empty. That
125
+ # situation is not prohibited for some reason.
126
+ if not levels[0]:
127
+ return tuple(categories)
128
+
129
+ parent_level, remaining_levels = levels[0], levels[1:]
130
+ leaf_node = categories[0]
131
+
132
+ # Make the first parent the default. A possible edge case is where no
133
+ # parent is defined for one or more leading values, e.g. idx > 0 for
134
+ # the first parent.
135
+ parent = parent_level[0]
136
+ for category in parent_level:
137
+ if category.idx > leaf_node.idx:
138
+ break
139
+ parent = category
140
+
141
+ extended_categories = tuple(categories) + (parent,)
142
+ return self._parentage(extended_categories, remaining_levels)
143
+
144
+
145
+ class Category(str):
146
+ """
147
+ An extension of `str` that provides the category label as its string
148
+ value, and additional attributes representing other aspects of the
149
+ category.
150
+ """
151
+
152
+ def __new__(cls, pt, *args):
153
+ category_label = "" if pt is None else pt.v.text
154
+ return str.__new__(cls, category_label)
155
+
156
+ def __init__(self, pt, idx=None):
157
+ """
158
+ *idx* is a required attribute of a c:pt element, but must be
159
+ specified when pt is None, as when a "placeholder" category is
160
+ created to represent a missing c:pt element.
161
+ """
162
+ self._element = self._pt = pt
163
+ self._idx = idx
164
+
165
+ @property
166
+ def idx(self):
167
+ """
168
+ Return an integer representing the index reference of this category.
169
+ For a leaf node, the index identifies the category. For a parent (or
170
+ other ancestor) category, the index specifies the first leaf category
171
+ that ancestor encloses.
172
+ """
173
+ if self._pt is None:
174
+ return self._idx
175
+ return self._pt.idx
176
+
177
+ @property
178
+ def label(self):
179
+ """
180
+ Return the label of this category as a string.
181
+ """
182
+ return str(self)
183
+
184
+
185
+ class CategoryLevel(Sequence):
186
+ """
187
+ A sequence of |category.Category| objects representing a single level in
188
+ a hierarchical category collection. This object is only used when the
189
+ categories are hierarchical, meaning they have more than one level and
190
+ higher level categories group those at lower levels.
191
+ """
192
+
193
+ def __init__(self, lvl):
194
+ self._element = self._lvl = lvl
195
+
196
+ def __getitem__(self, offset):
197
+ return Category(self._lvl.pt_lst[offset])
198
+
199
+ def __len__(self):
200
+ return len(self._lvl.pt_lst)
pptx/chart/chart.py ADDED
@@ -0,0 +1,280 @@
1
+ """Chart-related objects such as Chart and ChartTitle."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Sequence
6
+
7
+ from pptx.chart.axis import CategoryAxis, DateAxis, ValueAxis
8
+ from pptx.chart.legend import Legend
9
+ from pptx.chart.plot import PlotFactory, PlotTypeInspector
10
+ from pptx.chart.series import SeriesCollection
11
+ from pptx.chart.xmlwriter import SeriesXmlRewriterFactory
12
+ from pptx.dml.chtfmt import ChartFormat
13
+ from pptx.shared import ElementProxy, PartElementProxy
14
+ from pptx.text.text import Font, TextFrame
15
+ from pptx.util import lazyproperty
16
+
17
+
18
+ class Chart(PartElementProxy):
19
+ """A chart object."""
20
+
21
+ def __init__(self, chartSpace, chart_part):
22
+ super(Chart, self).__init__(chartSpace, chart_part)
23
+ self._chartSpace = chartSpace
24
+
25
+ @property
26
+ def category_axis(self):
27
+ """
28
+ The category axis of this chart. In the case of an XY or Bubble
29
+ chart, this is the X axis. Raises |ValueError| if no category
30
+ axis is defined (as is the case for a pie chart, for example).
31
+ """
32
+ catAx_lst = self._chartSpace.catAx_lst
33
+ if catAx_lst:
34
+ return CategoryAxis(catAx_lst[0])
35
+
36
+ dateAx_lst = self._chartSpace.dateAx_lst
37
+ if dateAx_lst:
38
+ return DateAxis(dateAx_lst[0])
39
+
40
+ valAx_lst = self._chartSpace.valAx_lst
41
+ if valAx_lst:
42
+ return ValueAxis(valAx_lst[0])
43
+
44
+ raise ValueError("chart has no category axis")
45
+
46
+ @property
47
+ def chart_style(self):
48
+ """
49
+ Read/write integer index of chart style used to format this chart.
50
+ Range is from 1 to 48. Value is |None| if no explicit style has been
51
+ assigned, in which case the default chart style is used. Assigning
52
+ |None| causes any explicit setting to be removed. The integer index
53
+ corresponds to the style's position in the chart style gallery in the
54
+ PowerPoint UI.
55
+ """
56
+ style = self._chartSpace.style
57
+ if style is None:
58
+ return None
59
+ return style.val
60
+
61
+ @chart_style.setter
62
+ def chart_style(self, value):
63
+ self._chartSpace._remove_style()
64
+ if value is None:
65
+ return
66
+ self._chartSpace._add_style(val=value)
67
+
68
+ @property
69
+ def chart_title(self):
70
+ """A |ChartTitle| object providing access to title properties.
71
+
72
+ Calling this property is destructive in the sense it adds a chart
73
+ title element (`c:title`) to the chart XML if one is not already
74
+ present. Use :attr:`has_title` to test for presence of a chart title
75
+ non-destructively.
76
+ """
77
+ return ChartTitle(self._element.get_or_add_title())
78
+
79
+ @property
80
+ def chart_type(self):
81
+ """Member of :ref:`XlChartType` enumeration specifying type of this chart.
82
+
83
+ If the chart has two plots, for example, a line plot overlayed on a bar plot,
84
+ the type reported is for the first (back-most) plot. Read-only.
85
+ """
86
+ first_plot = self.plots[0]
87
+ return PlotTypeInspector.chart_type(first_plot)
88
+
89
+ @lazyproperty
90
+ def font(self):
91
+ """Font object controlling text format defaults for this chart."""
92
+ defRPr = self._chartSpace.get_or_add_txPr().p_lst[0].get_or_add_pPr().get_or_add_defRPr()
93
+ return Font(defRPr)
94
+
95
+ @property
96
+ def has_legend(self):
97
+ """
98
+ Read/write boolean, |True| if the chart has a legend. Assigning
99
+ |True| causes a legend to be added to the chart if it doesn't already
100
+ have one. Assigning False removes any existing legend definition
101
+ along with any existing legend settings.
102
+ """
103
+ return self._chartSpace.chart.has_legend
104
+
105
+ @has_legend.setter
106
+ def has_legend(self, value):
107
+ self._chartSpace.chart.has_legend = bool(value)
108
+
109
+ @property
110
+ def has_title(self):
111
+ """Read/write boolean, specifying whether this chart has a title.
112
+
113
+ Assigning |True| causes a title to be added if not already present.
114
+ Assigning |False| removes any existing title along with its text and
115
+ settings.
116
+ """
117
+ title = self._chartSpace.chart.title
118
+ if title is None:
119
+ return False
120
+ return True
121
+
122
+ @has_title.setter
123
+ def has_title(self, value):
124
+ chart = self._chartSpace.chart
125
+ if bool(value) is False:
126
+ chart._remove_title()
127
+ autoTitleDeleted = chart.get_or_add_autoTitleDeleted()
128
+ autoTitleDeleted.val = True
129
+ return
130
+ chart.get_or_add_title()
131
+
132
+ @property
133
+ def legend(self):
134
+ """
135
+ A |Legend| object providing access to the properties of the legend
136
+ for this chart.
137
+ """
138
+ legend_elm = self._chartSpace.chart.legend
139
+ if legend_elm is None:
140
+ return None
141
+ return Legend(legend_elm)
142
+
143
+ @lazyproperty
144
+ def plots(self):
145
+ """
146
+ The sequence of plots in this chart. A plot, called a *chart group*
147
+ in the Microsoft API, is a distinct sequence of one or more series
148
+ depicted in a particular charting type. For example, a chart having
149
+ a series plotted as a line overlaid on three series plotted as
150
+ columns would have two plots; the first corresponding to the three
151
+ column series and the second to the line series. Plots are sequenced
152
+ in the order drawn, i.e. back-most to front-most. Supports *len()*,
153
+ membership (e.g. ``p in plots``), iteration, slicing, and indexed
154
+ access (e.g. ``plot = plots[i]``).
155
+ """
156
+ plotArea = self._chartSpace.chart.plotArea
157
+ return _Plots(plotArea, self)
158
+
159
+ def replace_data(self, chart_data):
160
+ """
161
+ Use the categories and series values in the |ChartData| object
162
+ *chart_data* to replace those in the XML and Excel worksheet for this
163
+ chart.
164
+ """
165
+ rewriter = SeriesXmlRewriterFactory(self.chart_type, chart_data)
166
+ rewriter.replace_series_data(self._chartSpace)
167
+ self._workbook.update_from_xlsx_blob(chart_data.xlsx_blob)
168
+
169
+ @lazyproperty
170
+ def series(self):
171
+ """
172
+ A |SeriesCollection| object containing all the series in this
173
+ chart. When the chart has multiple plots, all the series for the
174
+ first plot appear before all those for the second, and so on. Series
175
+ within a plot have an explicit ordering and appear in that sequence.
176
+ """
177
+ return SeriesCollection(self._chartSpace.plotArea)
178
+
179
+ @property
180
+ def value_axis(self):
181
+ """
182
+ The |ValueAxis| object providing access to properties of the value
183
+ axis of this chart. Raises |ValueError| if the chart has no value
184
+ axis.
185
+ """
186
+ valAx_lst = self._chartSpace.valAx_lst
187
+ if not valAx_lst:
188
+ raise ValueError("chart has no value axis")
189
+
190
+ idx = 1 if len(valAx_lst) > 1 else 0
191
+ return ValueAxis(valAx_lst[idx])
192
+
193
+ @property
194
+ def _workbook(self):
195
+ """
196
+ The |ChartWorkbook| object providing access to the Excel source data
197
+ for this chart.
198
+ """
199
+ return self.part.chart_workbook
200
+
201
+
202
+ class ChartTitle(ElementProxy):
203
+ """Provides properties for manipulating a chart title."""
204
+
205
+ # This shares functionality with AxisTitle, which could be factored out
206
+ # into a base class, perhaps pptx.chart.shared.BaseTitle. I suspect they
207
+ # actually differ in certain fuller behaviors, but at present they're
208
+ # essentially identical.
209
+
210
+ def __init__(self, title):
211
+ super(ChartTitle, self).__init__(title)
212
+ self._title = title
213
+
214
+ @lazyproperty
215
+ def format(self):
216
+ """|ChartFormat| object providing access to line and fill formatting.
217
+
218
+ Return the |ChartFormat| object providing shape formatting properties
219
+ for this chart title, such as its line color and fill.
220
+ """
221
+ return ChartFormat(self._title)
222
+
223
+ @property
224
+ def has_text_frame(self):
225
+ """Read/write Boolean specifying whether this title has a text frame.
226
+
227
+ Return |True| if this chart title has a text frame, and |False|
228
+ otherwise. Assigning |True| causes a text frame to be added if not
229
+ already present. Assigning |False| causes any existing text frame to
230
+ be removed along with its text and formatting.
231
+ """
232
+ if self._title.tx_rich is None:
233
+ return False
234
+ return True
235
+
236
+ @has_text_frame.setter
237
+ def has_text_frame(self, value):
238
+ if bool(value) is False:
239
+ self._title._remove_tx()
240
+ return
241
+ self._title.get_or_add_tx_rich()
242
+
243
+ @property
244
+ def text_frame(self):
245
+ """|TextFrame| instance for this chart title.
246
+
247
+ Return a |TextFrame| instance allowing read/write access to the text
248
+ of this chart title and its text formatting properties. Accessing this
249
+ property is destructive in the sense it adds a text frame if one is
250
+ not present. Use :attr:`has_text_frame` to test for the presence of
251
+ a text frame non-destructively.
252
+ """
253
+ rich = self._title.get_or_add_tx_rich()
254
+ return TextFrame(rich, self)
255
+
256
+
257
+ class _Plots(Sequence):
258
+ """
259
+ The sequence of plots in a chart, such as a bar plot or a line plot. Most
260
+ charts have only a single plot. The concept is necessary when two chart
261
+ types are displayed in a single set of axes, like a bar plot with
262
+ a superimposed line plot.
263
+ """
264
+
265
+ def __init__(self, plotArea, chart):
266
+ super(_Plots, self).__init__()
267
+ self._plotArea = plotArea
268
+ self._chart = chart
269
+
270
+ def __getitem__(self, index):
271
+ xCharts = self._plotArea.xCharts
272
+ if isinstance(index, slice):
273
+ plots = [PlotFactory(xChart, self._chart) for xChart in xCharts]
274
+ return plots[index]
275
+ else:
276
+ xChart = xCharts[index]
277
+ return PlotFactory(xChart, self._chart)
278
+
279
+ def __len__(self):
280
+ return len(self._plotArea.xCharts)