Skip to content

Commit e685394

Browse files
author
Steve Canny
committed
tbl: add _Column.width getter
Also, sequence Length methods in alpha order
1 parent 617eadd commit e685394

File tree

8 files changed

+100
-13
lines changed

8 files changed

+100
-13
lines changed

docs/dev/analysis/features/table.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,16 @@ Schema Definitions
197197
<xsd:union memberTypes="ST_UnsignedDecimalNumber ST_PositiveUniversalMeasure"/>
198198
</xsd:simpleType>
199199

200+
<xsd:simpleType name="ST_UnsignedDecimalNumber">
201+
<xsd:restriction base="xsd:unsignedLong"/>
202+
</xsd:simpleType>
203+
204+
<xsd:simpleType name="ST_PositiveUniversalMeasure">
205+
<xsd:restriction base="ST_UniversalMeasure">
206+
<xsd:pattern value="[0-9]+(\.[0-9]+)?(mm|cm|in|pt|pc|pi)"/>
207+
</xsd:restriction>
208+
</xsd:simpleType>
209+
200210
<xsd:group name="EG_ContentRowContent">
201211
<xsd:choice>
202212
<xsd:element name="tr" type="CT_Row" minOccurs="0" maxOccurs="unbounded"/>

docx/oxml/__init__.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,10 @@ def OxmlElement(nsptag_str, attrs=None, nsdecls=None):
107107
register_element_cls('w:style', CT_Style)
108108
register_element_cls('w:styles', CT_Styles)
109109

110-
from docx.oxml.table import CT_Row, CT_Tbl, CT_TblGrid, CT_TblPr, CT_Tc
110+
from docx.oxml.table import (
111+
CT_Row, CT_Tbl, CT_TblGrid, CT_TblGridCol, CT_TblPr, CT_Tc
112+
)
113+
register_element_cls('w:gridCol', CT_TblGridCol)
111114
register_element_cls('w:tbl', CT_Tbl)
112115
register_element_cls('w:tblGrid', CT_TblGrid)
113116
register_element_cls('w:tblPr', CT_TblPr)

docx/oxml/simpletypes.py

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

99
from __future__ import absolute_import, print_function
1010

11-
from ..shared import Emu
11+
from ..shared import Emu, Twips
1212

1313

1414
class BaseSimpleType(object):
@@ -153,6 +153,13 @@ def validate(cls, value):
153153
cls.validate_int_in_range(value, 0, 4294967295)
154154

155155

156+
class XsdUnsignedLong(BaseIntType):
157+
158+
@classmethod
159+
def validate(cls, value):
160+
cls.validate_int_in_range(value, 0, 18446744073709551615)
161+
162+
156163
class ST_BrClear(XsdString):
157164

158165
@classmethod
@@ -231,6 +238,21 @@ class ST_String(XsdString):
231238
pass
232239

233240

241+
class ST_TwipsMeasure(XsdUnsignedLong):
242+
243+
@classmethod
244+
def convert_from_xml(cls, str_value):
245+
if 'i' in str_value or 'm' in str_value or 'p' in str_value:
246+
return ST_UniversalMeasure.convert_from_xml(str_value)
247+
return Twips(int(str_value))
248+
249+
@classmethod
250+
def convert_to_xml(cls, value):
251+
emu = Emu(value)
252+
twips = emu.twips
253+
return str(twips)
254+
255+
234256
class ST_UniversalMeasure(BaseSimpleType):
235257

236258
@classmethod

docx/oxml/table.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@
88

99
from . import parse_xml
1010
from .ns import nsdecls
11+
from .simpletypes import ST_TwipsMeasure
1112
from .xmlchemy import (
12-
BaseOxmlElement, OneAndOnlyOne, OneOrMore, ZeroOrOne, ZeroOrMore
13+
BaseOxmlElement, OneAndOnlyOne, OneOrMore, OptionalAttribute, ZeroOrOne,
14+
ZeroOrMore
1315
)
1416

1517

