Commit ad7edb8
feat(ergonomics): PathLike + PERCENT_40 typo + Slide.background.element fix (modernization Phase 1)
Phase 1 of issue #29 (Modernization & Ergonomics epic). Bundles three
small, mostly-orthogonal wins that the issue called out as "trivial
cherry-picks" plus a long-standing correctness bug that pollutes the
power-user surface. Defers `Font.color` no-mutate-on-read (closes
upstream scanny#1111/scanny#1074), `collections.abc` import sweep, and dev-tooling
modernization (uv / pyright strict) to Phase 2.
What this PR adds / fixes
-------------------------
1. **`pathlib.Path` / `os.PathLike` support across the API.** Closes
upstream PR scanny#1123. The four entry points users
most commonly hit with a `Path` now accept it without a TypeError:
- `pptx.Presentation(path)` — open a deck from a Path
- `prs.save(path)` — write a deck to a Path
- `slide.shapes.add_picture(path, ...)` — embed an image by Path
- `pptx.parts.image.Image.from_file(path)` — lower-level loader
Each accepts any `os.PathLike[str]` (Path, custom subclasses, etc.)
by coercing via `os.fspath(...)` at the boundary. Existing `str`
and file-like-object callers are unaffected.
2. **`MSO_PATTERN_TYPE.PERCENT_40` typo fixed.** Closes upstream
scanny#1131. The enum member was misspelled `ERCENT_40` (missing leading
`P`). The fix renames to the correct `PERCENT_40` with no value
change (xml_value remains `pct40`, integer value remains 6). Code
that referenced the broken name needs to update — the broken name
is gone deliberately, callers will get a clear AttributeError.
3. **`slide.background.element` returns the `<p:bg>` element.** Closes
upstream issue scanny#1126. Previously `slide.background.element` (and
the private `._element`) returned the parent `<p:cSld>` element
instead of the actual `<p:bg>` background. Power users
introspecting the XML now get the right node. The `<p:bg>` is
materialized on construction (matching the legacy destructive
behavior of accessing `.fill`); since `slide.background` is a
lazyproperty, this only fires on first slide-background access,
not on slide load.
Out of scope (for explicit Phase 2 follow-up)
---------------------------------------------
- **`Font.color` mutate-on-read** (closes upstream scanny#1111, scanny#1074) —
the getter currently materializes `<a:solidFill>` on access, which
means READING a font's color modifies the file. The fix requires a
lazy ColorFormat wrapper that delays solidFill creation until the
setter actually fires; that's a larger refactor that needs its own
PR with careful review against the existing color/fill test suite.
- **`collections.abc` import sweep** (closes upstream scanny#771) — no
remaining offenders in our fork's source tree (the upstream PR was
authored against an older codebase). If any creep in via vendored
fixes, Phase 2 will sweep.
- **Dev-tooling modernization** (uv, pyright strict, pytest-syrupy)
— covered in the issue body but deserves its own PR per the
issue's own "patch 1 / 2 / 3" framing.
Test coverage
-------------
- 15 new unit tests in `tests/test_modernization_phase1.py`:
* 4 tests on `Presentation()` accepting Path/str/BytesIO/PathLike-subclass
* 2 tests on `Presentation.save(Path)` round-trip
* 1 test on `add_picture(Path)`
* 3 tests on `Image.from_file(Path|str|stream)`
* 2 tests on the PERCENT_40 typo fix
* 3 tests on `slide.background.element` (returns `<p:bg>`,
fill still works, RGB round-trip survives)
- 4 new behave scenarios in `features/modernization-phase1.feature`
- New `uat_modernization_phase1.py` (untracked per repo §6) — these
are programmer ergonomics, not visual changes, so the UAT prints
per-fix verification rather than producing a deck for visual review.
Verification
------------
```
$ python3 -m pytest tests/ -q | tail -3
3237 passed in 4.54s
$ ruff check src tests | tail -3
All checks passed!
$ python3 -m behave features/ --no-color | tail -3
1003 scenarios passed, 0 failed, 0 skipped
3010 steps passed, 0 failed, 0 skipped
```
Refs #291 parent 76291a2 commit ad7edb8
8 files changed
Lines changed: 336 additions & 10 deletions
File tree
- features
- steps
- src/pptx
- enum
- parts
- tests
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
18 | 18 | | |
19 | 19 | | |
20 | 20 | | |
21 | | - | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
22 | 24 | | |
23 | 25 | | |
24 | | - | |
25 | | - | |
26 | | - | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
27 | 29 | | |
28 | 30 | | |
29 | 31 | | |
30 | 32 | | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
31 | 37 | | |
32 | 38 | | |
33 | 39 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
351 | 351 | | |
352 | 352 | | |
353 | 353 | | |
354 | | - | |
| 354 | + | |
355 | 355 | | |
356 | 356 | | |
357 | 357 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
153 | 153 | | |
154 | 154 | | |
155 | 155 | | |
156 | | - | |
| 156 | + | |
157 | 157 | | |
158 | 158 | | |
159 | | - | |
| 159 | + | |
| 160 | + | |
160 | 161 | | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
161 | 165 | | |
162 | 166 | | |
163 | 167 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
| 5 | + | |
5 | 6 | | |
6 | 7 | | |
7 | 8 | | |
| |||
66 | 67 | | |
67 | 68 | | |
68 | 69 | | |
69 | | - | |
| 70 | + | |
70 | 71 | | |
71 | 72 | | |
72 | | - | |
| 73 | + | |
| 74 | + | |
73 | 75 | | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
74 | 79 | | |
75 | 80 | | |
76 | 81 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
595 | 595 | | |
596 | 596 | | |
597 | 597 | | |
| 598 | + | |
| 599 | + | |
| 600 | + | |
| 601 | + | |
| 602 | + | |
| 603 | + | |
| 604 | + | |
| 605 | + | |
598 | 606 | | |
599 | 607 | | |
600 | 608 | | |
601 | | - | |
| 609 | + | |
| 610 | + | |
| 611 | + | |
| 612 | + | |
602 | 613 | | |
603 | 614 | | |
604 | 615 | | |
| |||
0 commit comments