athena-python-pptx 0.16.0__tar.gz → 0.17.0__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 (109) hide show
  1. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/AGENTS.md +29 -2
  2. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/API_PARITY_REPORT.md +1 -1
  3. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/CHANGELOG.md +140 -0
  4. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/PKG-INFO +2 -1
  5. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/docs/API_PARITY_EXCEPTIONS.md +355 -8
  6. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/__init__.py +2 -2
  7. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/_unsupported.py +85 -43
  8. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/batching.py +179 -4
  9. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/client.py +13 -11
  10. athena_python_pptx-0.17.0/pptx/oxml/__init__.py +114 -0
  11. athena_python_pptx-0.17.0/pptx/oxml/_mirror.py +471 -0
  12. athena_python_pptx-0.17.0/pptx/oxml/_tbl.py +1152 -0
  13. athena_python_pptx-0.17.0/pptx/oxml/_txbody.py +1782 -0
  14. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/oxml/ns.py +8 -0
  15. athena_python_pptx-0.17.0/pptx/oxml/presentation.py +378 -0
  16. athena_python_pptx-0.17.0/pptx/oxml/shapes/__init__.py +68 -0
  17. athena_python_pptx-0.17.0/pptx/oxml/shapes/autoshape.py +32 -0
  18. athena_python_pptx-0.17.0/pptx/oxml/shapes/connector.py +31 -0
  19. athena_python_pptx-0.17.0/pptx/oxml/shapes/graphfrm.py +32 -0
  20. athena_python_pptx-0.17.0/pptx/oxml/shapes/groupshape.py +402 -0
  21. athena_python_pptx-0.17.0/pptx/oxml/shapes/picture.py +31 -0
  22. athena_python_pptx-0.17.0/pptx/oxml/shapes/shared.py +871 -0
  23. athena_python_pptx-0.17.0/pptx/oxml/simpletypes.py +727 -0
  24. athena_python_pptx-0.17.0/pptx/oxml/table.py +583 -0
  25. athena_python_pptx-0.17.0/pptx/oxml/text.py +652 -0
  26. athena_python_pptx-0.17.0/pptx/oxml/xmlchemy.py +716 -0
  27. athena_python_pptx-0.17.0/pptx/parts/presentation.py +54 -0
  28. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/presentation.py +65 -15
  29. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/shapes/__init__.py +837 -84
  30. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/slides.py +69 -4
  31. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/text/__init__.py +169 -2
  32. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/units.py +6 -0
  33. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pyproject.toml +5 -1
  34. athena_python_pptx-0.16.0/pptx/oxml/__init__.py +0 -43
  35. athena_python_pptx-0.16.0/pptx/parts/presentation.py +0 -15
  36. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/.gitignore +0 -0
  37. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/CLAUDE.md +0 -0
  38. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/DEV-GUIDE.md +0 -0
  39. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/PARITY_QUESTIONS.md +0 -0
  40. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/README.md +0 -0
  41. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/docs/athena-api.json +0 -0
  42. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/docs/athena-api.md +0 -0
  43. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/_athena_extension.py +0 -0
  44. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/_citations.py +0 -0
  45. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/_ptc.py +0 -0
  46. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/_references.py +0 -0
  47. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/action.py +0 -0
  48. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/chart/__init__.py +0 -0
  49. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/chart/axis.py +0 -0
  50. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/chart/category.py +0 -0
  51. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/chart/chart.py +0 -0
  52. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/chart/data.py +0 -0
  53. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/chart/datalabel.py +0 -0
  54. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/chart/legend.py +0 -0
  55. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/chart/marker.py +0 -0
  56. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/chart/plot.py +0 -0
  57. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/chart/point.py +0 -0
  58. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/chart/series.py +0 -0
  59. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/chart/xlsx.py +0 -0
  60. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/commands.py +0 -0
  61. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/decorators.py +0 -0
  62. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/dml/__init__.py +0 -0
  63. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/dml/chtfmt.py +0 -0
  64. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/dml/color.py +0 -0
  65. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/dml/effect.py +0 -0
  66. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/dml/fill.py +0 -0
  67. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/dml/line.py +0 -0
  68. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/docgen.py +0 -0
  69. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/enum/__init__.py +0 -0
  70. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/enum/action.py +0 -0
  71. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/enum/chart.py +0 -0
  72. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/enum/dml.py +0 -0
  73. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/enum/lang.py +0 -0
  74. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/enum/shapes.py +0 -0
  75. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/enum/text.py +0 -0
  76. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/errors.py +0 -0
  77. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/exc.py +0 -0
  78. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/generated/__init__.py +0 -0
  79. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/generated/autoshape_types.py +0 -0
  80. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/kit.py +0 -0
  81. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/media.py +0 -0
  82. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/package.py +0 -0
  83. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/parts/__init__.py +0 -0
  84. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/parts/_base.py +0 -0
  85. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/parts/chart.py +0 -0
  86. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/parts/coreprops.py +0 -0
  87. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/parts/embeddedpackage.py +0 -0
  88. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/parts/image.py +0 -0
  89. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/parts/media.py +0 -0
  90. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/parts/slide.py +0 -0
  91. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/shapes/autoshape.py +0 -0
  92. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/shapes/base.py +0 -0
  93. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/shapes/connector.py +0 -0
  94. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/shapes/freeform.py +0 -0
  95. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/shapes/graphfrm.py +0 -0
  96. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/shapes/group.py +0 -0
  97. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/shapes/picture.py +0 -0
  98. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/shapes/placeholder.py +0 -0
  99. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/shapes/shapetree.py +0 -0
  100. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/shared.py +0 -0
  101. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/slide.py +0 -0
  102. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/spec.py +0 -0
  103. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/table.py +0 -0
  104. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/text/fonts.py +0 -0
  105. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/text/layout.py +0 -0
  106. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/text/text.py +0 -0
  107. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/types.py +0 -0
  108. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/typing.py +0 -0
  109. {athena_python_pptx-0.16.0 → athena_python_pptx-0.17.0}/pptx/util.py +0 -0
