athena-python-pptx 0.1.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.
- athena_python_pptx-0.1.0/.gitignore +46 -0
- athena_python_pptx-0.1.0/PKG-INFO +309 -0
- athena_python_pptx-0.1.0/README.md +274 -0
- athena_python_pptx-0.1.0/pptx/__init__.py +130 -0
- athena_python_pptx-0.1.0/pptx/batching.py +165 -0
- athena_python_pptx-0.1.0/pptx/chart/__init__.py +14 -0
- athena_python_pptx-0.1.0/pptx/chart/data.py +96 -0
- athena_python_pptx-0.1.0/pptx/client.py +611 -0
- athena_python_pptx-0.1.0/pptx/commands.py +563 -0
- athena_python_pptx-0.1.0/pptx/dml/__init__.py +9 -0
- athena_python_pptx-0.1.0/pptx/dml/color.py +204 -0
- athena_python_pptx-0.1.0/pptx/enum/__init__.py +32 -0
- athena_python_pptx-0.1.0/pptx/enum/action.py +30 -0
- athena_python_pptx-0.1.0/pptx/enum/chart.py +151 -0
- athena_python_pptx-0.1.0/pptx/enum/dml.py +149 -0
- athena_python_pptx-0.1.0/pptx/enum/shapes.py +409 -0
- athena_python_pptx-0.1.0/pptx/enum/text.py +74 -0
- athena_python_pptx-0.1.0/pptx/errors.py +150 -0
- athena_python_pptx-0.1.0/pptx/presentation.py +445 -0
- athena_python_pptx-0.1.0/pptx/shapes.py +1356 -0
- athena_python_pptx-0.1.0/pptx/slides.py +459 -0
- athena_python_pptx-0.1.0/pptx/text.py +705 -0
- athena_python_pptx-0.1.0/pptx/typing.py +270 -0
- athena_python_pptx-0.1.0/pptx/units.py +148 -0
- athena_python_pptx-0.1.0/pptx/util.py +20 -0
- athena_python_pptx-0.1.0/pyproject.toml +111 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
.Python
|
|
7
|
+
build/
|
|
8
|
+
develop-eggs/
|
|
9
|
+
dist/
|
|
10
|
+
downloads/
|
|
11
|
+
eggs/
|
|
12
|
+
.eggs/
|
|
13
|
+
lib/
|
|
14
|
+
lib64/
|
|
15
|
+
parts/
|
|
16
|
+
sdist/
|
|
17
|
+
var/
|
|
18
|
+
wheels/
|
|
19
|
+
*.egg-info/
|
|
20
|
+
.installed.cfg
|
|
21
|
+
*.egg
|
|
22
|
+
|
|
23
|
+
# Virtual environments
|
|
24
|
+
.venv/
|
|
25
|
+
venv/
|
|
26
|
+
ENV/
|
|
27
|
+
|
|
28
|
+
# Testing
|
|
29
|
+
.pytest_cache/
|
|
30
|
+
.coverage
|
|
31
|
+
htmlcov/
|
|
32
|
+
.tox/
|
|
33
|
+
.nox/
|
|
34
|
+
|
|
35
|
+
# IDE
|
|
36
|
+
.idea/
|
|
37
|
+
.vscode/
|
|
38
|
+
*.swp
|
|
39
|
+
*.swo
|
|
40
|
+
|
|
41
|
+
# Test artifacts
|
|
42
|
+
tests/fixtures/exported_*.pptx
|
|
43
|
+
tests/fixtures/~$*.pptx
|
|
44
|
+
|
|
45
|
+
# OS
|
|
46
|
+
.DS_Store
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: athena-python-pptx
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Drop-in replacement for python-pptx that connects to PPTX Studio for real-time collaboration
|
|
5
|
+
Project-URL: Homepage, https://github.com/pptx-studio/python-sdk
|
|
6
|
+
Project-URL: Documentation, https://docs.pptx-studio.com/sdk/python
|
|
7
|
+
Project-URL: Repository, https://github.com/pptx-studio/python-sdk
|
|
8
|
+
Project-URL: Issues, https://github.com/pptx-studio/python-sdk/issues
|
|
9
|
+
Author: PPTX Studio Team
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
Keywords: api,powerpoint,pptx,presentation,python-pptx,sdk,slides
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Topic :: Office/Business :: Office Suites
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
|
+
Classifier: Typing :: Typed
|
|
23
|
+
Requires-Python: >=3.10
|
|
24
|
+
Requires-Dist: requests>=2.28.0
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: mypy>=1.0; extra == 'dev'
|
|
27
|
+
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
|
|
28
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
29
|
+
Requires-Dist: responses>=0.23; extra == 'dev'
|
|
30
|
+
Requires-Dist: ruff>=0.1; extra == 'dev'
|
|
31
|
+
Provides-Extra: e2e
|
|
32
|
+
Requires-Dist: pytest>=7.0; extra == 'e2e'
|
|
33
|
+
Requires-Dist: python-pptx>=0.6.21; extra == 'e2e'
|
|
34
|
+
Description-Content-Type: text/markdown
|
|
35
|
+
|
|
36
|
+
# athena-python-pptx
|
|
37
|
+
|
|
38
|
+
A **drop-in replacement for [python-pptx](https://python-pptx.readthedocs.io/)** that connects to PPTX Studio for real-time collaboration.
|
|
39
|
+
|
|
40
|
+
Use the exact same imports and API as python-pptx:
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
from pptx import Presentation
|
|
44
|
+
from pptx.util import Inches, Pt
|
|
45
|
+
from pptx.enum.shapes import MSO_SHAPE
|
|
46
|
+
from pptx.dml.color import RGBColor
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Features
|
|
50
|
+
|
|
51
|
+
- **100% python-pptx compatible imports** - `from pptx import Presentation`
|
|
52
|
+
- **Same API** - Familiar interface for developers and LLMs
|
|
53
|
+
- **Real-time collaboration** - Changes sync instantly with web UI
|
|
54
|
+
- **Remote-first** - Edits apply to live Yjs documents via API
|
|
55
|
+
- **Clear error messages** - Unimplemented features raise helpful errors
|
|
56
|
+
|
|
57
|
+
## Installation
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
pip install athena-python-pptx
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Quick Start
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
from pptx import Presentation
|
|
67
|
+
from pptx.util import Inches
|
|
68
|
+
|
|
69
|
+
# Connect to an existing deck
|
|
70
|
+
prs = Presentation(
|
|
71
|
+
deck_id="deck_123",
|
|
72
|
+
base_url="https://api.pptx-studio.com",
|
|
73
|
+
api_key="sk_live_..."
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
# Access slides
|
|
77
|
+
slide = prs.slides[0]
|
|
78
|
+
|
|
79
|
+
# Add a textbox
|
|
80
|
+
tb = slide.shapes.add_textbox(
|
|
81
|
+
Inches(1), Inches(1), # position
|
|
82
|
+
Inches(8), Inches(1) # size
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
# Set text content
|
|
86
|
+
tb.text_frame.text = "Hello from Python!"
|
|
87
|
+
|
|
88
|
+
# Export to local file
|
|
89
|
+
prs.save("output.pptx")
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Batching Operations
|
|
93
|
+
|
|
94
|
+
For better performance, batch multiple operations into a single request:
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
with prs.batch():
|
|
98
|
+
tb1 = slide.shapes.add_textbox(Inches(1), Inches(1), Inches(4), Inches(1))
|
|
99
|
+
tb1.text_frame.text = "First"
|
|
100
|
+
|
|
101
|
+
tb2 = slide.shapes.add_textbox(Inches(1), Inches(2), Inches(4), Inches(1))
|
|
102
|
+
tb2.text_frame.text = "Second"
|
|
103
|
+
# Both operations sent as one request when context exits
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## API Reference
|
|
107
|
+
|
|
108
|
+
### Presentation
|
|
109
|
+
|
|
110
|
+
The main entry point for working with a deck.
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
# Connect to existing deck
|
|
114
|
+
prs = Presentation(deck_id, base_url, api_key=None)
|
|
115
|
+
|
|
116
|
+
# Create new deck
|
|
117
|
+
prs = Presentation.create(base_url, api_key=None)
|
|
118
|
+
|
|
119
|
+
# Properties
|
|
120
|
+
prs.deck_id # Deck identifier
|
|
121
|
+
prs.slides # Slides collection
|
|
122
|
+
prs.slide_width # Width in EMU
|
|
123
|
+
prs.slide_height # Height in EMU
|
|
124
|
+
|
|
125
|
+
# Methods
|
|
126
|
+
prs.refresh() # Sync with server
|
|
127
|
+
prs.save(path) # Export and download
|
|
128
|
+
prs.save_to_bytes() # Export as bytes
|
|
129
|
+
prs.render_slide(index) # Render slide as PNG
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Slides
|
|
133
|
+
|
|
134
|
+
Collection of slides in the presentation.
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
# Access slides
|
|
138
|
+
slide = prs.slides[0] # By index
|
|
139
|
+
for slide in prs.slides: # Iterate
|
|
140
|
+
print(slide.slide_id)
|
|
141
|
+
len(prs.slides) # Count
|
|
142
|
+
|
|
143
|
+
# Add new slide
|
|
144
|
+
new_slide = prs.slides.add_slide()
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Shapes
|
|
148
|
+
|
|
149
|
+
Collection of shapes on a slide.
|
|
150
|
+
|
|
151
|
+
```python
|
|
152
|
+
# Access shapes
|
|
153
|
+
shape = slide.shapes[0]
|
|
154
|
+
for shape in slide.shapes:
|
|
155
|
+
print(shape.shape_id)
|
|
156
|
+
|
|
157
|
+
# Add textbox
|
|
158
|
+
tb = slide.shapes.add_textbox(left, top, width, height)
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Shape
|
|
162
|
+
|
|
163
|
+
Individual shape on a slide.
|
|
164
|
+
|
|
165
|
+
```python
|
|
166
|
+
# Properties
|
|
167
|
+
shape.shape_id # Shape identifier
|
|
168
|
+
shape.shape_type # "text", "image", etc.
|
|
169
|
+
shape.left # X position (EMU)
|
|
170
|
+
shape.top # Y position (EMU)
|
|
171
|
+
shape.width # Width (EMU)
|
|
172
|
+
shape.height # Height (EMU)
|
|
173
|
+
shape.rotation # Rotation (degrees)
|
|
174
|
+
shape.text_frame # TextFrame (for text shapes)
|
|
175
|
+
|
|
176
|
+
# Shortcuts
|
|
177
|
+
shape.text # Same as shape.text_frame.text
|
|
178
|
+
|
|
179
|
+
# Methods
|
|
180
|
+
shape.delete() # Remove shape
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### TextFrame
|
|
184
|
+
|
|
185
|
+
Text content container.
|
|
186
|
+
|
|
187
|
+
```python
|
|
188
|
+
# Get/set text
|
|
189
|
+
tf = shape.text_frame
|
|
190
|
+
tf.text = "Hello" # Set all text
|
|
191
|
+
text = tf.text # Get all text
|
|
192
|
+
|
|
193
|
+
# Paragraphs
|
|
194
|
+
for para in tf.paragraphs:
|
|
195
|
+
print(para.text)
|
|
196
|
+
|
|
197
|
+
# Clear text
|
|
198
|
+
tf.clear()
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Units
|
|
202
|
+
|
|
203
|
+
Unit conversion helpers (python-pptx compatible).
|
|
204
|
+
|
|
205
|
+
```python
|
|
206
|
+
from pptx.util import Inches, Pt, Cm, Px, Emu
|
|
207
|
+
|
|
208
|
+
# All return EMU values
|
|
209
|
+
Inches(1) # 914400 EMU
|
|
210
|
+
Pt(12) # 152400 EMU (12 points)
|
|
211
|
+
Cm(2.54) # ~914400 EMU (1 inch)
|
|
212
|
+
Px(96) # 914400 EMU (at 96 DPI)
|
|
213
|
+
Emu(914400) # Direct EMU value
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## Error Handling
|
|
217
|
+
|
|
218
|
+
The SDK raises specific exceptions for different error conditions:
|
|
219
|
+
|
|
220
|
+
```python
|
|
221
|
+
from pptx import (
|
|
222
|
+
UnsupportedFeatureError, # Feature not yet implemented
|
|
223
|
+
RemoteError, # Server rejected the request
|
|
224
|
+
ConflictError, # Stale IDs (concurrent modification)
|
|
225
|
+
ValidationError, # Invalid command parameters
|
|
226
|
+
ConnectionError, # Network issues
|
|
227
|
+
AuthenticationError, # Auth failed
|
|
228
|
+
ExportError, # Export job failed
|
|
229
|
+
RenderError, # Render job failed
|
|
230
|
+
)
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### Handling unsupported features
|
|
234
|
+
|
|
235
|
+
```python
|
|
236
|
+
try:
|
|
237
|
+
shape.fill.color = "red"
|
|
238
|
+
except UnsupportedFeatureError as e:
|
|
239
|
+
print(f"Not yet supported: {e.feature}")
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
## Phase 1 Limitations
|
|
243
|
+
|
|
244
|
+
The SDK is in Phase 1 with limited feature support:
|
|
245
|
+
|
|
246
|
+
### Supported
|
|
247
|
+
- Open deck by ID
|
|
248
|
+
- List and iterate slides
|
|
249
|
+
- Add textbox shapes
|
|
250
|
+
- Set text content
|
|
251
|
+
- Get/set shape position and size
|
|
252
|
+
- Export to PPTX
|
|
253
|
+
- Render slides to PNG
|
|
254
|
+
- Batch operations
|
|
255
|
+
|
|
256
|
+
### Not Yet Supported
|
|
257
|
+
- Upload local PPTX files
|
|
258
|
+
- Add images, charts, tables
|
|
259
|
+
- Slide layouts and masters
|
|
260
|
+
- Rich text formatting (bold, italic, etc.)
|
|
261
|
+
- Shape fills and lines
|
|
262
|
+
- Placeholder access
|
|
263
|
+
- Notes slides
|
|
264
|
+
|
|
265
|
+
Unsupported features raise `UnsupportedFeatureError` with a clear message.
|
|
266
|
+
|
|
267
|
+
## Development
|
|
268
|
+
|
|
269
|
+
```bash
|
|
270
|
+
# Clone and install dev dependencies
|
|
271
|
+
git clone https://github.com/pptx-studio/python-sdk
|
|
272
|
+
cd python-sdk
|
|
273
|
+
pip install -e ".[dev]"
|
|
274
|
+
|
|
275
|
+
# Run unit tests
|
|
276
|
+
pytest tests/ -v --ignore=tests/test_e2e_roundtrip.py
|
|
277
|
+
|
|
278
|
+
# Type checking
|
|
279
|
+
mypy pptx
|
|
280
|
+
|
|
281
|
+
# Linting
|
|
282
|
+
ruff check pptx
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### Running E2E Tests
|
|
286
|
+
|
|
287
|
+
End-to-end tests require a running PPTX Studio server and the `python-pptx` library.
|
|
288
|
+
|
|
289
|
+
```bash
|
|
290
|
+
# Install E2E dependencies
|
|
291
|
+
pip install -e ".[e2e]"
|
|
292
|
+
|
|
293
|
+
# Start the PPTX Studio server (from project root)
|
|
294
|
+
pnpm dev:infra
|
|
295
|
+
pnpm dev
|
|
296
|
+
|
|
297
|
+
# Run E2E tests (in another terminal)
|
|
298
|
+
PPTX_TEST_BASE_URL=http://localhost:3001 pytest tests/test_e2e_roundtrip.py -v
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
The E2E tests will:
|
|
302
|
+
1. Create a PPTX file using python-pptx
|
|
303
|
+
2. Upload it to the running server
|
|
304
|
+
3. Modify it using our SDK
|
|
305
|
+
4. Export and verify the changes
|
|
306
|
+
|
|
307
|
+
## License
|
|
308
|
+
|
|
309
|
+
MIT
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
# athena-python-pptx
|
|
2
|
+
|
|
3
|
+
A **drop-in replacement for [python-pptx](https://python-pptx.readthedocs.io/)** that connects to PPTX Studio for real-time collaboration.
|
|
4
|
+
|
|
5
|
+
Use the exact same imports and API as python-pptx:
|
|
6
|
+
|
|
7
|
+
```python
|
|
8
|
+
from pptx import Presentation
|
|
9
|
+
from pptx.util import Inches, Pt
|
|
10
|
+
from pptx.enum.shapes import MSO_SHAPE
|
|
11
|
+
from pptx.dml.color import RGBColor
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Features
|
|
15
|
+
|
|
16
|
+
- **100% python-pptx compatible imports** - `from pptx import Presentation`
|
|
17
|
+
- **Same API** - Familiar interface for developers and LLMs
|
|
18
|
+
- **Real-time collaboration** - Changes sync instantly with web UI
|
|
19
|
+
- **Remote-first** - Edits apply to live Yjs documents via API
|
|
20
|
+
- **Clear error messages** - Unimplemented features raise helpful errors
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pip install athena-python-pptx
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Quick Start
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
from pptx import Presentation
|
|
32
|
+
from pptx.util import Inches
|
|
33
|
+
|
|
34
|
+
# Connect to an existing deck
|
|
35
|
+
prs = Presentation(
|
|
36
|
+
deck_id="deck_123",
|
|
37
|
+
base_url="https://api.pptx-studio.com",
|
|
38
|
+
api_key="sk_live_..."
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
# Access slides
|
|
42
|
+
slide = prs.slides[0]
|
|
43
|
+
|
|
44
|
+
# Add a textbox
|
|
45
|
+
tb = slide.shapes.add_textbox(
|
|
46
|
+
Inches(1), Inches(1), # position
|
|
47
|
+
Inches(8), Inches(1) # size
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
# Set text content
|
|
51
|
+
tb.text_frame.text = "Hello from Python!"
|
|
52
|
+
|
|
53
|
+
# Export to local file
|
|
54
|
+
prs.save("output.pptx")
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Batching Operations
|
|
58
|
+
|
|
59
|
+
For better performance, batch multiple operations into a single request:
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
with prs.batch():
|
|
63
|
+
tb1 = slide.shapes.add_textbox(Inches(1), Inches(1), Inches(4), Inches(1))
|
|
64
|
+
tb1.text_frame.text = "First"
|
|
65
|
+
|
|
66
|
+
tb2 = slide.shapes.add_textbox(Inches(1), Inches(2), Inches(4), Inches(1))
|
|
67
|
+
tb2.text_frame.text = "Second"
|
|
68
|
+
# Both operations sent as one request when context exits
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## API Reference
|
|
72
|
+
|
|
73
|
+
### Presentation
|
|
74
|
+
|
|
75
|
+
The main entry point for working with a deck.
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
# Connect to existing deck
|
|
79
|
+
prs = Presentation(deck_id, base_url, api_key=None)
|
|
80
|
+
|
|
81
|
+
# Create new deck
|
|
82
|
+
prs = Presentation.create(base_url, api_key=None)
|
|
83
|
+
|
|
84
|
+
# Properties
|
|
85
|
+
prs.deck_id # Deck identifier
|
|
86
|
+
prs.slides # Slides collection
|
|
87
|
+
prs.slide_width # Width in EMU
|
|
88
|
+
prs.slide_height # Height in EMU
|
|
89
|
+
|
|
90
|
+
# Methods
|
|
91
|
+
prs.refresh() # Sync with server
|
|
92
|
+
prs.save(path) # Export and download
|
|
93
|
+
prs.save_to_bytes() # Export as bytes
|
|
94
|
+
prs.render_slide(index) # Render slide as PNG
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Slides
|
|
98
|
+
|
|
99
|
+
Collection of slides in the presentation.
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
# Access slides
|
|
103
|
+
slide = prs.slides[0] # By index
|
|
104
|
+
for slide in prs.slides: # Iterate
|
|
105
|
+
print(slide.slide_id)
|
|
106
|
+
len(prs.slides) # Count
|
|
107
|
+
|
|
108
|
+
# Add new slide
|
|
109
|
+
new_slide = prs.slides.add_slide()
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Shapes
|
|
113
|
+
|
|
114
|
+
Collection of shapes on a slide.
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
# Access shapes
|
|
118
|
+
shape = slide.shapes[0]
|
|
119
|
+
for shape in slide.shapes:
|
|
120
|
+
print(shape.shape_id)
|
|
121
|
+
|
|
122
|
+
# Add textbox
|
|
123
|
+
tb = slide.shapes.add_textbox(left, top, width, height)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Shape
|
|
127
|
+
|
|
128
|
+
Individual shape on a slide.
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
# Properties
|
|
132
|
+
shape.shape_id # Shape identifier
|
|
133
|
+
shape.shape_type # "text", "image", etc.
|
|
134
|
+
shape.left # X position (EMU)
|
|
135
|
+
shape.top # Y position (EMU)
|
|
136
|
+
shape.width # Width (EMU)
|
|
137
|
+
shape.height # Height (EMU)
|
|
138
|
+
shape.rotation # Rotation (degrees)
|
|
139
|
+
shape.text_frame # TextFrame (for text shapes)
|
|
140
|
+
|
|
141
|
+
# Shortcuts
|
|
142
|
+
shape.text # Same as shape.text_frame.text
|
|
143
|
+
|
|
144
|
+
# Methods
|
|
145
|
+
shape.delete() # Remove shape
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### TextFrame
|
|
149
|
+
|
|
150
|
+
Text content container.
|
|
151
|
+
|
|
152
|
+
```python
|
|
153
|
+
# Get/set text
|
|
154
|
+
tf = shape.text_frame
|
|
155
|
+
tf.text = "Hello" # Set all text
|
|
156
|
+
text = tf.text # Get all text
|
|
157
|
+
|
|
158
|
+
# Paragraphs
|
|
159
|
+
for para in tf.paragraphs:
|
|
160
|
+
print(para.text)
|
|
161
|
+
|
|
162
|
+
# Clear text
|
|
163
|
+
tf.clear()
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Units
|
|
167
|
+
|
|
168
|
+
Unit conversion helpers (python-pptx compatible).
|
|
169
|
+
|
|
170
|
+
```python
|
|
171
|
+
from pptx.util import Inches, Pt, Cm, Px, Emu
|
|
172
|
+
|
|
173
|
+
# All return EMU values
|
|
174
|
+
Inches(1) # 914400 EMU
|
|
175
|
+
Pt(12) # 152400 EMU (12 points)
|
|
176
|
+
Cm(2.54) # ~914400 EMU (1 inch)
|
|
177
|
+
Px(96) # 914400 EMU (at 96 DPI)
|
|
178
|
+
Emu(914400) # Direct EMU value
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Error Handling
|
|
182
|
+
|
|
183
|
+
The SDK raises specific exceptions for different error conditions:
|
|
184
|
+
|
|
185
|
+
```python
|
|
186
|
+
from pptx import (
|
|
187
|
+
UnsupportedFeatureError, # Feature not yet implemented
|
|
188
|
+
RemoteError, # Server rejected the request
|
|
189
|
+
ConflictError, # Stale IDs (concurrent modification)
|
|
190
|
+
ValidationError, # Invalid command parameters
|
|
191
|
+
ConnectionError, # Network issues
|
|
192
|
+
AuthenticationError, # Auth failed
|
|
193
|
+
ExportError, # Export job failed
|
|
194
|
+
RenderError, # Render job failed
|
|
195
|
+
)
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Handling unsupported features
|
|
199
|
+
|
|
200
|
+
```python
|
|
201
|
+
try:
|
|
202
|
+
shape.fill.color = "red"
|
|
203
|
+
except UnsupportedFeatureError as e:
|
|
204
|
+
print(f"Not yet supported: {e.feature}")
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## Phase 1 Limitations
|
|
208
|
+
|
|
209
|
+
The SDK is in Phase 1 with limited feature support:
|
|
210
|
+
|
|
211
|
+
### Supported
|
|
212
|
+
- Open deck by ID
|
|
213
|
+
- List and iterate slides
|
|
214
|
+
- Add textbox shapes
|
|
215
|
+
- Set text content
|
|
216
|
+
- Get/set shape position and size
|
|
217
|
+
- Export to PPTX
|
|
218
|
+
- Render slides to PNG
|
|
219
|
+
- Batch operations
|
|
220
|
+
|
|
221
|
+
### Not Yet Supported
|
|
222
|
+
- Upload local PPTX files
|
|
223
|
+
- Add images, charts, tables
|
|
224
|
+
- Slide layouts and masters
|
|
225
|
+
- Rich text formatting (bold, italic, etc.)
|
|
226
|
+
- Shape fills and lines
|
|
227
|
+
- Placeholder access
|
|
228
|
+
- Notes slides
|
|
229
|
+
|
|
230
|
+
Unsupported features raise `UnsupportedFeatureError` with a clear message.
|
|
231
|
+
|
|
232
|
+
## Development
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
# Clone and install dev dependencies
|
|
236
|
+
git clone https://github.com/pptx-studio/python-sdk
|
|
237
|
+
cd python-sdk
|
|
238
|
+
pip install -e ".[dev]"
|
|
239
|
+
|
|
240
|
+
# Run unit tests
|
|
241
|
+
pytest tests/ -v --ignore=tests/test_e2e_roundtrip.py
|
|
242
|
+
|
|
243
|
+
# Type checking
|
|
244
|
+
mypy pptx
|
|
245
|
+
|
|
246
|
+
# Linting
|
|
247
|
+
ruff check pptx
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Running E2E Tests
|
|
251
|
+
|
|
252
|
+
End-to-end tests require a running PPTX Studio server and the `python-pptx` library.
|
|
253
|
+
|
|
254
|
+
```bash
|
|
255
|
+
# Install E2E dependencies
|
|
256
|
+
pip install -e ".[e2e]"
|
|
257
|
+
|
|
258
|
+
# Start the PPTX Studio server (from project root)
|
|
259
|
+
pnpm dev:infra
|
|
260
|
+
pnpm dev
|
|
261
|
+
|
|
262
|
+
# Run E2E tests (in another terminal)
|
|
263
|
+
PPTX_TEST_BASE_URL=http://localhost:3001 pytest tests/test_e2e_roundtrip.py -v
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
The E2E tests will:
|
|
267
|
+
1. Create a PPTX file using python-pptx
|
|
268
|
+
2. Upload it to the running server
|
|
269
|
+
3. Modify it using our SDK
|
|
270
|
+
4. Export and verify the changes
|
|
271
|
+
|
|
272
|
+
## License
|
|
273
|
+
|
|
274
|
+
MIT
|