Skip to content

Commit 1ff6d38

Browse files
author
Steve Canny
committed
blkct: rewrite BlockItemContainer.add_table()
* Fix Describe_Cell.it_can_add_a_table() to work until it can be rewritten in next few commits.
1 parent 7ea4d29 commit 1ff6d38

File tree

8 files changed

+111
-42
lines changed

8 files changed

+111
-42
lines changed

docx/blkcntnr.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
from __future__ import absolute_import, print_function
1010

11+
from .oxml.table import CT_Tbl
1112
from .shared import Parented
1213
from .text.paragraph import Paragraph
1314

@@ -44,13 +45,9 @@ def add_table(self, rows, cols, width):
4445
distributed between the table columns.
4546
"""
4647
from .table import Table
47-
tbl = self._element.add_tbl()
48-
table = Table(tbl, self)
49-
for i in range(cols):
50-
table.add_column()
51-
for i in range(rows):
52-
table.add_row()
53-
return table
48+
tbl = CT_Tbl.new_tbl(rows, cols, width)
49+
self._element._insert_tbl(tbl)
50+
return Table(tbl, self)
5451

5552
@property
5653
def paragraphs(self):

docx/oxml/document.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
<w:document>.
66
"""
77

8-
from .table import CT_Tbl
98
from .xmlchemy import BaseOxmlElement, ZeroOrOne, ZeroOrMore
109

1110

@@ -47,9 +46,6 @@ def add_section_break(self):
4746
p.set_sectPr(cloned_sectPr)
4847
return sentinel_sectPr
4948

50-
def _new_tbl(self):
51-
return CT_Tbl.new()
52-
5349
def clear_content(self):
5450
"""
5551
Remove all content child elements from this <w:body> element. Leave

docx/oxml/table.py

Lines changed: 52 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
Custom element classes for tables
55
"""
66

7-
from __future__ import absolute_import, print_function, unicode_literals
7+
from __future__ import (
8+
absolute_import, division, print_function, unicode_literals
9+
)
810

911
from . import parse_xml
1012
from ..exceptions import InvalidSpanError
@@ -77,13 +79,12 @@ def iter_tcs(self):
7779
yield tc
7880

7981
@classmethod
80-
def new(cls):
82+
def new_tbl(cls, rows, cols, width):
8183
"""
82-
Return a new ``<w:tbl>`` element, containing the required
83-
``<w:tblPr>`` and ``<w:tblGrid>`` child elements.
84+
Return a new `w:tbl` element having *rows* rows and *cols* columns
85+
with *width* distributed evenly between the columns.
8486
"""
85-
tbl = parse_xml(cls._tbl_xml())
86-
return tbl
87+
return parse_xml(cls._tbl_xml(rows, cols, width))
8788

8889
@property
8990
def tblStyle_val(self):
@@ -109,16 +110,58 @@ def tblStyle_val(self, styleId):
109110
tblPr._add_tblStyle().val = styleId
110111

111112
@classmethod
112-
def _tbl_xml(cls):
113+
def _tbl_xml(cls, rows, cols, width):
114+
col_width = Emu(width/cols) if cols > 0 else Emu(0)
113115
return (
114116
'<w:tbl %s>\n'
115117
' <w:tblPr>\n'
116118
' <w:tblW w:type="auto" w:w="0"/>\n'
119+
' <w:tblLook w:firstColumn="1" w:firstRow="1"\n'
120+
' w:lastColumn="0" w:lastRow="0" w:noHBand="0"\n'
121+
' w:noVBand="1" w:val="04A0"/>\n'
117122
' </w:tblPr>\n'
118-
' <w:tblGrid/>\n'
119-
'</w:tbl>' % nsdecls('w')
123+
'%s' # tblGrid
124+
'%s' # trs
125+
'</w:tbl>\n'
126+
) % (
127+
nsdecls('w'),
128+
cls._tblGrid_xml(cols, col_width),
129+
cls._trs_xml(rows, cols, col_width)
120130
)
121131

132+
@classmethod
133+
def _tblGrid_xml(cls, col_count, col_width):
134+
xml = ' <w:tblGrid>\n'
135+
for i in range(col_count):
136+
xml += ' <w:gridCol w:w="%d"/>\n' % col_width.twips
137+
xml += ' </w:tblGrid>\n'
138+
return xml
139+
140+
@classmethod
141+
def _trs_xml(cls, row_count, col_count, col_width):
142+
xml = ''
143+
for i in range(row_count):
144+
xml += (
145+
' <w:tr>\n'
146+
'%s'
147+
' </w:tr>\n'
148+
) % cls._tcs_xml(col_count, col_width)
149+
return xml
150+
151+
@classmethod
152+
def _tcs_xml(cls, col_count, col_width):
153+
xml = ''
154+
for i in range(col_count):
155+
xml += (
156+
' <w:tc>\n'
157+
' <w:tcPr>\n'
158+
' <w:tcW w:type="dxa" w:w="%d"/>\n'
159+
' </w:tcPr>\n'
160+
' <w:p/>\n'
161+
' </w:tc>\n'
162+
) % col_width.twips
163+
return xml
164+
122165

123166
class CT_TblGrid(BaseOxmlElement):
124167
"""

docx/table.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class Table(Parented):
1818
"""
1919
def __init__(self, tbl, parent):
2020
super(Table, self).__init__(parent)
21-
self._tbl = tbl
21+
self._element = self._tbl = tbl
2222