@@ -69,7 +69,8 @@ A small number of REST-SDK-specific departures are documented in
69
69
 
70
70
  These standard python-pptx members are omitted because a REST SDK has no
71
71
  local XML / OPC parts:
72
- - `Shape.element`, `Shape.part` — XML element access.
72
+ - `Shape.part` — package part access. (`Shape.element` is implemented: the
73
+ shape's element, for python-pptx's shape-tree recipes; see Architecture.)
73
74
  - `TextFrame.part`, `Paragraph.part`, `Run.part` — package part access.
74
75
  - `FillFormat.from_fill_parent()`, `ColorFormat.from_colorchoice_parent()` — internal XML constructors.
75
76
  - `Font.fill` — Font fill format (uncommon; use `font.color` for text color).
@@ -119,7 +120,33 @@ install fails the parity tests rather than skipping them.
119
120
 
120
121
  This is a **REST API client** that mimics the python-pptx API. Instead of manipulating XML directly, method calls are translated to commands sent to the PPTX Studio API server. Key differences from python-pptx internals:
121
122
 
122
- - No `_element`, `_sp`, `_spTree` XML attributes — these don't exist
123
+ - No local OOXML package. python-pptx's private XML attributes (`_tbl`,
124
+ `_tc`, `series._element`, ...) raise `UnsupportedAttributeError` naming the
125
+ supported API (`pptx/_unsupported.py`), except where common recipes map onto
126
+ commands. Those edits are held until complete
127
+ (`CommandBuffer.hold_pending_edit`):
128
+ - `prs.slides._sldIdLst` and `prs.part.drop_rel()` for slide delete and move
129
+ (`pptx/oxml/presentation.py`, tests in `tests/test_sldidlst_compat.py`);
130
+ - `shape._element` / `shape.element` (with `_sp`, `_pic`, `_graphicFrame`,
131
+ `_grpSp`) and `slide.shapes._spTree` for shape delete, z-order and
132
+ duplicate, sent as `DeleteShape`, `SetShapeZOrder` and `CloneShape`
133
+ (`pptx/oxml/shapes/`, tests in `tests/test_shape_element_compat.py`);
134
+ - a shape's text: `text_frame._txBody` / `_bodyPr`, `paragraph._p`,
135
+ `run._r` and `font._rPr` are real lxml elements of python-pptx's classes
136
+ (`pptx/oxml/text.py` on the ported `xmlchemy` / `simpletypes`), a mirror of
137
+ the deck that is diffed into the public API's commands when the change
138
+ resolves. `pptx/oxml/_mirror.py` holds the reusable lifecycle (hold,
139
+ resolve, in-place re-sync, late edits, the access hooks that resolve before
140
+ a public call), `pptx/oxml/_txbody.py` the text translation; tests in
141
+ `tests/test_text_xml_compat.py`. A change no command carries raises
142
+ naming the XML path; never drop one silently.
143
+ - a table: `table._tbl`, `cell._tc`, `row._tr` and `column._gridCol`
144
+ (`pptx/oxml/table.py`), the same kind of mirror (`pptx/oxml/_tbl.py`):
145
+ cell borders, margins, anchor and fill, row heights, column widths, the
146
+ look flags, and row / column removal. It captures rows by their
147
+ serialization and re-syncs only the cells an API write touched, so a
148
+ recipe that walks a large table cell by cell stays linear; tests in
149
+ `tests/test_table_xml_compat.py`.
123
150
  - Operations are batched via `with prs.batch():` context manager
