Skip to content

Commit fa30e11

Browse files
author
Steve Canny
committed
tbl: add _Cell.width getter
1 parent 70e39d3 commit fa30e11

File tree

7 files changed

+104
-6
lines changed

7 files changed

+104
-6
lines changed

docx/oxml/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ def OxmlElement(nsptag_str, attrs=None, nsdecls=None):
115115

116116
from docx.oxml.table import (
117117
CT_Row, CT_Tbl, CT_TblGrid, CT_TblGridCol, CT_TblLayoutType, CT_TblPr,
118-
CT_Tc
118+
CT_TblWidth, CT_Tc, CT_TcPr
119119
)
120120
register_element_cls('w:gridCol', CT_TblGridCol)
121121
register_element_cls('w:tbl', CT_Tbl)
@@ -124,6 +124,8 @@ def OxmlElement(nsptag_str, attrs=None, nsdecls=None):
124124
register_element_cls('w:tblPr', CT_TblPr)
125125
register_element_cls('w:tblStyle', CT_String)
126126
register_element_cls('w:tc', CT_Tc)
127+
register_element_cls('w:tcPr', CT_TcPr)
128+
register_element_cls('w:tcW', CT_TblWidth)
127129
register_element_cls('w:tr', CT_Row)
128130

129131
from docx.oxml.text import (

docx/oxml/simpletypes.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,18 @@ def validate(cls, value):
276276
)
277277

278278

279+
class ST_TblWidth(XsdString):
280+
281+
@classmethod
282+
def validate(cls, value):
283+
cls.validate_string(value)
284+
valid_values = ('auto', 'dxa', 'nil', 'pct')
285+
if value not in valid_values:
286+
raise ValueError(
287+
"must be one of %s, got '%s'" % (valid_values, value)
288+
)
289+
290+
279291
class ST_TwipsMeasure(XsdUnsignedLong):
280292

281293
@classmethod

docx/oxml/table.py

Lines changed: 72 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,13 @@
88

99
from . import parse_xml
1010
from .ns import nsdecls
11-
from .simpletypes import ST_TblLayoutType, ST_TwipsMeasure
11+
from ..shared import Emu, Twips
12+
from .simpletypes import (
13+
ST_TblLayoutType, ST_TblWidth, ST_TwipsMeasure, XsdInt
14+
)
1215
from .xmlchemy import (
13-
BaseOxmlElement, OneAndOnlyOne, OneOrMore, OptionalAttribute, ZeroOrOne,
14-
ZeroOrMore
16+
BaseOxmlElement, OneAndOnlyOne, OneOrMore, OptionalAttribute,
17+
RequiredAttribute, ZeroOrOne, ZeroOrMore
1518
)
1619

1720

@@ -129,6 +132,33 @@ def style(self, value):
129132
self._add_tblStyle(val=value)
130133

131134

135+
class CT_TblWidth(BaseOxmlElement):
136+
"""
137+
Used for ``<w:tblW>`` and ``<w:tcW>`` elements and many others, to
138+
specify a table-related width.
139+
"""
140+
# the type for `w` attr is actually ST_MeasurementOrPercent, but using
141+
# XsdInt for now because only dxa (twips) values are being used. It's not
142+
# entirely clear what the semantics are for other values like -01.4mm
143+
w = RequiredAttribute('w:w', XsdInt)
144+
type = RequiredAttribute('w:type', ST_TblWidth)
145+
146+
@property
147+
def width(self):
148+
"""
149+
Return the EMU length value represented by the combined ``w:w`` and
150+
``w:type`` attributes.
151+
"""
152+
if self.type != 'dxa':
153+
return None
154+
return Twips(self.w)
155+
156+
@width.setter
157+
def width(self, value):
158+
self.type = 'dxa'
159+
self.w = Emu(value).twips
160+
161+
132162
class CT_Tc(BaseOxmlElement):
133163
"""
134164
``<w:tc>`` table cell element
@@ -170,3 +200,42 @@ def new(cls):
170200
' <w:p/>\n'
171201
'</w:tc>' % nsdecls('w')
172202
)
203+
204+
@property
205+
def width(self):
206+
"""
207+
Return the EMU length value represented in the ``./w:tcPr/w:tcW``
208+
child element or |None| if not present.
209+
"""
210+
tcPr = self.tcPr
211+
if tcPr is None:
212+
return None
213+
return tcPr.width
214+
215+
216+
class CT_TcPr(BaseOxmlElement):
217+
"""
218+
``<w:tcPr>`` element, defining table cell properties
219+
"""
220+
tcW = ZeroOrOne('w:tcW', successors=(
221+
'w:gridSpan', 'w:hMerge', 'w:vMerge', 'w:tcBorders', 'w:shd',
222+
'w:noWrap', 'w:tcMar', 'w:textDirection', 'w:tcFitText', 'w:vAlign',
223+
'w:hideMark', 'w:headers', 'w:cellIns', 'w:cellDel', 'w:cellMerge',
224+
'w:tcPrChange'
225+
))
226+
227+
@property
228+
def width(self):
229+
"""
230+
Return the EMU length value represented in the ``<w:tcW>`` child
231+
element or |None| if not present or its type is not 'dxa'.
232+
"""
233+
tcW = self.tcW
234+
if tcW is None:
235+
return None
236+
return tcW.width
237+
238+
@width.setter
239+
def width(self, value):
240+
tcW = self.get_or_add_tcW()
241+
tcW.width = value

docx/table.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ def width(self):
126126
"""
127127
The width of this cell in EMU, or |None| if no explicit width is set.
128128
"""
129+
return self._tc.width
129130

130131

131132
class _Column(Parented):

features/tbl-cell-props.feature

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

66

7-
@wip
87
Scenario Outline: Get cell width
98
Given a table cell having a width of <width-setting>
109
Then the reported width of the cell is <reported-width>

tests/test_table.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,10 @@ def it_can_replace_its_content_with_a_string_of_text(
168168
cell.text = text
169169
assert cell._tc.xml == expected_xml
170170

171+
def it_knows_its_width_in_EMU(self, width_get_fixture):
172+
cell, expected_width = width_get_fixture
173+
assert cell.width == expected_width
174+
171175
# fixtures -------------------------------------------------------
172176

173177
@pytest.fixture
@@ -188,6 +192,17 @@ def text_set_fixture(self, request):
188192
expected_xml = xml(expected_cxml)
189193
return cell, new_text, expected_xml
190194

195+
@pytest.fixture(params=[
196+
('w:tc', None),
197+
('w:tc/w:tcPr', None),
198+
('w:tc/w:tcPr/w:tcW{w:w=25%,w:type=pct}', None),
199+
('w:tc/w:tcPr/w:tcW{w:w=1440,w:type=dxa}', 914400),
200+
])
201+
def width_get_fixture(self, request):
202+
tc_cxml, expected_width = request.param
203+
cell = _Cell(element(tc_cxml), None)
204+
return cell, expected_width
205+
191206

192207
class Describe_Column(object):
193208

tests/unitutil/cxml.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ def grammar():
228228

229229
# np:attr_name=attr_val ----------------------
230230
attr_name = Word(alphas + ':')
231-
attr_val = Word(alphanums + '-.')
231+
attr_val = Word(alphanums + '-.%')
232232
attr_def = Group(attr_name + equal + attr_val)
233233
attr_list = open_brace + delimitedList(attr_def) + close_brace
234234

0 commit comments

Comments
 (0)