You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Issue: #29 (Phase 2)
Phase 1 (PR #39) shipped PathLike + PERCENT_40 typo + Slide.background fix.
This PR closes three nagging upstream tickets in a single bundle, all
covered by issue #29's "bug fixes that pollute every other epic if left
unfixed" group plus the most-cited shape-lookup ergonomic from the API
ergonomics group.
Bug fixes
- `Font.color` getter is now non-mutating. Prior implementation called
`self.fill.solid()` on every read, inserting `<a:solidFill/>` into the
run's `<a:rPr>` element — meaning *reading* a font's color silently
modified the document. New implementation returns a
`_LazyFontColorFormat` proxy that mirrors `ColorFormat`'s public
surface; reads (`type`, `rgb`, `theme_color`, `brightness`,
`transparency`) return |None| / inherit values without writing; the
setter path materializes `<a:solidFill/>` lazily on first write and
delegates to the real `ColorFormat`. Closesscanny#1111
and scanny#1074.
- W3CDTF datetime parser returns tz-aware datetimes when the source
string carries timezone information. `Z` suffix → UTC; numeric offsets
like `-08:00` or `+05:30` → fixed-offset `datetime.timezone`. Strings
with no offset (year-only, year-month, year-month-day, or bare
timestamp) continue to return naive datetimes — we don't assume a
timezone where none was given. The setter accepts both naive and
tz-aware inputs; tz-aware inputs are converted to UTC via
`astimezone(timezone.utc)` before serialization so the on-disk W3CDTF
form always uses the canonical `YYYY-MM-DDTHH:MM:SSZ` shape. Closesscanny#957.
Sign-convention fix: the prior `_offset_dt` had `sign_factor = -1 if
sign == "+" else 1` (inverted vs. POSIX/W3CDTF convention) and
*adjusted the clock values*; the new `_tzinfo_from_offset_str` uses
`sign_factor = 1 if sign == "+" else -1` and returns a `tzinfo`
instance, leaving the clock values intact. End-to-end behavior is
preserved when callers convert via `astimezone(utc)` — `'2024-01-15
T10:30:00-08:00'` still represents the same instant (18:30 UTC).
API ergonomics
- `_BaseShapes.by_name(name)` lookup helper. Returns the first shape in
document order whose `.name` matches `name` (case-sensitive, matching
PowerPoint's behavior). Raises `KeyError` with a clear message on
miss. Defined on `_BaseShapes` so it inherits to `SlideShapes`,
`SlideLayoutShapes`, `SlideMasterShapes`, etc. Closesscanny#798, scanny#309, and
scanny#532.
Behavior changes (intentional, documented in the PR body)
- Reading `font.color` no longer inserts `<a:solidFill/>`. Code that
relied on the mutation as a side-effect needs to call
`font.fill.solid()` explicitly.
- Reading `core_properties.created` / `last_printed` / `modified` on a
document whose XML carries `Z` or numeric offset markers now returns
a tz-aware datetime. Naive-input expectations must update.
Tests
- 27 new pytest cases in `tests/test_modernization_phase2.py` covering
byte-stable XML on Font.color reads, lazy materialization on first
set, datetime parser tz-awareness across all five W3CDTF input
forms, round-trip through save/reload, and the three by_name paths
(hit / miss / case-sensitivity / multi-match / inheritance to layouts
and masters). Two existing test fixtures updated to expect tz-aware
values where the input strings carry `Z`. Full pytest: `3453 passed`.
- 5 new behave scenarios in `features/modernization-phase2.feature`
(Font.color non-mutation byte-diff, lazy materialization, tz-aware
round-trip, by_name match, by_name miss). Existing
`features/steps/coreprops.py` updated to use tz-aware datetimes for
the now-tz-aware reload values. Full behave: `1041 scenarios passed,
0 failed`.
- Ruff: `ruff check src tests` → All checks passed; `ruff format
--check` → no diff.
Skipped from issue #29 Phase 2 (deferred or no-op)
- `collections.abc` import path migration (would closescanny#771):
already complete in this fork; verified via grep across `src/`.
- `iter_leaf_shapes`, `Mapping` ABC, `find_by_xpath`, selection-pane
order listing: deferred to a future Phase 4 to keep Phase 2 focused
on bug fixes.
Refs #29
0 commit comments