Skip to content

Commit 1cfcee7

Browse files
committed
feat(table): add _Row.grid_cols_after
1 parent 4e5dd91 commit 1cfcee7

File tree

7 files changed

+73
-0
lines changed

7 files changed

+73
-0
lines changed

features/steps/table.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,13 @@ def given_a_table_having_two_rows(context: Context):
154154
context.table_ = document.tables[0]
155155

156156

157+
@given("a table row ending with {count} empty grid columns")
158+
def given_a_table_row_ending_with_count_empty_grid_columns(context: Context, count: str):
159+
document = Document(test_docx("tbl-props"))
160+
table = document.tables[8]
161+
context.row = table.rows[int(count)]
162+
163+
157164
@given("a table row having height of {state}")
158165
def given_a_table_row_having_height_of_state(context: Context, state: str):
159166
table_idx = {"no explicit setting": 0, "2 inches": 2, "3 inches": 3}[state]
@@ -354,6 +361,13 @@ def then_can_iterate_over_row_collection(context: Context):
354361
assert actual_count == 2
355362

356363

364+
@then("row.grid_cols_after is {value}")
365+
def then_row_grid_cols_after_is_value(context: Context, value: str):
366+
expected = int(value)
367+
actual = context.row.grid_cols_after
368+
assert actual == expected, "expected %s, got %s" % (expected, actual)
369+
370+
357371
@then("row.grid_cols_before is {value}")
358372
def then_row_grid_cols_before_is_value(context: Context, value: str):
359373
expected = int(value)
22 Bytes
Binary file not shown.

features/tbl-row-props.feature

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,17 @@ Feature: Get and set table row properties
44
I need a way to get and set the properties of a table row
55

66

7+
Scenario Outline: Get Row.grid_cols_after
8+
Given a table row ending with <count> empty grid columns
9+
Then row.grid_cols_after is <count>
10+
11+
Examples: Row.grid_cols_after value cases
12+
| count |
13+
| 0 |
14+
| 1 |
15+
| 2 |
16+
17+
718
Scenario Outline: Get Row.grid_cols_before
819
Given a table row starting with <count> empty grid columns
920
Then row.grid_cols_before is <count>

src/docx/oxml/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@
159159
)
160160

161161
register_element_cls("w:bidiVisual", CT_OnOff)
162+
register_element_cls("w:gridAfter", CT_DecimalNumber)
162163
register_element_cls("w:gridBefore", CT_DecimalNumber)
163164
register_element_cls("w:gridCol", CT_TblGridCol)
164165
register_element_cls("w:gridSpan", CT_DecimalNumber)

src/docx/oxml/table.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,14 @@ class CT_Row(BaseOxmlElement):
6060
trPr: CT_TrPr | None = ZeroOrOne("w:trPr") # pyright: ignore[reportAssignmentType]
6161
tc = ZeroOrMore("w:tc")
6262

63+
@property
64+
def grid_after(self) -> int:
65+
"""The number of unpopulated layout-grid cells at the end of this row."""
66+
trPr = self.trPr
67+
if trPr is None:
68+
return 0
69+
return trPr.grid_after
70+
6371
@property
6472
def grid_before(self) -> int:
6573
"""The number of unpopulated layout-grid cells at the start of this row."""
@@ -893,6 +901,9 @@ class CT_TrPr(BaseOxmlElement):
893901
"w:del",
894902
"w:trPrChange",
895903
)
904+
gridAfter: CT_DecimalNumber | None = ZeroOrOne( # pyright: ignore[reportAssignmentType]
905+
"w:gridAfter", successors=_tag_seq[4:]
906+
)
896907
gridBefore: CT_DecimalNumber | None = ZeroOrOne( # pyright: ignore[reportAssignmentType]
897908
"w:gridBefore", successors=_tag_seq[3:]
898909
)
@@ -901,6 +912,12 @@ class CT_TrPr(BaseOxmlElement):
901912
)
902913
del _tag_seq
903914

915+
@property
916+
def grid_after(self) -> int:
917+
"""The number of unpopulated layout-grid cells at the end of this row."""
918+
gridAfter = self.gridAfter
919+
return 0 if gridAfter is None else gridAfter.val
920+
904921
@property
905922
def grid_before(self) -> int:
906923
"""The number of unpopulated layout-grid cells at the start of this row."""

src/docx/table.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,23 @@ def cells(self) -> tuple[_Cell, ...]:
385385
"""Sequence of |_Cell| instances corresponding to cells in this row."""
386386
return tuple(self.table.row_cells(self._index))
387387

388+
@property
389+
def grid_cols_after(self) -> int:
390+
"""Count of unpopulated grid-columns after the last cell in this row.
391+
392+
Word allows a row to "end early", meaning that one or more cells are not present at the
393+
end of that row.
394+
395+
Note these are not simply "empty" cells. The renderer reads this value and "skips" this
396+
many columns after drawing the last cell.
397+
398+
Note this also implies that not all rows are guaranteed to have the same number of cells,
399+
e.g. `_Row.cells` could have length `n` for one row and `n - m` for the next row in the same
400+
table. Visually this appears as a column (at the beginning or end, not in the middle) with
401+
one or more cells missing.
402+
"""
403+
return self._tr.grid_after
404+
388405
@property
389406
def grid_cols_before(self) -> int:
390407
"""Count of unpopulated grid-columns before the first cell in this row.

tests/test_table.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -645,6 +645,19 @@ def table_(self, request: FixtureRequest):
645645
class Describe_Row:
646646
"""Unit-test suite for `docx.table._Row` objects."""
647647

648+
@pytest.mark.parametrize(
649+
("tr_cxml", "expected_value"),
650+
[
651+
("w:tr", 0),
652+
("w:tr/w:trPr", 0),
653+
("w:tr/w:trPr/w:gridAfter{w:val=0}", 0),
654+
("w:tr/w:trPr/w:gridAfter{w:val=4}", 4),
655+
],
656+
)
657+
def it_knows_its_grid_cols_after(self, tr_cxml: str, expected_value: int | None, parent_: Mock):
658+
row = _Row(cast(CT_Row, element(tr_cxml)), parent_)
659+
assert row.grid_cols_after == expected_value
660+
648661
@pytest.mark.parametrize(
649662
("tr_cxml", "expected_value"),
650663
[

0 commit comments

Comments
 (0)