feat(tables): row_count/column_count/dimensions + sizing round-trip lock — Tables 2.0 Phase 4 (closes epic)#42
Merged
Conversation
…ock — Tables 2.0 Phase 4 (closes epic) Issue: #12 (Phase 4 — closing PR) Closes the Tables 2.0 epic. Phase 1 (PR #37) shipped row/column add/remove. Phase 2 (PR #40) shipped the table style API. Phase 3 (PR #41) shipped range-style merge_cells/split_cells with Cell inspection accessors. This PR closes the last two unchecked sub-features on issue #12: ergonomic count properties on Table, and a regression-lock on per-row height / per-column width round-trip preservation. Public surface added (additive — no existing API changed): `Table` (read-only convenience properties) - `Table.row_count` — number of rows; equivalent to `len(table.rows)` but doesn't instantiate the `_RowCollection`. - `Table.column_count` — number of columns; equivalent to `len(table.columns)` but doesn't instantiate the `_ColumnCollection`. - `Table.dimensions` — `(row_count, column_count)` tuple. Symmetrical with `TcRange.dimensions`; rows-first per the dominant 2D-array convention. Round-trip regression-lock for per-row height / per-column width - `_Row.height` and `_Column.width` setters already wrote to `<a:tr>/@h` and `<a:gridCol>/@w` correctly, and a smoke test confirmed round-trip through save+reload already worked. This PR pins that down with five regression tests covering single-row height, single-column width, mixed-height row sets, mixed-width column sets, and count-property preservation through round-trip — so any future change that breaks EMU preservation fails CI immediately. Out of scope (deferred to follow-ups, not omitted from issue #12) - NumPy-style `table[r, c]` indexing — `table.cell(r, c)` is canonical; adding `__getitem__` would conflict with `_RowCollection.__getitem__` on `table.rows[i]` and confuse the data model. - Bulk getter helpers (`row_heights` / `column_widths` returning lists) — list-comprehension is one line; no API value-add. - Constraint or auto-fit logic — PowerPoint's job at render time. Tests - 22 new pytest cases in `tests/test_tables_phase4.py` covering each new count property (including reactivity to `.rows.add()` / `.columns.remove()` etc.), the read-only setter checks, the round-trip preservation matrix, and Phase-1/2/3 regression checks. Full suite: `3426 passed`. - 7 new behave scenarios in `features/tbl-sizing.feature`: row_count, column_count, dimensions, count-after-add, count-after-remove, height round-trip via stream, width round-trip via stream. Full behave: `1036 scenarios passed, 0 failed` (baseline 1029 + 7 new). - Ruff: `ruff check src tests` → All checks passed; `ruff format --check` → no diff. UAT - `uat_tables_phase4.py` (untracked per CLAUDE.md §6) at repo root. Builds two tables — a 4×4 with explicit graduated row heights and column widths, and a 3×4 that's grown into a 4×4 by using the count properties to drive the loop. All round-trip assertions pass programmatically; visual UAT in PowerPoint or Keynote pending maintainer signoff. Issue #12 closes with this merge — all eight sub-features now shipped. Closes #12
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Phase 4 of issue #12 (Tables 2.0): closing PR — sizing & ergonomics
Closes the Tables 2.0 epic. Phase 1 (PR #37) shipped row/column add/remove. Phase 2 (PR #40) shipped the table style API. Phase 3 (PR #41) shipped range-style merge_cells/split_cells with Cell inspection accessors. This PR adds the last two unchecked sub-features on issue #12 and closes the issue entirely.
Public surface added (additive — no existing API changed)
All three are read-only (
AttributeErroron assignment). They're already reactive:table.rows.add()incrementsrow_count,table.columns.remove(0)decrementscolumn_count, etc.Round-trip regression-lock for sizing
_Row.heightand_Column.widthsetters already wrote to<a:tr>/@hand<a:gridCol>/@wcorrectly, and a smoke test confirmed round-trip through save+reload already worked on master. This PR pins that down with five regression tests covering single-row height, single-column width, mixed-height row sets, mixed-width column sets, and count-property preservation through round-trip — so any future change that breaks EMU preservation fails CI immediately.Out of scope (deferred to follow-ups, not omitted from issue #12)
table[r, c]indexing —table.cell(r, c)is canonical; adding__getitem__would conflict with_RowCollection.__getitem__ontable.rows[i]and confuse the data model.row_heights/column_widthsreturning lists) — list-comprehension is one line; no API value-add.Tests
tests/test_tables_phase4.pycovering each new count property (including reactivity to.rows.add()/.columns.remove()etc.), the read-only setter checks, the round-trip preservation matrix, and Phase-1/2/3 regression checks. Full suite:3426 passed.features/tbl-sizing.feature: row_count read, column_count read, dimensions read, count-after-add, count-after-remove, height round-trip via stream, width round-trip via stream. Full behave:1036 scenarios passed, 0 failed(baseline 1029 + 7 new).ruff check src tests→ All checks passed;ruff format --check→ no diff.Reporting contract (CLAUDE.md §7)
UAT
uat_tables_phase4.py(untracked per CLAUDE.md §6) at repo root.Tables 2.0 epic accounting (all eight sub-features now shipped)
Table.apply_style(name_or_id)Table.rows.add()/.remove()Table.columns.add()/.remove()first_row/banded_rows/last_rowetc. bound to a realtableStyleIdTable.merge_cells/split_cells(idempotent)Cell.gridSpan/rowSpan/hMerge/vMergeread-onlyTable.row_count/column_countergonomicsCloses #12