Skip to content

Commit baceb41

Browse files
author
Steve Canny
committed
tbl: add _CellCollection magic methods
1 parent 8e9f36a commit baceb41

File tree

4 files changed

+72
-2
lines changed

4 files changed

+72
-2
lines changed

docx/oxml/table.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,13 @@ def new(cls):
3131
"""
3232
return OxmlElement('w:tr')
3333

34+
@property
35+
def tc_lst(self):
36+
"""
37+
Sequence containing the ``<w:tc>`` child elements in this ``<w:tr>``.
38+
"""
39+
return self.findall(qn('w:tc'))
40+
3441
def _append_tc(self, tc):
3542
"""
3643
Return *tc* after appending it to end of tc sequence.

docx/table.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ class _Cell(object):
4646
"""
4747
Table cell
4848
"""
49+
def __init__(self, tc):
50+
super(_Cell, self).__init__()
51+
self._tc = tc
4952

5053

5154
class _CellCollection(object):
@@ -56,6 +59,23 @@ def __init__(self, tr):
5659
super(_CellCollection, self).__init__()
5760
self._tr = tr
5861

62+
def __getitem__(self, idx):
63+
"""
64+
Provide indexed access, (e.g. 'cells[0]')
65+
"""
66+
try:
67+
tc = self._tr.tc_lst[idx]
68+
except IndexError:
69+
msg = "cell index [%d] is out of range" % idx
70+
raise IndexError(msg)
71+
return _Cell(tc)
72+
73+
def __iter__(self):
74+
return iter([_Cell(tc) for tc in self._tr.tc_lst])
75+
76+
def __len__(self):
77+
return len(self._tr.tc_lst)
78+
5979

6080
class _Column(object):
6181
"""

features/tbl-item-access.feature

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ Feature: Access table rows, columns, and cells
1212
Given a table having two rows
1313
Then I can access the rows by index
1414

15-
@wip
1615
Scenario: Access cell collection of table row
1716
Given a table row having two cells
1817
Then I can access the cell collection of the row

tests/test_table.py

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88

99
import pytest
1010

11-
from docx.table import _CellCollection, _Column, _Row, _RowCollection, Table
11+
from docx.table import (
12+
_Cell, _CellCollection, _Column, _Row, _RowCollection, Table
13+
)
1214

1315
from .oxml.unitdata.table import a_gridCol, a_tbl, a_tblGrid, a_tc, a_tr
1416
from .oxml.unitdata.text import a_p
@@ -56,6 +58,48 @@ def row_access_fixture(self):
5658
return table
5759

5860

61+
class Describe_CellCollection(object):
62+
63+
def it_can_iterate_over_its__Cell_instances(self, cell_count_fixture):
64+
cells, cell_count = cell_count_fixture
65+
actual_count = 0
66+
for cell in cells:
67+
assert isinstance(cell, _Cell)
68+
actual_count += 1
69+
assert actual_count == cell_count
70+
71+
def it_knows_how_many_cells_it_contains(self, cell_count_fixture):
72+
cells, cell_count = cell_count_fixture
73+
assert len(cells) == cell_count
74+
75+
def it_provides_indexed_access_to_cells(self, cell_count_fixture):
76+
cells, cell_count = cell_count_fixture
77+
for idx in range(-cell_count, cell_count):
78+
cell = cells[idx]
79+
assert isinstance(cell, _Cell)
80+
81+
def it_raises_on_indexed_access_out_of_range(self, cell_count_fixture):
82+
cells, cell_count = cell_count_fixture
83+
too_low = -1 - cell_count
84+
too_high = cell_count
85+
with pytest.raises(IndexError):
86+
cells[too_low]
87+
with pytest.raises(IndexError):
88+
cells[too_high]
89+
90+
# fixtures -------------------------------------------------------
91+
92+
@pytest.fixture
93+
def cell_count_fixture(self):
94+
cell_count = 2
95+
tr_bldr = a_tr().with_nsdecls()
96+
for idx in range(cell_count):
97+
tr_bldr.with_child(a_tc())
98+
tr = tr_bldr.element
99+
cells = _CellCollection(tr)
100+
return cells, cell_count
101+
102+
59103
class Describe_Row(object):
60104

61105
def it_provides_access_to_the_row_cells(self, cells_access_fixture):

0 commit comments

Comments
 (0)