@@ -65,6 +67,7 @@ class CT_TblGridCol(BaseOxmlElement):
6567
``<w:gridCol>`` element, child of ``<w:tblGrid>``, defines a table
6668
column.
6769
"""
70+
w = OptionalAttribute('w:w', ST_TwipsMeasure)
6871

6972

7073
class CT_TblPr(BaseOxmlElement):

docx/shared.py

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,23 +18,31 @@ class Length(int):
1818
_EMUS_PER_CM = 360000
1919
_EMUS_PER_MM = 36000
2020
_EMUS_PER_PX = 12700
21+
_EMUS_PER_TWIP = 635
2122

2223
def __new__(cls, emu):
2324
return int.__new__(cls, emu)
2425

2526
@property
26-
def inches(self):
27+
def cm(self):
2728
"""
28-
The equivalent length expressed in inches (float).
29+
The equivalent length expressed in centimeters (float).
2930
"""
30-
return self / float(self._EMUS_PER_INCH)
31+
return self / float(self._EMUS_PER_CM)
3132

3233
@property
33-
def cm(self):
34+
def emu(self):
3435
"""
35-
The equivalent length expressed in centimeters (float).
36+
The equivalent length expressed in English Metric Units (int).
3637
"""
37-
return self / float(self._EMUS_PER_CM)
38+
return self
39+
40+
@property
41+
def inches(self):
42+
"""
43+
The equivalent length expressed in inches (float).
44+
"""
45+
return self / float(self._EMUS_PER_INCH)
3846

3947
@property
4048
def mm(self):
@@ -50,11 +58,11 @@ def px(self):
5058
return int(round(self / float(self._EMUS_PER_PX)) + 0.1)
5159

5260
@property
53-
def emu(self):
61+
def twips(self):
5462
"""
55-
The equivalent length expressed in English Metric Units (int).
63+
The equivalent length expressed in twips (int).
5664
"""
57-
return self
65+
return int(round(self / float(self._EMUS_PER_TWIP)) + 0.1)
5866

5967

6068
class Inches(Length):
@@ -116,6 +124,16 @@ def __new__(cls, px):
116124
return Length.__new__(cls, emu)
117125

118126

127+
class Twips(Length):
128+
"""
129+
Convenience constructor for length in twips, e.g. ``width = Twips(42)``.
130+
A twip is a twentieth of a point, 635 EMU.
131+
"""
132+
def __new__(cls, twips):
133+
emu = int(twips * Length._EMUS_PER_TWIP)
134+
return Length.__new__(cls, emu)
135+
136+
119137
def lazyproperty(f):
120138
"""
121139
@lazyprop decorator. Decorated method will be called only on first access

docx/table.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,14 @@ def cells(self):
132132
"""
133133
return _ColumnCells(self._tbl, self._gridCol)
134134

135+
@property
136+
def width(self):
137+
"""
138+
The width of this column in EMU, or |None| if no explicit width is
139+
set.
140+
"""
141+
return self._gridCol.w
142+
135143

136144
class _ColumnCells(object):
137145
"""

features/tbl-col-props.feature

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ Feature: Get and set table column widths
33
As an python-docx developer
44
I need a way to get and set the width of a table's columns
55

6-
@wip
6+
77
Scenario Outline: Get existing column width
88
Given a table column having a width of <width>
99
Then the reported column width is <width-emu>

tests/test_table.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,8 +168,31 @@ def it_provides_access_to_the_column_cells(self, column):
168168
cells = column.cells
169169
assert isinstance(cells, _ColumnCells)
170170

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

177+
@pytest.fixture(params=[
178+
(4242, 2693670),
179+
(1440, 914400),
180+
('2.54cm', 914400),
181+
('54mm', 1944000),
182+
('12.5pt', 158750),
183+
(None, None),
184+
])
185+
def width_fixture(self, request):
186+
w, expected_width = request.param
187+
gridCol_bldr = a_gridCol().with_nsdecls()
188+
if w is not None:
189+
gridCol_bldr.with_w(w)
190+
gridCol = gridCol_bldr.element
191+
column = _Column(gridCol, None)
192+
return column, expected_width
193+
194+
# fixture components ---------------------------------------------
195+
173196
@pytest.fixture
174197
def column(self):
175198
return _Column(None, None)

0 commit comments

Comments
 (0)