athena-python-pptx 0.1.59__tar.gz → 0.1.63__tar.gz

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 (46) hide show
  1. athena_python_pptx-0.1.63/CHANGELOG.md +194 -0
  2. {athena_python_pptx-0.1.59 → athena_python_pptx-0.1.63}/CLAUDE.md +8 -2
  3. {athena_python_pptx-0.1.59 → athena_python_pptx-0.1.63}/PKG-INFO +1 -1
  4. {athena_python_pptx-0.1.59 → athena_python_pptx-0.1.63}/pptx/__init__.py +3 -2
  5. athena_python_pptx-0.1.63/pptx/action.py +34 -0
  6. {athena_python_pptx-0.1.59 → athena_python_pptx-0.1.63}/pptx/chart/__init__.py +3 -0
  7. athena_python_pptx-0.1.63/pptx/chart/category.py +17 -0
  8. {athena_python_pptx-0.1.59 → athena_python_pptx-0.1.63}/pptx/commands.py +5 -0
  9. {athena_python_pptx-0.1.59 → athena_python_pptx-0.1.63}/pptx/enum/shapes.py +196 -0
  10. {athena_python_pptx-0.1.59 → athena_python_pptx-0.1.63}/pptx/presentation.py +14 -3
  11. {athena_python_pptx-0.1.59 → athena_python_pptx-0.1.63}/pptx/shapes.py +328 -17
  12. athena_python_pptx-0.1.63/pptx/slide.py +28 -0
  13. {athena_python_pptx-0.1.59 → athena_python_pptx-0.1.63}/pptx/slides.py +100 -15
  14. athena_python_pptx-0.1.63/pptx/table.py +15 -0
  15. {athena_python_pptx-0.1.59 → athena_python_pptx-0.1.63}/pyproject.toml +1 -1
  16. athena_python_pptx-0.1.59/CHANGELOG.md +0 -48
  17. {athena_python_pptx-0.1.59 → athena_python_pptx-0.1.63}/.gitignore +0 -0
  18. {athena_python_pptx-0.1.59 → athena_python_pptx-0.1.63}/API_PARITY_REPORT.md +0 -0
  19. {athena_python_pptx-0.1.59 → athena_python_pptx-0.1.63}/DEV-GUIDE.md +0 -0
  20. {athena_python_pptx-0.1.59 → athena_python_pptx-0.1.63}/PUBLISHING.md +0 -0
  21. {athena_python_pptx-0.1.59 → athena_python_pptx-0.1.63}/README.md +0 -0
  22. {athena_python_pptx-0.1.59 → athena_python_pptx-0.1.63}/docs/API_PARITY_EXCEPTIONS.md +0 -0
  23. {athena_python_pptx-0.1.59 → athena_python_pptx-0.1.63}/docs/athena-api.json +0 -0
  24. {athena_python_pptx-0.1.59 → athena_python_pptx-0.1.63}/docs/athena-api.md +0 -0
  25. {athena_python_pptx-0.1.59 → athena_python_pptx-0.1.63}/parity-tests/.gitignore +0 -0
  26. {athena_python_pptx-0.1.59 → athena_python_pptx-0.1.63}/parity-tests/GAP_REPORT.md +0 -0
  27. {athena_python_pptx-0.1.59 → athena_python_pptx-0.1.63}/parity-tests/README.md +0 -0
  28. {athena_python_pptx-0.1.59 → athena_python_pptx-0.1.63}/parity-tests/_harness.py +0 -0
  29. {athena_python_pptx-0.1.59 → athena_python_pptx-0.1.63}/parity-tests/runner.py +0 -0
  30. {athena_python_pptx-0.1.59 → athena_python_pptx-0.1.63}/pptx/batching.py +0 -0
  31. {athena_python_pptx-0.1.59 → athena_python_pptx-0.1.63}/pptx/chart/data.py +0 -0
  32. {athena_python_pptx-0.1.59 → athena_python_pptx-0.1.63}/pptx/client.py +0 -0
  33. {athena_python_pptx-0.1.59 → athena_python_pptx-0.1.63}/pptx/decorators.py +0 -0
  34. {athena_python_pptx-0.1.59 → athena_python_pptx-0.1.63}/pptx/dml/__init__.py +0 -0
  35. {athena_python_pptx-0.1.59 → athena_python_pptx-0.1.63}/pptx/dml/color.py +0 -0
  36. {athena_python_pptx-0.1.59 → athena_python_pptx-0.1.63}/pptx/docgen.py +0 -0
  37. {athena_python_pptx-0.1.59 → athena_python_pptx-0.1.63}/pptx/enum/__init__.py +0 -0
  38. {athena_python_pptx-0.1.59 → athena_python_pptx-0.1.63}/pptx/enum/action.py +0 -0
  39. {athena_python_pptx-0.1.59 → athena_python_pptx-0.1.63}/pptx/enum/chart.py +0 -0
  40. {athena_python_pptx-0.1.59 → athena_python_pptx-0.1.63}/pptx/enum/dml.py +0 -0
  41. {athena_python_pptx-0.1.59 → athena_python_pptx-0.1.63}/pptx/enum/text.py +0 -0
  42. {athena_python_pptx-0.1.59 → athena_python_pptx-0.1.63}/pptx/errors.py +0 -0
  43. {athena_python_pptx-0.1.59 → athena_python_pptx-0.1.63}/pptx/text.py +0 -0
  44. {athena_python_pptx-0.1.59 → athena_python_pptx-0.1.63}/pptx/typing.py +0 -0
  45. {athena_python_pptx-0.1.59 → athena_python_pptx-0.1.63}/pptx/units.py +0 -0
  46. {athena_python_pptx-0.1.59 → athena_python_pptx-0.1.63}/pptx/util.py +0 -0