2323
def add_column(self):
2424
"""

features/doc-add-table.feature

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ Feature: Add a table
44
I need a way to add a table
55

66

7-
@wip
87
Scenario: Add a table specifying only row and column count
98
Given a blank document
109
When I add a 2 x 2 table specifying only row and column count

tests/test_blkcntnr.py

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@
99
import pytest
1010

1111
from docx.blkcntnr import BlockItemContainer
12+
from docx.shared import Inches
1213
from docx.table import Table
1314
from docx.text.paragraph import Paragraph
1415

1516
from .unitutil.cxml import element, xml
17+
from .unitutil.file import snippet_seq
1618
from .unitutil.mock import call, instance_mock, method_mock
1719

1820

@@ -30,10 +32,11 @@ def it_can_add_a_paragraph(self, add_paragraph_fixture):
3032
assert new_paragraph is paragraph_
3133

3234
def it_can_add_a_table(self, add_table_fixture):
33-
blkcntnr, rows, cols, expected_xml = add_table_fixture
34-
table = blkcntnr.add_table(rows, cols, None)
35-
assert blkcntnr._element.xml == expected_xml
35+
blkcntnr, rows, cols, width, expected_xml = add_table_fixture
36+
table = blkcntnr.add_table(rows, cols, width)
3637
assert isinstance(table, Table)
38+
assert table._element.xml == expected_xml
39+
assert table._parent is blkcntnr
3740

3841
def it_provides_access_to_the_paragraphs_it_contains(
3942
self, paragraphs_fixture):
@@ -91,21 +94,12 @@ def _add_paragraph_fixture(self, request):
9194
expected_xml = xml(after_cxml)
9295
return blkcntnr, expected_xml
9396

94-
@pytest.fixture(params=[
95-
('w:body', 0, 0, 'w:body/w:tbl/(w:tblPr/w:tblW{w:type=auto,w:w=0},w:'
96-
'tblGrid)'),
97-
('w:body', 1, 0, 'w:body/w:tbl/(w:tblPr/w:tblW{w:type=auto,w:w=0},w:'
98-
'tblGrid,w:tr)'),
99-
('w:body', 0, 1, 'w:body/w:tbl/(w:tblPr/w:tblW{w:type=auto,w:w=0},w:'
100-
'tblGrid/w:gridCol)'),
101-
('w:body', 1, 1, 'w:body/w:tbl/(w:tblPr/w:tblW{w:type=auto,w:w=0},w:'
102-
'tblGrid/w:gridCol,w:tr/w:tc/w:p)'),
103-
])
104-
def add_table_fixture(self, request):
105-
blkcntnr_cxml, rows, cols, after_cxml = request.param
106-
blkcntnr = BlockItemContainer(element(blkcntnr_cxml), None)
107-
expected_xml = xml(after_cxml)
108-
return blkcntnr, rows, cols, expected_xml
97+
@pytest.fixture
98+
def add_table_fixture(self):
99+
blkcntnr = BlockItemContainer(element('w:body'), None)
100+
rows, cols, width = 2, 2, Inches(2)
101+
expected_xml = snippet_seq('new-tbl')[0]
102+
return blkcntnr, rows, cols, width, expected_xml
109103

110104
@pytest.fixture(params=[
111105
('w:body', 0),
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<w:tbl xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
2+
<w:tblPr>
3+
<w:tblW w:type="auto" w:w="0"/>
4+
<w:tblLook w:firstColumn="1" w:firstRow="1" w:lastColumn="0" w:lastRow="0" w:noHBand="0" w:noVBand="1" w:val="04A0"/>
5+
</w:tblPr>
6+
<w:tblGrid>
7+
<w:gridCol w:w="1440"/>
8+
<w:gridCol w:w="1440"/>
9+
</w:tblGrid>
10+
<w:tr>
11+
<w:tc>
12+
<w:tcPr>
13+
<w:tcW w:type="dxa" w:w="1440"/>
14+
</w:tcPr>
15+
<w:p/>
16+
</w:tc>
17+
<w:tc>
18+
<w:tcPr>
19+
<w:tcW w:type="dxa" w:w="1440"/>
20+
</w:tcPr>
21+
<w:p/>
22+
</w:tc>
23+
</w:tr>
24+
<w:tr>
25+
<w:tc>
26+
<w:tcPr>
27+
<w:tcW w:type="dxa" w:w="1440"/>
28+
</w:tcPr>
29+
<w:p/>
30+
</w:tc>
31+
<w:tc>
32+
<w:tcPr>
33+
<w:tcW w:type="dxa" w:w="1440"/>
34+
</w:tcPr>
35+
<w:p/>
36+
</w:tc>
37+
</w:tr>
38+
</w:tbl>

tests/test_table.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@ def it_can_add_a_paragraph(self, add_paragraph_fixture):
338338

339339
def it_can_add_a_table(self, add_table_fixture):
340340
cell, expected_xml = add_table_fixture
341-
table = cell.add_table(rows=0, cols=0)
341+
table = cell.add_table(rows=0, cols=1)
342342
assert cell._tc.xml == expected_xml
343343
assert isinstance(table, Table)
344344

@@ -372,7 +372,9 @@ def add_table_fixture(self, request):
372372
# the table has some overhead elements, also a blank para after since
373373
# it's in a cell.
374374
after_tc_cxml += (
375-
'/(w:tblPr/w:tblW{w:type=auto,w:w=0},w:tblGrid),w:p)'
375+
'/(w:tblPr/(w:tblW{w:type=auto,w:w=0},w:tblLook{w:firstColumn=1,'
376+
'w:firstRow=1,w:lastColumn=0,w:lastRow=0,w:noHBand=0,w:noVBand=1'
377+
',w:val=04A0}),w:tblGrid/w:gridCol{w:w=1440}),w:p)'
376378
)
377379
cell = _Cell(element(tc_cxml), None)
378380
expected_xml = xml(after_tc_cxml)

0 commit comments

Comments
 (0)