athena-python-pptx 0.1.56__tar.gz → 0.1.62__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.
- athena_python_pptx-0.1.62/CHANGELOG.md +160 -0
- {athena_python_pptx-0.1.56 → athena_python_pptx-0.1.62}/CLAUDE.md +8 -2
- {athena_python_pptx-0.1.56 → athena_python_pptx-0.1.62}/PKG-INFO +1 -1
- athena_python_pptx-0.1.62/parity-tests/.gitignore +4 -0
- athena_python_pptx-0.1.62/parity-tests/GAP_REPORT.md +618 -0
- athena_python_pptx-0.1.62/parity-tests/README.md +56 -0
- athena_python_pptx-0.1.62/parity-tests/_harness.py +252 -0
- athena_python_pptx-0.1.62/parity-tests/runner.py +131 -0
- {athena_python_pptx-0.1.56 → athena_python_pptx-0.1.62}/pptx/__init__.py +4 -2
- athena_python_pptx-0.1.62/pptx/action.py +34 -0
- {athena_python_pptx-0.1.56 → athena_python_pptx-0.1.62}/pptx/chart/__init__.py +3 -0
- athena_python_pptx-0.1.62/pptx/chart/category.py +17 -0
- {athena_python_pptx-0.1.56 → athena_python_pptx-0.1.62}/pptx/chart/data.py +47 -8
- {athena_python_pptx-0.1.56 → athena_python_pptx-0.1.62}/pptx/client.py +99 -5
- {athena_python_pptx-0.1.56 → athena_python_pptx-0.1.62}/pptx/commands.py +104 -3
- {athena_python_pptx-0.1.56 → athena_python_pptx-0.1.62}/pptx/dml/color.py +39 -0
- {athena_python_pptx-0.1.56 → athena_python_pptx-0.1.62}/pptx/enum/shapes.py +200 -0
- {athena_python_pptx-0.1.56 → athena_python_pptx-0.1.62}/pptx/presentation.py +51 -7
- {athena_python_pptx-0.1.56 → athena_python_pptx-0.1.62}/pptx/shapes.py +1149 -114
- athena_python_pptx-0.1.62/pptx/slide.py +28 -0
- {athena_python_pptx-0.1.56 → athena_python_pptx-0.1.62}/pptx/slides.py +313 -33
- athena_python_pptx-0.1.62/pptx/table.py +15 -0
- {athena_python_pptx-0.1.56 → athena_python_pptx-0.1.62}/pptx/text.py +73 -0
- {athena_python_pptx-0.1.56 → athena_python_pptx-0.1.62}/pptx/typing.py +29 -0
- {athena_python_pptx-0.1.56 → athena_python_pptx-0.1.62}/pyproject.toml +1 -1
- athena_python_pptx-0.1.56/CHANGELOG.md +0 -29
- {athena_python_pptx-0.1.56 → athena_python_pptx-0.1.62}/.gitignore +0 -0
- {athena_python_pptx-0.1.56 → athena_python_pptx-0.1.62}/API_PARITY_REPORT.md +0 -0
- {athena_python_pptx-0.1.56 → athena_python_pptx-0.1.62}/DEV-GUIDE.md +0 -0
- {athena_python_pptx-0.1.56 → athena_python_pptx-0.1.62}/PUBLISHING.md +0 -0
- {athena_python_pptx-0.1.56 → athena_python_pptx-0.1.62}/README.md +0 -0
- {athena_python_pptx-0.1.56 → athena_python_pptx-0.1.62}/docs/API_PARITY_EXCEPTIONS.md +0 -0
- {athena_python_pptx-0.1.56 → athena_python_pptx-0.1.62}/docs/athena-api.json +0 -0
- {athena_python_pptx-0.1.56 → athena_python_pptx-0.1.62}/docs/athena-api.md +0 -0
- {athena_python_pptx-0.1.56 → athena_python_pptx-0.1.62}/pptx/batching.py +0 -0
- {athena_python_pptx-0.1.56 → athena_python_pptx-0.1.62}/pptx/decorators.py +0 -0
- {athena_python_pptx-0.1.56 → athena_python_pptx-0.1.62}/pptx/dml/__init__.py +0 -0
- {athena_python_pptx-0.1.56 → athena_python_pptx-0.1.62}/pptx/docgen.py +0 -0
- {athena_python_pptx-0.1.56 → athena_python_pptx-0.1.62}/pptx/enum/__init__.py +0 -0
- {athena_python_pptx-0.1.56 → athena_python_pptx-0.1.62}/pptx/enum/action.py +0 -0
- {athena_python_pptx-0.1.56 → athena_python_pptx-0.1.62}/pptx/enum/chart.py +0 -0
- {athena_python_pptx-0.1.56 → athena_python_pptx-0.1.62}/pptx/enum/dml.py +0 -0
- {athena_python_pptx-0.1.56 → athena_python_pptx-0.1.62}/pptx/enum/text.py +0 -0
- {athena_python_pptx-0.1.56 → athena_python_pptx-0.1.62}/pptx/errors.py +0 -0
- {athena_python_pptx-0.1.56 → athena_python_pptx-0.1.62}/pptx/units.py +0 -0
- {athena_python_pptx-0.1.56 → athena_python_pptx-0.1.62}/pptx/util.py +0 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `athena-python-pptx` are documented in this file.
|
|
4
|
+
|
|
5
|
+
## 0.1.61
|
|
6
|
+
|
|
7
|
+
Parity round: structural module shims + python-pptx-aligned signatures.
|
|
8
|
+
|
|
9
|
+
- **Module shims** so user code written against python-pptx imports unchanged:
|
|
10
|
+
`pptx.slide` (Slide / Slides / SlideLayout / SlideMaster / SlideMasters /
|
|
11
|
+
SlideBackground / SlideLayouts), `pptx.table` (Table / `_Cell`), and
|
|
12
|
+
`pptx.action` (Hyperlink, ActionSetting placeholder).
|
|
13
|
+
- **`Presentation.save(file=...)`** — renamed kwarg from `path=` to match
|
|
14
|
+
python-pptx exactly. Positional callers (`prs.save("out.pptx")`) keep
|
|
15
|
+
working; keyword callers using `path=` must update.
|
|
16
|
+
- **`Slides.add_slide(slide_layout=...)`** — renamed kwarg from `layout=` to
|
|
17
|
+
match python-pptx. `add_blank_slide()` updated internally.
|
|
18
|
+
- **`Table.cell(row_idx, col_idx)`** and the `GraphicFrame.cell` shortcut —
|
|
19
|
+
renamed parameters from `(row, col)` to match python-pptx.
|
|
20
|
+
- **`SlideShapes.add_chart(x, y, cx, cy, ...)`** — renamed positional
|
|
21
|
+
parameters from `(left, top, width, height)` to match python-pptx (EMU
|
|
22
|
+
semantics unchanged).
|
|
23
|
+
- **`pptx.SlideMaster`** — added top-level export (was only available via
|
|
24
|
+
`pptx.slides.SlideMaster` previously).
|
|
25
|
+
- **Parity test coverage doubled** — `tests/test_python_pptx_api_parity.py`
|
|
26
|
+
now compares 17 user-facing classes against stock python-pptx, up from 8.
|
|
27
|
+
Newly covered: Presentation, Slide, Slides, SlideLayout, SlideMaster,
|
|
28
|
+
SlideShapes, Table, `_Cell`. All deviations documented as either
|
|
29
|
+
REST-internal omissions (`element` / `part`) or SDK-extension extras.
|
|
30
|
+
|
|
31
|
+
## 0.1.60
|
|
32
|
+
|
|
33
|
+
Round 5 fidelity push — close diffs the parity harness surfaces against
|
|
34
|
+
`lowes_template_v1.pptx` for `add_shape` / `add_textbox` / `add_picture` /
|
|
35
|
+
`add_connector` / `add_table`. End-to-end: SDK → command → applier → Y.Doc →
|
|
36
|
+
export-worker → OOXML.
|
|
37
|
+
|
|
38
|
+
- **python-pptx-style auto-naming for new shapes:**
|
|
39
|
+
`slide.shapes.add_shape(MSO_SHAPE.OVAL, …)` now writes
|
|
40
|
+
`<p:cNvPr name="Oval 2"/>` instead of `name="Shape qR6BLH"`. Mirrors
|
|
41
|
+
python-pptx's deterministic `"<basename> <count_after_add>"` contract so
|
|
42
|
+
AI agents can find shapes by predictable names. Same scheme for
|
|
43
|
+
`add_textbox` (`"TextBox 2"`), `add_picture` (`"Picture 2"`),
|
|
44
|
+
`add_table` (`"Table 2"`), and `add_connector`
|
|
45
|
+
(`"Straight Connector 5"` / `"Elbow Connector …"` / `"Curved Connector …"`).
|
|
46
|
+
New `MSO_SHAPE → basename` map covers all 156 standard auto-shape
|
|
47
|
+
display names (`"Right Triangle"`, `"Rounded Rectangle"`,
|
|
48
|
+
`"Left-Right Arrow"`, etc.). `name` field added to `AddShape` /
|
|
49
|
+
`AddTextBox` / `AddPicture` / `AddConnector` / `AddTable` commands and
|
|
50
|
+
schemas; the applier stores it on the Y.Doc element and the
|
|
51
|
+
export-worker plumbs it through `CreateElement.shapeName`.
|
|
52
|
+
- **Default `<p:txBody>` on `add_shape`:** SDK auto-shapes without text
|
|
53
|
+
now emit python-pptx's standard placeholder body
|
|
54
|
+
(`<a:bodyPr rtlCol="0" anchor="ctr"/><a:lstStyle/><a:p><a:pPr algn="ctr"/></a:p>`)
|
|
55
|
+
so PowerPoint's "click to type text" affordance survives an export.
|
|
56
|
+
Previously athena dropped `<p:txBody>` entirely when no text was set,
|
|
57
|
+
which made downstream PowerPoint editing harder.
|
|
58
|
+
- **Default `<a:bodyPr>` on `add_textbox`:** new SDK textboxes now write
|
|
59
|
+
`<a:bodyPr wrap="none"><a:spAutoFit/></a:bodyPr>` (python-pptx's
|
|
60
|
+
default — auto-shrink to text). Previously athena wrote `wrap="square"`
|
|
61
|
+
which kept the box at its declared size and wrapped instead. Override
|
|
62
|
+
via `text_frame.word_wrap = True` to restore square-wrap behaviour.
|
|
63
|
+
|
|
64
|
+
## 0.1.59
|
|
65
|
+
|
|
66
|
+
Multi-round fidelity push (PR #19786). All items below are end-to-end:
|
|
67
|
+
SDK setter → command → applier → Y.Doc → export-worker → OOXML.
|
|
68
|
+
|
|
69
|
+
- **Picture crop end-to-end (`Shape.crop_left/top/right/bottom`):**
|
|
70
|
+
exported `<p:pic>` now emits `<a:srcRect l/t/r/b="..."/>` inside
|
|
71
|
+
`<a:blipFill>` for both `slide.shapes.add_picture(...)` and
|
|
72
|
+
`placeholder.insert_picture(...)`. Crop fractions clamp to [0,1]
|
|
73
|
+
and convert to OOXML's 1000ths-of-percent.
|
|
74
|
+
- **Server-side `<c:title>` for SDK-authored charts (Gap 16
|
|
75
|
+
follow-up):** `chart.has_title = True; chart.chart_title.text_frame.text = '...'`
|
|
76
|
+
on a freshly-added chart now lands in the rendered chart XML. New
|
|
77
|
+
helper folds queued `ChartPatch` ops into the `ChartSpec` before
|
|
78
|
+
authoring (handles `SetChartTitle`, `SetLegendVisible`,
|
|
79
|
+
`UpdateSeriesValue/Name`, `UpdateCategoryLabel`, `SetSeriesColor`).
|
|
80
|
+
- **Scatter / bubble `replace_data` (Gap 18 follow-up):**
|
|
81
|
+
`chart.replace_data(XyChartData)` and `chart.replace_data(BubbleChartData)`
|
|
82
|
+
now mutate the rendered chart's `<c:xVal>` / `<c:yVal>` /
|
|
83
|
+
`<c:bubbleSize>` via two new patch ops (`UpdateSeriesXValue`,
|
|
84
|
+
`UpdateBubbleSize`).
|
|
85
|
+
- **Run strike + sub/superscript export:** `Run.font.strike = True`,
|
|
86
|
+
`Run.font.subscript = True`, `Run.font.superscript = True` now emit
|
|
87
|
+
`<a:rPr strike="sngStrike"/>` and `<a:rPr baseline="-25000|30000"/>`
|
|
88
|
+
on both SDK-authored runs and `SetTextRunStyle` patches. Schema also
|
|
89
|
+
accepts a raw `baseline: int|null` override.
|
|
90
|
+
- **Connector elementType end-to-end:**
|
|
91
|
+
`slide.shapes.add_connector(MSO_CONNECTOR.STRAIGHT, ...)` now
|
|
92
|
+
renders on export as `<p:cxnSp prst="..."/>` with
|
|
93
|
+
`<a:headEnd>/<a:tailEnd>` arrow attributes when set. Previously
|
|
94
|
+
`add_connector` was silently dropped at export time.
|
|
95
|
+
- **`add_slide(layout)` routes via snapshot-resolved `layoutPath`:**
|
|
96
|
+
closes the SDK→server layout-index mismatch that broke
|
|
97
|
+
`placeholder.insert_picture()` on Picture-with-Caption slides. The
|
|
98
|
+
SDK's `slide_layouts` ordering comes from the master's
|
|
99
|
+
`<p:sldLayoutIdLst>`, which generally does NOT match the
|
|
100
|
+
`slideLayout{i+1}.xml` filename numbering the server fell back to.
|
|
101
|
+
`add_slide` now forwards `layout._path` (and `layout.name` as
|
|
102
|
+
fallback); the applier prefers `layoutPath > layoutName > layoutIndex`.
|
|
103
|
+
- **Theme/scheme color support for shape fill + line:**
|
|
104
|
+
`shape.fill.fore_color.theme_color = MSO_THEME_COLOR.ACCENT_1` and
|
|
105
|
+
`shape.line.color.theme_color = MSO_THEME_COLOR.HYPERLINK` round-trip
|
|
106
|
+
end-to-end as `<a:solidFill><a:schemeClr val="accent1"/></a:solidFill>`
|
|
107
|
+
in the exported OOXML. AI-driven brand templates can now keep
|
|
108
|
+
customers' theme colors instead of hard-coding sRGB. New
|
|
109
|
+
`SetShapeStyle` fields `fill_scheme_color` / `line_scheme_color`;
|
|
110
|
+
setting one clears the corresponding sRGB so each `<a:solidFill>`
|
|
111
|
+
slot has a single declaration.
|
|
112
|
+
- **`Picture.crop_*` on `SubstitutePlaceholder(picture)`:** crop
|
|
113
|
+
fields now flow through the substitute-placeholder applier path so
|
|
114
|
+
cropped images filling layout placeholders honour the crop on
|
|
115
|
+
export.
|
|
116
|
+
|
|
117
|
+
## 0.1.58
|
|
118
|
+
|
|
119
|
+
- **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).
|
|
120
|
+
- **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.
|
|
121
|
+
|
|
122
|
+
## 0.1.57
|
|
123
|
+
|
|
124
|
+
- **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.
|
|
125
|
+
- **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.
|
|
126
|
+
- **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.
|
|
127
|
+
- **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.
|
|
128
|
+
- **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.
|
|
129
|
+
- **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`).
|
|
130
|
+
- **Font.strike / Font.subscript / Font.superscript:** new properties on `Run.font` for python-pptx parity. Persist via the existing run-style emission pipeline.
|
|
131
|
+
- **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`.
|
|
132
|
+
- **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.
|
|
133
|
+
- **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`.
|
|
134
|
+
- New `SetPictureCrop` command on the SDK→server protocol; applier wired through `updateElementCrop`.
|
|
135
|
+
|
|
136
|
+
## 0.1.56
|
|
137
|
+
|
|
138
|
+
- **Charts: end-to-end author + edit support** for column / bar / line / area / pie / doughnut (including all stacked variants).
|
|
139
|
+
- `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.
|
|
140
|
+
- `placeholder.insert_chart(chart_type, chart_data)` now wires up the same path — previously raised `NotImplementedError`.
|
|
141
|
+
- `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.
|
|
142
|
+
- New `Chart.chart_title` setter and `Chart.has_legend` setter emit `SetChartTitle` and `SetLegendVisible` patches respectively.
|
|
143
|
+
- `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.)
|
|
144
|
+
- `GraphicFrame` extended to host a `Chart` (in addition to `Table`), so `gf.chart` and `gf.has_chart` work.
|
|
145
|
+
|
|
146
|
+
## 0.1.55
|
|
147
|
+
|
|
148
|
+
- Internal: bumped version coordinated with the `Presentation.create()` server-side fix (#19270). No SDK API change.
|
|
149
|
+
|
|
150
|
+
## 0.1.54
|
|
151
|
+
|
|
152
|
+
- `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`.
|
|
153
|
+
|
|
154
|
+
## 0.1.39
|
|
155
|
+
|
|
156
|
+
- Added SDK support for `slide.shapes.add_table(...)` and table creation command wiring.
|
|
157
|
+
- Added `slide.notes_slide.notes_text_frame.text` compatibility adapter for python-pptx style notes access.
|
|
158
|
+
- Added support for auto-shape text frame access (`shape.text_frame`) to match python-pptx behavior.
|
|
159
|
+
- Added smoke/integration tests for table creation/cell updates, notes slide adapter, and shape text-frame regression.
|
|
160
|
+
- 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.
|
|
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
|
|
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.
|
|
3
|
+
Version: 0.1.62
|
|
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
|