124
151
  - State is synchronized via the PPTX Studio collaboration layer (Yjs)
125
152
  - **Programmatic Tool Calling (PTC):** every `CommandBuffer.add` and
@@ -91,7 +91,7 @@ via Tranches R–W:
91
91
  | SlideLayout | PASS (+`index`) |
92
92
  | SlideMaster | PASS |
93
93
  | SlideShapes | PASS (+SDK REST helpers; `add_connector` accepts optional `begin_shape`/`end_shape`) |
94
- | Table | PASS (+SDK REST helpers + inherited `Shape.element` proxy) |
94
+ | Table | PASS (+SDK REST helpers + inherited `Shape.element`, its frame's `p:graphicFrame` element) |
95
95
  | `_Cell` | PASS (+SDK REST helpers) |
96
96
  | PlaceholderFormat | PASS (+convenience type-check booleans + custom-prompt/transform fields) |
97
97
  | Chart | PASS (`category_axis` / `value_axis` / `legend` / `font` / `chart_style` added in v0.1.68; replaces `UnsupportedFeatureError` stubs) |
@@ -2,6 +2,146 @@
2
2
 
3
3
  All notable changes to `athena-python-pptx` are documented in this file.
4
4
 
5
+ ## 0.17.0
6
+
7
+ - python-pptx's slide delete and move recipes work. They edit
8
+ `prs.slides._sldIdLst`, which raised `UnsupportedAttributeError`; it is now
9
+ python-pptx's `p:sldIdLst` (`pptx.oxml.presentation.CT_SlideIdList`):
10
+ - `xml_slides.remove(entry)` (or `del xml_slides[i]`) deletes the slide;
11
+ - re-inserting it (`insert`, `append`, `addnext`, `addprevious`) moves it
12
+ instead, and inserting a slide that is still in the list moves it, as
13
+ lxml does;
14
+ - `prs.part.drop_rel(entry.rId)` then `del` deletes the slide once;
15
+ - an entry's `id` is its slide's `slide_id`, as in python-pptx, so the
16
+ recipe that finds a slide's entry by comparing the two works.
17
+
18
+ Edits are held until the change is complete, then sent as deletes and one
19
+ reorder, so a move never deletes its slide first and "remove every slide,
20
+ then append them in a new order" is a single reorder. Anything that reads
21
+ slide positions sends an open change first (the next command, `prs.slides`,
22
+ a slide's index, a flush, a refresh, a `batch()` or `with prs:` block), so
23
+ later commands address slides by their new positions; a block that raises
24
+ drops the edits made inside it. The bulk-delete guard applies. Other lxml
25
+ members, and other OPC members of `prs.part`, raise naming the supported
26
+ API.
27
+ - A slide proxy held from before its slide was deleted (`prs.slides.delete`
28
+ or the recipes above) raises `ConflictError` on an edit. It wrote to the
29
+ slide that had taken its position.
30
+ - python-pptx's shape delete, z-order and duplicate recipes work.
31
+ `shape._element` and python-pptx's public `shape.element` (both raised or
32
+ answered with a delete-only proxy) are the shape's element, with python-pptx's
33
+ `_sp`, `_pic`, `_graphicFrame` and `_grpSp` aliases, and
34
+ `slide.shapes._spTree` is the slide's shape tree (`pptx.oxml.shapes`:
35
+ `CT_Shape`, `CT_Picture`, `CT_GraphicalObjectFrame`, `CT_Connector`,
36
+ `CT_GroupShape`). As in python-pptx, `group.shapes._spTree` is the group's
37
+ element and the tree holds `p:nvGrpSpPr` and `p:grpSpPr` first.
38
+ - `sp.getparent().remove(sp)` (or `spTree.remove(el)`, `del spTree[i]`)
39
+ deletes the shape or placeholder;
40
+ - putting it back (`insert`, `append`, `addnext`, `addprevious`), or
41
+ inserting a shape that is still in the tree, moves it, as lxml does, sent
42
+ as the fewest `SetShapeZOrder` steps that give exactly the new order:
43
+ `spTree.insert(2, el)` sends it to the back;
44
+ - inserting `copy.deepcopy(shape._element)` into any slide's tree clones the
45
+ shape there in place (`CloneShape` with no offset), and a copy never
46
+ inserted sends nothing.
47
+
48
+ Edits are held until the change is complete, as for `_sldIdLst`, so a move
49
+ never deletes its shape; the next command, a flush or refresh, and reading
50
+ `slide.shapes` send them (clones, then deletes, then z-order). An element's
51
+ tag, parent and siblings, and its `p:cNvPr` id and name, read as in
52
+ python-pptx. Other lxml members, property-level XML (`spPr`, `txBody`),
53
+ moving a shape to another slide or group, and copies changed after
54
+ `deepcopy()` raise naming the supported API.
55
+ - A held XML-recipe change that completes sends its commands without forcing
56
+ the other held change, so a shape move made during a slide move no longer
57
+ turns the slide's removal into a delete, and a clone lands on the slide it
58
+ named.
59
+ - A group member's `bring_to_front()` / `send_to_back()` / `bring_forward()` /
60
+ `send_backward()` and `delete()` update `group.shapes`, which kept the old
61
+ order and the deleted member until a refresh.
62
+ - python-pptx's text XML recipes work: bullets on and off, numbered lists,
63
+ hanging indents, superscript, letter spacing, line spacing and autofit
64
+ through XML. `text_frame._txBody` / `_bodyPr`, `paragraph._p` / `_pPr` /
65
+ `_defRPr`, `run._r` / `_rPr` and `font._rPr` raised
66
+ `UnsupportedAttributeError`; they are now real lxml elements of
67
+ python-pptx's classes (`pptx.oxml.text`), one tree per text frame built from
68
+ the deck, with python-pptx's helpers (`get_or_add_pPr()`,
69
+ `insert_element_before()`, `pPr.lvl`, ...). What a recipe changes is sent
70
+ through the public API's setters:
71
+ - `a:pPr` as `SetParagraphStyle` (indents, level, alignment, spacing, bullet
72
+ color and the `•` / `◦` / `▪`, `a:buNone` and `arabicPeriod` bullets),
73
+ its `a:defRPr` as `paragraph.font`;
74
+ - `a:rPr` as `SetRunStyle` (bold, italic, underline, size, strike,
75
+ baseline, caps, spacing, language, color, highlight, typeface);
76
+ - `a:bodyPr` as `SetTextFrameProperties` (wrap, anchor, insets, autofit);
77
+ - run text, appended runs, breaks and paragraphs, and trailing removals
78
+ through the existing text commands.
79
+
80
+ The change is sent before the next command, explicit flush, refresh or API
81
+ call on that text (never by the idle timer), so a later API write wins and
82
+ reads see the edit; like `_sldIdLst`'s, a `prs.batch()` or `with prs:` block
83
+ that raises drops the changes made inside it. Requested again, the tree shows
84
+ the deck's state in place. Anything no command carries raises
85
+ `UnsupportedAttributeError` naming the XML path and the supported API, and
86
+ is dropped. `pptx.oxml.parse_xml` and `pptx.oxml.xmlchemy.OxmlElement` build
87
+ real elements instead of raising. `lxml` is now a dependency.
88
+ - `str()` of a length (`Emu`, `Pt`, ...) and f-strings give the EMU integer, as
89
+ in python-pptx, so `pPr.set("marL", str(Emu(Pt(18))))` writes `"228600"`
90
+ (it wrote `"Emu(228600)"`); `repr()` is unchanged.
91
+ - A run's color writes merged into one command drop an earlier brightness the
92
+ later write does not set, as the studio does when it applies them one by
93
+ one: `font.color.brightness = 0.4` then `font.color.brightness = 0` (or a
94
+ new `theme_color`) sent the 0.4.
95
+ - python-pptx's table XML recipes work: cell borders, row heights, column
96
+ widths, the look flags, a cell's margins, anchor and fill through XML, and
97
+ the row and column delete recipes. `table._tbl`, `cell._tc`, `row._tr` and
98
+ `column._gridCol` raised `UnsupportedAttributeError`; they are now real lxml
99
+ elements of python-pptx's classes (`pptx.oxml.table`), one tree per table
100
+ built from the deck. What a recipe changes is sent through the public API's
101
+ setters:
102
+ - a cell's `a:lnL` / `a:lnR` / `a:lnT` / `a:lnB` as one `SetCellBorders`
103
+ (`w`, an RGB or no line, the dash), which `cell.border_*` then reads (a
104
+ later `width` or `dash_style` write keeps the no line or theme color);
105
+ - `marL` / `marR` / `marT` / `marB` as `SetCellMargins`, `anchor` as
106
+ `SetCellAnchor`, an RGB `a:solidFill` or `a:noFill` as `SetTableCell`;
107
+ - `a:tr/@h` as `SetRowHeight`, `a:gridCol/@w` as `SetColWidth`, the
108
+ `a:tblPr` flags as one `SetTableLook`;
109
+ - a removed `a:tr` as `DeleteTableRow`, a removed column (its `a:gridCol`
110
+ and its `a:tc` in every row) as `DeleteTableColumn`.
111
+
112
+ The studio cannot change an existing table's style, so an edit to
113
+ `a:tableStyleId` raises `UnsupportedAttributeError` naming what can change;
114
+ so do merges, a cell's text, rows or columns added through XML and the
115
+ other properties no command carries. A border's `cap` is ignored with a
116
+ warning. Walking the table (`table.cell(r, c)`, `row.cells`) does not send a
117
+ pending change, so a recipe that edits every cell sends its edits together.
118
+ - `table.delete_row(i)` / `table.delete_column(i)` drop the row's height (the
119
+ column's width) locally, as the server does: the rows below kept reading
120
+ the height of the row after them.
121
+ - A row or column proxy (`table.rows[i]`, `table.columns[i]`) kept across
122
+ rows or columns inserted or removed before it keeps meaning its own row or
123
+ column, as python-pptx's does: it read and wrote the one that took its
124
+ index. One whose row or column was removed raises `IndexError`.
125
+ - A chart data label's `text_frame` has python-pptx's `paragraphs`: one
126
+ paragraph over the label's text whose runs and font are the label's, so
127
+ `point.data_label.text_frame.paragraphs[0].runs[0].font.bold = True` and
128
+ `paragraphs[0].text = ...` work. `paragraphs` raised `AttributeError`.
129
+ - Table cell text frames have python-pptx's `vertical_anchor` and margins
130
+ (they write the cell's own), and `word_wrap` / `auto_size`; cell paragraphs
131
+ have `line_spacing`, `space_before`, `space_after` and `level`. A
132
+ one-paragraph cell cannot apply those last members, so a write warns once
133
+ per presentation and keeps the value for read-after-write, instead of
134
+ raising `AttributeError`, which production scripts hit. An uploaded cell's
135
+ paragraph reads its own level and spacing (`a:pPr`), as python-pptx does.
136
+
137
+ ## 0.16.1 — `Presentation.upload()` and `create(pptx=...)` report the deck they create
138
+
139
+ - `Presentation.upload()` emits the `CreatePresentation` tool-call event with
140
+ the new deck's id, as `Presentation.create()` and the docx and xlsx uploads
141
+ do. It emitted nothing, so a deck uploaded from sandbox code, including one
142
+ seeded from a brand template with `Presentation.create(pptx=...)`, showed no
143
+ creation card and never joined the Athena session's created assets.
144
+
5
145
  ## 0.16.0 — `Presentation.create()` makes 13.333" × 7.5" decks; `create(name=, title=)` titles the deck
6
146
 
7
147
  - **Behaviour change:** `Presentation.create()` makes a deck at PowerPoint's
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: athena-python-pptx
3
- Version: 0.16.0
3
+ Version: 0.17.0
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
@@ -22,6 +22,7 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
22
  Classifier: Typing :: Typed
23
23
  Requires-Python: >=3.10
24
24
  Requires-Dist: athena-references>=0.1.0
25
+ Requires-Dist: lxml>=4.9.0
25
26
  Requires-Dist: requests>=2.28.0
26
27
  Provides-Extra: dev
27
28
  Requires-Dist: mypy>=1.0; extra == 'dev'