WolfPPT - migration playbook
Move one python-pptx workflow to WolfPPT
WolfPPT keeps the python-pptx names for the calls it implements, so most of a migration is an import change plus a check of each call against the compatibility matrix. Move the narrowest edit path first and keep python-pptx for anything the matrix does not list.
The import change
Replace from pptx import Presentation with from wolfppt import Presentation. Keep the pptx.chart.data, pptx.enum, and pptx.util imports for chart data, enums, and units, and keep python-pptx installed for them, since WolfPPT does not provide those modules in the current release. The facade implements a documented subset of python-pptx. The compatibility matrix in the repository lists supported calls. Check each call against the version you install.
Call mapping
| python-pptx | WolfPPT |
|---|---|
| Presentation("deck.pptx") | from wolfppt import Presentation, then Presentation("deck.pptx") |
| Presentation() | Presentation() starts a new deck from the default template |
| prs.slides, prs.slide_layouts | Presentation.slides (a SlideCollection) and Presentation.slide_layouts |
| slide.shapes, shape.has_text_frame | Slide.shapes (a ShapeCollection) and Shape.has_text_frame |
| text_frame.paragraphs, paragraph.runs | The same names on the text frame and its paragraphs |
| run.text = value | Same assignment. It keeps the run formatting and changes only the slide that holds the run. |
| text_frame.text = value | Same assignment |
| Loop over runs to replace text | The same loop over paragraph.runs with run.text = .... A document-wide Presentation.replace_text is not in the current release. |
| shape.has_table, shape.table | Same names. See update a PowerPoint table. |
| table.cell(r, c).text = value | Table.cell(row, column).text = value. Indexes start at 0, as in python-pptx. |
| Add a table row (no python-pptx method; XML workaround) | table.rows.insert(index) and table.rows.remove(index). Likewise table.columns.insert. |
| shapes.add_table(rows, cols, left, top, width, height) | ShapeCollection.add_table with the same arguments |
| shape.has_chart, chart.replace_data(chart_data) | Same names, with CategoryChartData from pptx.chart.data. See update a PowerPoint chart. |
| shapes.add_chart(XL_CHART_TYPE, x, y, cx, cy, chart_data) | ShapeCollection.add_chart with the same arguments, importing XL_CHART_TYPE from pptx.enum.chart |
| from pptx.util import Inches, Pt | Keep the pptx.util import. wolfppt.util is not in the current release, and neither are wolfppt.enum or wolfppt.chart, so keep pptx.enum and pptx.chart.data too. |
| prs.slides.add_slide(layout) | SlideCollection.add_slide(slide_layout) |
| slide.shapes.title | ShapeCollection.title |
| shapes.add_textbox(...), shapes.add_picture(path, ...) | ShapeCollection.add_textbox and ShapeCollection.add_picture |
| Delete a shape (element.getparent().remove(...)) | slide.shapes.remove(shape) for a shape that exists in the opened file. Deleting a shape added in the same session is not supported yet. |
| Duplicate or reorder slides (XML workarounds) | SlideCollection.duplicate(slide) takes a Slide object, adds the copy at the end, and exposes its shapes after you save and reopen the deck. SlideCollection.move(old_index, new_index) reorders. |
| prs.save(path) | Presentation.save(path) |
| Render to PDF or PNG (LibreOffice) | Not part of the Python facade. Use wolf render deck.pptx --to pdf --outdir out. See convert PPTX to PDF. |
| shape.left, shape.top, shape.width, shape.height = value | Same assignments on text boxes, pictures, tables, charts, and shapes. Not supported on a placeholder that takes its position from the layout, such as a title or body: in 0.1.4 the assignment is not saved and the getters return 0. Keep python-pptx for that call, or add a text box. |
| Delete a slide (prs.slides._sldIdLst workaround) | SlideCollection.remove(slide). Private handles such as _sldIdLst and shape._element.getparent() raise AttributeError, so replace XML workarounds with the mapped calls. |
| Fonts, paragraph spacing and alignment, notes, core properties, hyperlinks, fills, groups, merged cells, column widths | Same names and assignments. Checked in 0.1.4 against python-pptx output for each. |
| Any python-pptx API missing from the compatibility matrix | Not supported. Keep python-pptx for that call. |
Verified sample
The sample assumes a deck whose first slide holds a title with {{month}}, a table, and a chart.
from pptx.chart.data import CategoryChartData
from pptx.enum.chart import XL_CHART_TYPE
from pptx.util import Inches
from wolfppt import Presentation
prs = Presentation("deck.pptx")
slide = prs.slides[0]
# Text: a run-level edit keeps the run formatting.
for shape in slide.shapes:
if shape.has_text_frame:
for paragraph in shape.text_frame.paragraphs:
for run in paragraph.runs:
if "{{month}}" in run.text:
run.text = run.text.replace("{{month}}", "September")
# Table: set one cell, then add a row.
table = next(s for s in slide.shapes if s.has_table).table
table.cell(1, 1).text = "$4.2M"
table.rows.insert(2)
table.cell(2, 0).text = "NRR"
table.cell(2, 1).text = "118%"
# Chart: replace the data behind an existing chart.
chart = next(s for s in slide.shapes if s.has_chart).chart
data = CategoryChartData()
data.categories = ["Q1", "Q2", "Q3"]
data.add_series("Revenue", (3.1, 3.8, 4.2))
chart.replace_data(data)
# New slide with a text box and a chart.
appendix = prs.slides.add_slide(prs.slide_layouts[5])
appendix.shapes.title.text = "Appendix"
appendix.shapes.add_textbox(Inches(1), Inches(2), Inches(5), Inches(1)).text_frame.text = "Source: finance export"
appendix.shapes.add_chart(XL_CHART_TYPE.COLUMN_CLUSTERED, Inches(1), Inches(3), Inches(5), Inches(3), data)
prs.save("deck_updated.pptx")
check = Presentation("deck_updated.pptx")
print(len(check.slides)) # 2Migration checklist
- List the python-pptx calls the workflow makes and check each against the mapping table and the compatibility matrix.
- Swap the import in one script and run it on a copy of a representative deck. Write every test result to a new path.
- Reopen the saved deck and assert the text, table cells, and chart series you changed.
- Compare the ZIP parts before and after. Untouched slides, media, and masters should keep their original bytes.
- Keep python-pptx imports for any call outside the matrix, and note each one in the migrated script.
- Run the migrated script on a small cohort of real decks and keep the old script available for rollback.
Install WolfPPT
The public WolfPPT release is MIT-licensed and free, including commercial use.
pip install wolfpptPyPI wheels cover CPython 3.11 to 3.14 on Linux x86_64 and aarch64 and on macOS arm64. Source, tests, and the full facade reference live at github.com/wolfiesch/wolfppt-oss.