@@ -0,0 +1,194 @@
1
+ # Changelog
2
+
3
+ All notable changes to `athena-python-pptx` are documented in this file.
4
+
5
+ ## 0.1.63
6
+
7
+ Theme-hierarchy parity round (originally targeted 0.1.62, but PyPI's 0.1.62
8
+ was claimed by an unrelated upload on 2026-05-06 — bumped to 0.1.63 to keep
9
+ the SDK and PyPI sequence in step). — closes the remaining python-pptx surface gaps
10
+ on `Presentation`, `SlideMaster`, `SlideLayout`, `Slides`, and `SlideShapes`
11
+ that the parity test was allow-listing as KNOWN_MISSING.
12
+
13
+ - **`Presentation.slide_master`** — shorthand for `slide_masters[0]`. Matches
14
+ python-pptx where most single-master decks reach for the canonical master
15
+ via this attribute. Raises `IndexError` if the snapshot has no masters.
16
+ - **`SlideMaster.shapes`** / **`SlideMaster.placeholders`** — return empty
17
+ read-only collections instead of raising `AttributeError`. The REST snapshot
18
+ doesn't materialize master-level shapes as first-class elements (they are
19
+ projected onto each slide during ingestion), but code that probes these
20
+ collections for parity now gets a sensible empty result.
21
+ - **`SlideLayout.shapes`** — same treatment as the master-level collection.
22
+ - **`SlideLayout.slide_master`** — backreference to the parent
23
+ `SlideMaster`. `_build_slide_masters` now threads the master onto each
24
+ child layout when constructing the theme hierarchy, and the backreference
25
+ is `None` only on the legacy hardcoded fallback layouts (used when no
26
+ snapshot is available).
27
+ - **`Slides.get(slide_id, default=None)`** — matches python-pptx's
28
+ dict-style lookup. Same backing store as `Slides.get_by_id`, with the
29
+ added optional default-return semantics.
30
+ - **`SlideShapes.add_group_shape(shapes=())`** — alias that materializes any
31
+ iterable to a list and forwards to `group_shapes(...)`. Consistent with
32
+ python-pptx's signature; the SDK still requires at least 2 shapes per
33
+ group (one `GroupShapes` command per call).
34
+ - **Parity test cleanup** — `tests/test_python_pptx_api_parity.py` no longer
35
+ allow-lists the items above under `KNOWN_MISSING`. Type mismatches for the
36
+ new `@property` accessors are documented in `KNOWN_TYPE_MISMATCHES`
37
+ (functionally identical to python-pptx's `lazyproperty`).
38
+
39
+ ## 0.1.61
40
+
41
+ Parity round: structural module shims + python-pptx-aligned signatures.
42
+
43
+ - **Module shims** so user code written against python-pptx imports unchanged:
44
+ `pptx.slide` (Slide / Slides / SlideLayout / SlideMaster / SlideMasters /
45
+ SlideBackground / SlideLayouts), `pptx.table` (Table / `_Cell`), and
46
+ `pptx.action` (Hyperlink, ActionSetting placeholder).
47
+ - **`Presentation.save(file=...)`** — renamed kwarg from `path=` to match
48
+ python-pptx exactly. Positional callers (`prs.save("out.pptx")`) keep
49
+ working; keyword callers using `path=` must update.
50
+ - **`Slides.add_slide(slide_layout=...)`** — renamed kwarg from `layout=` to
51
+ match python-pptx. `add_blank_slide()` updated internally.
52
+ - **`Table.cell(row_idx, col_idx)`** and the `GraphicFrame.cell` shortcut —
53
+ renamed parameters from `(row, col)` to match python-pptx.
54
+ - **`SlideShapes.add_chart(x, y, cx, cy, ...)`** — renamed positional
55
+ parameters from `(left, top, width, height)` to match python-pptx (EMU
56
+ semantics unchanged).
57
+ - **`pptx.SlideMaster`** — added top-level export (was only available via
58
+ `pptx.slides.SlideMaster` previously).
59
+ - **Parity test coverage doubled** — `tests/test_python_pptx_api_parity.py`
60
+ now compares 17 user-facing classes against stock python-pptx, up from 8.
61
+ Newly covered: Presentation, Slide, Slides, SlideLayout, SlideMaster,
62
+ SlideShapes, Table, `_Cell`. All deviations documented as either
63
+ REST-internal omissions (`element` / `part`) or SDK-extension extras.
64
+
65
+ ## 0.1.60
66
+
67
+ Round 5 fidelity push — close diffs the parity harness surfaces against
68
+ `lowes_template_v1.pptx` for `add_shape` / `add_textbox` / `add_picture` /
69
+ `add_connector` / `add_table`. End-to-end: SDK → command → applier → Y.Doc →
70
+ export-worker → OOXML.
71
+
72
+ - **python-pptx-style auto-naming for new shapes:**
73
+ `slide.shapes.add_shape(MSO_SHAPE.OVAL, …)` now writes
74
+ `<p:cNvPr name="Oval 2"/>` instead of `name="Shape qR6BLH"`. Mirrors
75
+ python-pptx's deterministic `"<basename> <count_after_add>"` contract so
76
+ AI agents can find shapes by predictable names. Same scheme for
77
+ `add_textbox` (`"TextBox 2"`), `add_picture` (`"Picture 2"`),
78
+ `add_table` (`"Table 2"`), and `add_connector`
79
+ (`"Straight Connector 5"` / `"Elbow Connector …"` / `"Curved Connector …"`).
80
+ New `MSO_SHAPE → basename` map covers all 156 standard auto-shape
81
+ display names (`"Right Triangle"`, `"Rounded Rectangle"`,
82
+ `"Left-Right Arrow"`, etc.). `name` field added to `AddShape` /
83
+ `AddTextBox` / `AddPicture` / `AddConnector` / `AddTable` commands and
84
+ schemas; the applier stores it on the Y.Doc element and the
85
+ export-worker plumbs it through `CreateElement.shapeName`.
86
+ - **Default `<p:txBody>` on `add_shape`:** SDK auto-shapes without text
87
+ now emit python-pptx's standard placeholder body
88
+ (`<a:bodyPr rtlCol="0" anchor="ctr"/><a:lstStyle/><a:p><a:pPr algn="ctr"/></a:p>`)
89
+ so PowerPoint's "click to type text" affordance survives an export.
90
+ Previously athena dropped `<p:txBody>` entirely when no text was set,
91
+ which made downstream PowerPoint editing harder.
92
+ - **Default `<a:bodyPr>` on `add_textbox`:** new SDK textboxes now write
93
+ `<a:bodyPr wrap="none"><a:spAutoFit/></a:bodyPr>` (python-pptx's
94
+ default — auto-shrink to text). Previously athena wrote `wrap="square"`
95
+ which kept the box at its declared size and wrapped instead. Override
96
+ via `text_frame.word_wrap = True` to restore square-wrap behaviour.
97
+
98
+ ## 0.1.59
99
+
100
+ Multi-round fidelity push (PR #19786). All items below are end-to-end:
101
+ SDK setter → command → applier → Y.Doc → export-worker → OOXML.
102
+
103
+ - **Picture crop end-to-end (`Shape.crop_left/top/right/bottom`):**
104
+ exported `<p:pic>` now emits `<a:srcRect l/t/r/b="..."/>` inside
105
+ `<a:blipFill>` for both `slide.shapes.add_picture(...)` and
106
+ `placeholder.insert_picture(...)`. Crop fractions clamp to [0,1]
107
+ and convert to OOXML's 1000ths-of-percent.
108
+ - **Server-side `<c:title>` for SDK-authored charts (Gap 16
109
+ follow-up):** `chart.has_title = True; chart.chart_title.text_frame.text = '...'`
110
+ on a freshly-added chart now lands in the rendered chart XML. New
111
+ helper folds queued `ChartPatch` ops into the `ChartSpec` before
112
+ authoring (handles `SetChartTitle`, `SetLegendVisible`,
113
+ `UpdateSeriesValue/Name`, `UpdateCategoryLabel`, `SetSeriesColor`).
114
+ - **Scatter / bubble `replace_data` (Gap 18 follow-up):**
115
+ `chart.replace_data(XyChartData)` and `chart.replace_data(BubbleChartData)`
116
+ now mutate the rendered chart's `<c:xVal>` / `<c:yVal>` /
117
+ `<c:bubbleSize>` via two new patch ops (`UpdateSeriesXValue`,
118
+ `UpdateBubbleSize`).
119
+ - **Run strike + sub/superscript export:** `Run.font.strike = True`,
120
+ `Run.font.subscript = True`, `Run.font.superscript = True` now emit
121
+ `<a:rPr strike="sngStrike"/>` and `<a:rPr baseline="-25000|30000"/>`
122
+ on both SDK-authored runs and `SetTextRunStyle` patches. Schema also
123
+ accepts a raw `baseline: int|null` override.
124
+ - **Connector elementType end-to-end:**
125
+ `slide.shapes.add_connector(MSO_CONNECTOR.STRAIGHT, ...)` now
126
+ renders on export as `<p:cxnSp prst="..."/>` with
127
+ `<a:headEnd>/<a:tailEnd>` arrow attributes when set. Previously
128
+ `add_connector` was silently dropped at export time.
129
+ - **`add_slide(layout)` routes via snapshot-resolved `layoutPath`:**
130
+ closes the SDK→server layout-index mismatch that broke
131
+ `placeholder.insert_picture()` on Picture-with-Caption slides. The
132
+ SDK's `slide_layouts` ordering comes from the master's
133
+ `<p:sldLayoutIdLst>`, which generally does NOT match the
134
+ `slideLayout{i+1}.xml` filename numbering the server fell back to.
135
+ `add_slide` now forwards `layout._path` (and `layout.name` as
136
+ fallback); the applier prefers `layoutPath > layoutName > layoutIndex`.
137
+ - **Theme/scheme color support for shape fill + line:**
138
+ `shape.fill.fore_color.theme_color = MSO_THEME_COLOR.ACCENT_1` and
139
+ `shape.line.color.theme_color = MSO_THEME_COLOR.HYPERLINK` round-trip
140
+ end-to-end as `<a:solidFill><a:schemeClr val="accent1"/></a:solidFill>`
141
+ in the exported OOXML. AI-driven brand templates can now keep
142
+ customers' theme colors instead of hard-coding sRGB. New
143
+ `SetShapeStyle` fields `fill_scheme_color` / `line_scheme_color`;
144
+ setting one clears the corresponding sRGB so each `<a:solidFill>`
145
+ slot has a single declaration.
146
+ - **`Picture.crop_*` on `SubstitutePlaceholder(picture)`:** crop
147
+ fields now flow through the substitute-placeholder applier path so
148
+ cropped images filling layout placeholders honour the crop on
149
+ export.
150
+
151
+ ## 0.1.58
152
+
153
+ - **Gap 18 (scatter / bubble chart authoring):** `slide.shapes.add_chart(XL_CHART_TYPE.XY_SCATTER, ..., XyChartData(...))` and `BUBBLE` with `BubbleChartData(...)` now author end-to-end. Server-side: chart-ooxml emits `<c:scatterChart>` / `<c:bubbleChart>` with `<c:xVal>` / `<c:yVal>` (and `<c:bubbleSize>` for bubble), pairs of value axes (no category axis), and an embedded workbook with x/y/(size) columns per series. SDK: `_split_chart_type` accepts all five `XY_SCATTER*` variants plus `BUBBLE`; `add_chart` and `insert_chart` validate the chart_data shape against the chart-type family. `replace_data` for XY/bubble is still gated (needs new patch ops; see GAP_REPORT.md Gap 18).
154
+ - **Gap 9 (notesMaster export):** export-worker now bootstraps a `ppt/notesMasters/notesMaster1.xml` + companion `ppt/theme/themeN.xml` whenever speaker notes are added to a deck without a notesMaster. Generators are extracted into `apps/export-worker/src/notes-master.ts`. Bootstrap path also registers the `notesMaster` relationship in `presentation.xml.rels` and adds content-type overrides for the new parts. Matches python-pptx's behavior for the same flow.
155
+
156
+ ## 0.1.57
157
+
158
+ - **Gap 13 (line.dash_style export):** SDK shapes / textboxes with `line.dash_style = MSO_LINE_DASH_STYLE.DASH` (or any preset) now emit `<a:prstDash val=...>` inside `<a:ln>` on export. Schema, ooxml-patch shape-creator, and export-worker plumbing all updated.
159
+ - **Gap 14 (table column widths / row heights):** `table.columns[i].width` and `table.rows[i].height` on SDK-created tables now emit explicit `<a:gridCol w=...>` and `<a:tr h=...>` instead of dividing evenly.
160
+ - **Gap 15 (cell.merge export):** `cell.merge(other)` on SDK-created tables now emits `gridSpan="..."` / `rowSpan="..."` on the merge origin and `hMerge="1"` / `vMerge="1"` on consumed cells.
161
+ - **Gap 11 (run.hyperlink export):** `run.hyperlink.address = "https://..."` on SDK-created textboxes now writes `<a:hlinkClick r:id="rId..."/>` plus a corresponding External hyperlink relationship in the slide's `.rels`. Hyperlinked runs auto-underline to match python-pptx visual default.
162
+ - **Gap 10 (group_shapes/.ungroup id mapping):** In immediate (non-batched) mode `slide.shapes.group_shapes(...)` now flushes the buffer and stamps the real server-assigned id onto the returned `Shape`, so `group.ungroup()` works in the same statement chain.
163
+ - **Presentation.slide_width / slide_height setters:** `prs.slide_width = Inches(13.333)` and `prs.slide_height = Inches(7.5)` now work for python-pptx parity (route through `set_slide_size`).
164
+ - **Font.strike / Font.subscript / Font.superscript:** new properties on `Run.font` for python-pptx parity. Persist via the existing run-style emission pipeline.
165
+ - **Picture crop (`Shape.crop_top` / `crop_bottom` / `crop_left` / `crop_right`):** image shapes now expose python-pptx-compatible crop fractions (0.0–1.0). Setters emit a new `SetPictureCrop` command that writes to the Y.Doc element via `updateElementCrop`.
166
+ - **Connector geometry (`Shape.begin_x` / `begin_y` / `end_x` / `end_y`):** connector shapes expose the python-pptx endpoint API. Setters update the bounding box + `flipH/flipV` accordingly.
167
+ - **GroupShape.shapes children traversal:** for `is_group` shapes, `shape.shapes` returns the slide-level Shape objects whose ids match the group's `childIds`, mirroring `python-pptx GroupShape.shapes`.
168
+ - New `SetPictureCrop` command on the SDK→server protocol; applier wired through `updateElementCrop`.
169
+
170
+ ## 0.1.56
171
+
172
+ - **Charts: end-to-end author + edit support** for column / bar / line / area / pie / doughnut (including all stacked variants).
173
+ - `slide.shapes.add_chart(chart_type, left, top, width, height, chart_data)` now authors a fresh chart from scratch — previously raised `UnsupportedFeatureError`. Returns a `GraphicFrame` whose `.chart` property exposes the resulting `Chart` object. Supported types: `XL_CHART_TYPE.COLUMN_CLUSTERED`, `COLUMN_STACKED`, `COLUMN_STACKED_100`, `BAR_CLUSTERED`, `BAR_STACKED`, `BAR_STACKED_100`, `LINE`, `LINE_MARKERS`, `LINE_STACKED`, `LINE_STACKED_100`, `AREA`, `AREA_STACKED`, `AREA_STACKED_100`, `PIE`, `DOUGHNUT`. 3-D / scatter / bubble / radar / stock / surface / combo still raise `UnsupportedFeatureError` with a clearer message listing the supported set.
174
+ - `placeholder.insert_chart(chart_type, chart_data)` now wires up the same path — previously raised `NotImplementedError`.
175
+ - `Chart.replace_data(chart_data)` now emits `UpdateChartData` patches against an existing chart (ingested or just-authored) — previously raised `UnsupportedFeatureError`. Rewrites series values, series names, and category labels in place; embedded `.xlsx` workbook stays in sync.
176
+ - New `Chart.chart_title` setter and `Chart.has_legend` setter emit `SetChartTitle` and `SetLegendVisible` patches respectively.
177
+ - `CategoryChartData.add_series()` and `XyChartData` / `BubbleChartData` now capture data client-side instead of raising eagerly. (Authoring scatter / bubble charts still raises at `add_chart()` time.)
178
+ - `GraphicFrame` extended to host a `Chart` (in addition to `Table`), so `gf.chart` and `gf.has_chart` work.
179
+
180
+ ## 0.1.55
181
+
182
+ - Internal: bumped version coordinated with the `Presentation.create()` server-side fix (#19270). No SDK API change.
183
+
184
+ ## 0.1.54
185
+
186
+ - `RemoteError.__str__` now includes the HTTP status code (e.g., `[HTTP 400] Invalid request body: ...`) so the status is visible in tracebacks without unpacking `exc.status_code`.
187
+
188
+ ## 0.1.39
189
+
190
+ - Added SDK support for `slide.shapes.add_table(...)` and table creation command wiring.
191
+ - Added `slide.notes_slide.notes_text_frame.text` compatibility adapter for python-pptx style notes access.
192
+ - Added support for auto-shape text frame access (`shape.text_frame`) to match python-pptx behavior.
193
+ - Added smoke/integration tests for table creation/cell updates, notes slide adapter, and shape text-frame regression.
194
+ - Updated README examples for notes slide adapter and auto-shape text support.
@@ -23,13 +23,19 @@ Before adding or modifying any API surface:
23
23
  3. Confirm the method/property/parameter exists with the same name and signature
24
24
  4. If it doesn't exist in python-pptx, **do not add it** without explicit user approval
25
25
 
26
- ### Current status (v0.1.52)
26
+ ### Current status (v0.1.60)
27
27
 
28
28
  **Core classes are at 1:1 parity** with python-pptx: FillFormat, LineFormat, RGBColor, ColorFormat, Font. All legacy convenience methods on these classes have been removed.
29
29
 
30
+ **Module path shims** mirror stock python-pptx layout: `pptx.slide`, `pptx.table`, `pptx.action`. User code written for python-pptx (`from pptx.table import _Cell`, `from pptx.slide import Slide`) imports unchanged.
31
+
32
+ **Structural classes** (Presentation, Slide, Slides, SlideLayout, SlideMaster, SlideShapes, Table, `_Cell`) are parity-tested with deviations documented:
33
+ - Stock-only members like `element` / `part` are intentionally absent (REST SDK has no XML/OPC parts).
34
+ - SDK-specific extras (e.g., `Table.add_row()`, `Slide.title_text`, `Presentation.from_url()`) are listed in the test allowlist.
35
+
30
36
  **TextFrame, Paragraph, and Run** still have non-standard convenience extras (e.g., `to_dict()`, `word_count`, `capitalize()`, string helpers). These are candidates for removal in a future cleanup pass.
31
37
 
32
- Run `python -m pytest tests/test_python_pptx_api_parity.py -v -s` to verify parity across 8 classes.
38
+ Run `python -m pytest tests/test_python_pptx_api_parity.py -v -s` to verify parity across 17 classes.
33
39
 
34
40
  ### Intentionally omitted (REST SDK limitations)
35
41
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: athena-python-pptx
3
- Version: 0.1.59
3
+ Version: 0.1.63
4
4
  Summary: Drop-in replacement for python-pptx that connects to PPTX Studio for real-time collaboration
5
5
  Project-URL: Homepage, https://github.com/pptx-studio/python-sdk
6
6
  Project-URL: Documentation, https://docs.pptx-studio.com/sdk/python
@@ -37,7 +37,7 @@ a clear message explaining what's not supported.
37
37
  from .presentation import Presentation
38
38
 
39
39
  # Slide classes
40
- from .slides import Slide, Slides, SlideLayout, SlideLayouts, SlideMasters, SlideBackground
40
+ from .slides import Slide, Slides, SlideLayout, SlideLayouts, SlideMaster, SlideMasters, SlideBackground
41
41
 
42
42
  # Shape classes
43
43
  from .shapes import (
@@ -127,7 +127,7 @@ def flush_all() -> None:
127
127
  _active_buffers[:] = alive
128
128
 
129
129
 
130
- __version__ = "0.1.59"
130
+ __version__ = "0.1.63"
131
131
 
132
132
  __all__ = [
133
133
  # Main entry point
@@ -137,6 +137,7 @@ __all__ = [
137
137
  "Slides",
138
138
  "SlideLayout",
139
139
  "SlideLayouts",
140
+ "SlideMaster",
140
141
  "SlideMasters",
141
142
  "SlideBackground",
142
143
  # Shape classes
@@ -0,0 +1,34 @@
1
+ """Stock python-pptx exposes hyperlink/action classes via ``pptx.action``.
2
+
3
+ Mirror that module path so user code written for python-pptx
4
+ (``from pptx.action import Hyperlink, ActionSetting``) keeps working.
5
+
6
+ ``ActionSetting`` and the ``PP_ACTION`` enum are not yet implemented in this
7
+ REST SDK — only ``Hyperlink`` is functional. The placeholders are provided so
8
+ that imports succeed and ``isinstance``-style checks behave predictably; they
9
+ will raise ``UnsupportedFeatureError`` if instantiated.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ from .errors import UnsupportedFeatureError
15
+ from .text import Hyperlink
16
+
17
+
18
+ class ActionSetting:
19
+ """Placeholder for python-pptx's ``ActionSetting``.
20
+
21
+ Click-action support is not yet implemented in athena-python-pptx. The
22
+ class exists so that ``from pptx.action import ActionSetting`` succeeds;
23
+ instantiation raises :class:`pptx.errors.UnsupportedFeatureError`.
24
+ """
25
+
26
+ def __init__(self, *_args: object, **_kwargs: object) -> None:
27
+ raise UnsupportedFeatureError(
28
+ "ActionSetting is not implemented in athena-python-pptx. "
29
+ "Use Run.hyperlink for URL hyperlinks; click-actions to slides "
30
+ "are not yet supported.",
31
+ )
32
+
33
+
34
+ __all__ = ["ActionSetting", "Hyperlink"]
@@ -4,9 +4,12 @@ Chart module for python-pptx compatibility.
4
4
  Provides chart-related classes (currently stubs for unimplemented features).
5
5
  """
6
6
 
7
+ from .category import Categories, Category
7
8
  from .data import CategoryChartData, ChartData, XyChartData, BubbleChartData
8
9
 
9
10
  __all__ = [
11
+ "Categories",
12
+ "Category",
10
13
  "CategoryChartData",
11
14
  "ChartData",
12
15
  "XyChartData",
@@ -0,0 +1,17 @@
1
+ """Category sequence classes for python-pptx compatibility."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Iterable
6
+ from typing import Any
7
+
8
+
9
+ class Category(str):
10
+ """Single chart category label."""
11
+
12
+
13
+ class Categories(tuple[Category, ...]):
14
+ """Read-only chart category label sequence."""
15
+
16
+ def __new__(cls, values: Iterable[Any] = ()) -> "Categories":
17
+ return super().__new__(cls, (Category(str(value)) for value in values))
@@ -71,6 +71,7 @@ class AddTextBox(Command):
71
71
  font_size_pt: Optional[float] = None
72
72
  bold: Optional[bool] = None
73
73
  italic: Optional[bool] = None
74
+ name: Optional[str] = None
74
75
 
75
76
  @property
76
77
  def command_type(self) -> str:
@@ -325,6 +326,7 @@ class AddShape(Command):
325
326
  line_color_hex: Optional[str] = None
326
327
  line_width_emu: Optional[int] = None
327
328
  text: Optional[str] = None
329
+ name: Optional[str] = None
328
330
 
329
331
  @property
330
332
  def command_type(self) -> str:
@@ -403,6 +405,7 @@ class AddPicture(Command):
403
405
  w_emu: Optional[int] = None
404
406
  h_emu: Optional[int] = None
405
407
  client_id: Optional[str] = None
408
+ name: Optional[str] = None
406
409
 
407
410
  @property
408
411
  def command_type(self) -> str:
@@ -443,6 +446,7 @@ class AddTable(Command):
443
446
  w_emu: int
444
447
  h_emu: int
445
448
  client_id: Optional[str] = None
449
+ name: Optional[str] = None
446
450
 
447
451
  @property
448
452
  def command_type(self) -> str:
@@ -1024,6 +1028,7 @@ class AddConnector(Command):
1024
1028
  begin_arrow: Optional[str] = None
1025
1029
  end_arrow: Optional[str] = None
1026
1030
  client_id: Optional[str] = None
1031
+ name: Optional[str] = None
1027
1032
 
1028
1033
  @property
1029
1034
  def command_type(self) -> str:
@@ -576,3 +576,199 @@ class PP_PLACEHOLDER(IntEnum):
576
576
 
577
577
  # Alias for compatibility
578
578
  PP_PLACEHOLDER_TYPE = PP_PLACEHOLDER
579
+
580
+
581
+ # ---------------------------------------------------------------------------
582
+ # MSO_SHAPE → display "basename" used by python-pptx for default shape names.
583
+ # python-pptx names new auto-shapes as "<basename> <slide_shape_count_after>".
584
+ # We mirror that contract so AI agents can find shapes by predictable names.
585
+ # ---------------------------------------------------------------------------
586
+ _MSO_SHAPE_BASENAME = {
587
+ 1: 'Rectangle',
588
+ 2: 'Parallelogram',
589
+ 3: 'Trapezoid',
590
+ 4: 'Diamond',
591
+ 5: 'Rounded Rectangle',
592
+ 6: 'Octagon',
593
+ 7: 'Isosceles Triangle',
594
+ 8: 'Right Triangle',
595
+ 9: 'Oval',
596
+ 10: 'Hexagon',
597
+ 11: 'Cross',
598
+ 12: 'Regular Pentagon',
599
+ 13: 'Can',
600
+ 14: 'Cube',
601
+ 15: 'Bevel',
602
+ 16: 'Folded Corner',
603
+ 17: 'Smiley Face',
604
+ 18: 'Donut',
605
+ 19: '"No" Symbol',
606
+ 20: 'Block Arc',
607
+ 21: 'Heart',
608
+ 22: 'Lightning Bolt',
609
+ 23: 'Sun',
610
+ 24: 'Moon',
611
+ 25: 'Arc',
612
+ 26: 'Double Bracket',
613
+ 27: 'Double Brace',
614
+ 28: 'Plaque',
615
+ 29: 'Left Bracket',
616
+ 30: 'Right Bracket',
617
+ 31: 'Left Brace',
618
+ 32: 'Right Brace',
619
+ 33: 'Right Arrow',
620
+ 34: 'Left Arrow',
621
+ 35: 'Up Arrow',
622
+ 36: 'Down Arrow',
623
+ 37: 'Left-Right Arrow',
624
+ 38: 'Up-Down Arrow',
625
+ 39: 'Quad Arrow',
626
+ 40: 'Left-Right-Up Arrow',
627
+ 41: 'Bent Arrow',
628
+ 42: 'U-Turn Arrow',
629
+ 43: 'Left-Up Arrow',
630
+ 44: 'Bent-Up Arrow',
631
+ 45: 'Curved Right Arrow',
632
+ 46: 'Curved Left Arrow',
633
+ 47: 'Curved Up Arrow',
634
+ 48: 'Curved Down Arrow',
635
+ 49: 'Striped Right Arrow',
636
+ 50: 'Notched Right Arrow',
637
+ 51: 'Pentagon',
638
+ 52: 'Chevron',
639
+ 53: 'Right Arrow Callout',
640
+ 54: 'Left Arrow Callout',
641
+ 55: 'Up Arrow Callout',
642
+ 56: 'Down Arrow Callout',
643
+ 57: 'Left-Right Arrow Callout',
644
+ 58: 'Up-Down Arrow Callout',
645
+ 59: 'Quad Arrow Callout',
646
+ 60: 'Circular Arrow',
647
+ 61: 'Process',
648
+ 62: 'Alternate Process',
649
+ 63: 'Decision',
650
+ 64: 'Data',
651
+ 65: 'Predefined Process',
652
+ 66: 'Internal Storage',
653
+ 67: 'Document',
654
+ 68: 'Multidocument',
655
+ 69: 'Terminator',
656
+ 70: 'Preparation',
657
+ 71: 'Manual Input',
658
+ 72: 'Manual Operation',
659
+ 73: 'Connector',
660
+ 74: 'Off-page Connector',
661
+ 75: 'Card',
662
+ 76: 'Punched Tape',
663
+ 77: 'Summing Junction',
664
+ 78: 'Or',
665
+ 79: 'Collate',
666
+ 80: 'Sort',
667
+ 81: 'Extract',
668
+ 82: 'Merge',
669
+ 83: 'Stored Data',
670
+ 84: 'Delay',
671
+ 85: 'Sequential Access Storage',
672
+ 86: 'Magnetic Disk',
673
+ 87: 'Direct Access Storage',
674
+ 88: 'Display',
675
+ 92: 'Explosion 1',
676
+ 93: 'Explosion 2',
677
+ 94: '4-Point Star',
678
+ 95: '5-Point Star',
679
+ 96: '8-Point Star',
680
+ 97: '16-Point Star',
681
+ 98: '24-Point Star',
682
+ 99: '32-Point Star',
683
+ 100: 'Up Ribbon',
684
+ 101: 'Down Ribbon',
685
+ 102: 'Curved Up Ribbon',
686
+ 103: 'Curved Down Ribbon',
687
+ 104: 'Vertical Scroll',
688
+ 105: 'Horizontal Scroll',
689
+ 106: 'Wave',
690
+ 107: 'Double Wave',
691
+ 108: 'Rectangular Callout',
692
+ 109: 'Rounded Rectangular Callout',
693
+ 110: 'Oval Callout',
694
+ 111: 'Cloud Callout',
695
+ 112: 'Line Callout 1',
696
+ 113: 'Line Callout 2',
697
+ 114: 'Line Callout 3',
698
+ 115: 'Line Callout 4',
699
+ 116: 'Line Callout 1 (Accent Bar)',
700
+ 117: 'Line Callout 2 (Accent Bar)',
701
+ 118: 'Line Callout 3 (Accent Bar)',
702
+ 119: 'Line Callout 4 (Accent Bar)',
703
+ 120: 'Line Callout 1 (No Border)',
704
+ 121: 'Line Callout 2 (No Border)',
705
+ 122: 'Line Callout 3 (No Border)',
706
+ 123: 'Line Callout 4 (No Border)',
707
+ 124: 'Line Callout 1 (Border and Accent Bar)',
708
+ 125: 'Line Callout 2 (Border and Accent Bar)',
709
+ 126: 'Line Callout 3 (Border and Accent Bar)',
710
+ 127: 'Line Callout 4 (Border and Accent Bar)',
711
+ 128: 'Action Button: Custom',
712
+ 129: 'Action Button: Back or Previous',
713
+ 130: 'Action Button: Forward or Next',
714
+ 131: 'Action Button: Beginning',
715
+ 132: 'Action Button: End',
716
+ 133: 'Action Button: Home',
717
+ 134: 'Action Button: Information',
718
+ 135: 'Action Button: Return',
719
+ 136: 'Action Button: Movie',
720
+ 137: 'Action Button: Document',
721
+ 138: 'Action Button: Sound',
722
+ 139: 'Action Button: Help',
723
+ 140: 'Bevel',
724
+ 156: 'Frame',
725
+ }
726
+
727
+
728
+ def mso_shape_basename(shape) -> str:
729
+ """Return python-pptx-compatible display basename for an MSO_SHAPE.
730
+
731
+ Used by ``Shapes.add_shape()`` to mirror python-pptx's default naming
732
+ scheme: ``f"{basename} {slide_shape_count_after_add}"``.
733
+ """
734
+ if isinstance(shape, str):
735
+ # Backend string ('rectangle', 'oval', etc.) — title-case fallback.
736
+ return shape.replace('_', ' ').title()
737
+ try:
738
+ value = int(shape)
739
+ except (TypeError, ValueError):
740
+ return 'Shape'
741
+ if value in _MSO_SHAPE_BASENAME:
742
+ return _MSO_SHAPE_BASENAME[value]
743
+ name = getattr(shape, 'name', None)
744
+ if name:
745
+ return name.replace('_', ' ').title()
746
+ return 'Shape'
747
+
748
+
749
+ _MSO_CONNECTOR_BASENAME = {
750
+ 1: 'Straight Connector',
751
+ 2: 'Elbow Connector',
752
+ 3: 'Curved Connector',
753
+ }
754
+
755
+
756
+ def mso_connector_basename(connector) -> str:
757
+ """python-pptx names new connectors as ``f"{basename} {slide_count_after}"``.
758
+
759
+ Mirrors python-pptx — ``MSO_CONNECTOR.STRAIGHT`` → ``"Straight Connector"``.
760
+ """
761
+ if isinstance(connector, str):
762
+ normalized = connector.lower()
763
+ if normalized in {'straight', 'line'}:
764
+ return 'Straight Connector'
765
+ if normalized == 'elbow':
766
+ return 'Elbow Connector'
767
+ if normalized == 'curve':
768
+ return 'Curved Connector'
769
+ return connector.replace('_', ' ').title()
770
+ try:
771
+ value = int(connector)
772
+ except (TypeError, ValueError):
773
+ return 'Connector'
774
+ return _MSO_CONNECTOR_BASENAME.get(value, 'Connector')
@@ -513,6 +513,16 @@ class Presentation:
513
513
  from .slides import _build_slide_masters
514
514
  return _build_slide_masters(self)
515
515
 
516
+ @property
517
+ def slide_master(self):
518
+ """The first :class:`SlideMaster` (python-pptx parity).
519
+
520
+ Stock python-pptx exposes ``Presentation.slide_master`` as a shortcut
521
+ for ``slide_masters[0]``. Raises ``IndexError`` if the deck has no
522
+ masters in its snapshot.
523
+ """
524
+ return self.slide_masters[0]
525
+
516
526
  def reorder_slides(self, new_order: list[int]) -> None:
517
527
  """
518
528
  Reorder slides in the presentation.
@@ -1230,12 +1240,13 @@ class Presentation:
1230
1240
  snapshot=self._snapshot,
1231
1241
  )
1232
1242
 
1233
- def save(self, path: Union[str, Path]) -> None:
1243
+ def save(self, file: Union[str, Path]) -> None:
1234
1244
  """
1235
1245
  Export the presentation and download to a local file.
1236
1246
 
1237
1247
  Args:
1238
- path: Path where the PPTX file should be saved
1248
+ file: Path where the PPTX file should be saved.
1249
+ Matches python-pptx's ``Presentation.save(file)`` signature.
1239
1250
  """
1240
1251
  # Flush any pending commands first
1241
1252
  self._buffer.flush()
@@ -1244,7 +1255,7 @@ class Presentation:
1244
1255
  pptx_bytes = self._client.export_and_download(self._deck_id)
1245
1256
 
1246
1257
  # Write to file
1247
- path = Path(path)
1258
+ path = Path(file)
1248
1259
  path.write_bytes(pptx_bytes)
1249
1260
 
1250
1261
  def save_to_bytes(self) -> bytes: