Skip to content

Commit e85ba54

Browse files
author
Steve Canny
committed
font: add Font.size getter
1 parent 60b38a8 commit e85ba54

File tree

6 files changed

+83
-6
lines changed

6 files changed

+83
-6
lines changed

docx/oxml/__init__.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,9 @@ def OxmlElement(nsptag_str, attrs=None, nsdecls=None):
142142
register_element_cls('w:pPr', CT_PPr)
143143
register_element_cls('w:pStyle', CT_String)
144144

145-
from .text.run import CT_Br, CT_Fonts, CT_R, CT_RPr, CT_Text, CT_Underline
145+
from .text.run import (
146+
CT_Br, CT_Fonts, CT_HpsMeasure, CT_R, CT_RPr, CT_Text, CT_Underline
147+
)
146148
register_element_cls('w:b', CT_OnOff)
147149
register_element_cls('w:bCs', CT_OnOff)
148150
register_element_cls('w:br', CT_Br)
@@ -166,6 +168,7 @@ def OxmlElement(nsptag_str, attrs=None, nsdecls=None):
166168
register_element_cls('w:snapToGrid', CT_OnOff)
167169
register_element_cls('w:specVanish', CT_OnOff)
168170
register_element_cls('w:strike', CT_OnOff)
171+
register_element_cls('w:sz', CT_HpsMeasure)
169172
register_element_cls('w:t', CT_Text)
170173
register_element_cls('w:u', CT_Underline)
171174
register_element_cls('w:vanish', CT_OnOff)

docx/oxml/simpletypes.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@
66
type in the associated XML schema.
77
"""
88

9-
from __future__ import absolute_import, print_function
9+
from __future__ import (
10+
absolute_import, division, print_function, unicode_literals
11+
)
1012

1113
from ..exceptions import InvalidXmlError
12-
from ..shared import Emu, Twips
14+
from ..shared import Emu, Pt, Twips
1315

1416

1517
class BaseSimpleType(object):
@@ -235,6 +237,23 @@ class ST_DrawingElementId(XsdUnsignedInt):
235237
pass
236238

237239

240+
class ST_HpsMeasure(XsdUnsignedLong):
241+
"""
242+
Half-point measure, e.g. 24.0 represents 12.0 points.
243+
"""
244+
@classmethod
245+
def convert_from_xml(cls, str_value):
246+
if 'm' in str_value or 'n' in str_value or 'p' in str_value:
247+
return ST_UniversalMeasure.convert_from_xml(str_value)
248+
return Pt(int(str_value)/2.0)
249+
250+
@classmethod
251+
def convert_to_xml(cls, value):
252+
emu = Emu(value)
253+
half_points = int(emu.pt * 2)
254+
return str(half_points)
255+
256+
238257
class ST_Merge(XsdStringEnumeration):
239258
"""
240259
Valid values for <w:xMerge val=""> attribute

docx/oxml/text/run.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@
66

77
from ...enum.text import WD_UNDERLINE
88
from ..ns import qn
9-
from ..simpletypes import ST_BrClear, ST_BrType, ST_String
9+
from ..simpletypes import ST_BrClear, ST_BrType, ST_HpsMeasure, ST_String
1010
from ..xmlchemy import (
11-
BaseOxmlElement, OptionalAttribute, ZeroOrMore, ZeroOrOne
11+
BaseOxmlElement, OptionalAttribute, RequiredAttribute, ZeroOrMore,
12+
ZeroOrOne
1213
)
1314

1415

@@ -29,6 +30,14 @@ class CT_Fonts(BaseOxmlElement):
2930
hAnsi = OptionalAttribute('w:hAnsi', ST_String)
3031

3132

33+
class CT_HpsMeasure(BaseOxmlElement):
34+
"""
35+
Used for ``<w:sz>`` element and others, specifying font size in
36+
half-points.
37+
"""
38+
val = RequiredAttribute('w:val', ST_HpsMeasure)
39+
40+
3241
class CT_R(BaseOxmlElement):
3342
"""
3443
``<w:r>`` element, containing the properties and text for a run.
@@ -161,6 +170,7 @@ class CT_RPr(BaseOxmlElement):
161170
snapToGrid = ZeroOrOne('w:snapToGrid', successors=_tag_seq[16:])
162171
vanish = ZeroOrOne('w:vanish', successors=_tag_seq[17:])
163172
webHidden = ZeroOrOne('w:webHidden', successors=_tag_seq[18:])
173+
sz = ZeroOrOne('w:sz', successors=_tag_seq[24:])
164174
u = ZeroOrOne('w:u', successors=_tag_seq[27:])
165175
rtl = ZeroOrOne('w:rtl', successors=_tag_seq[33:])
166176
cs = ZeroOrOne('w:cs', successors=_tag_seq[34:])
@@ -231,6 +241,16 @@ def style(self, style):
231241
else:
232242
self.rStyle.val = style
233243

244+
@property
245+
def sz_val(self):
246+
"""
247+
The value of `w:sz/@w:val` or |None| if not present.
248+
"""
249+
sz = self.sz
250+
if sz is None:
251+
return None
252+
return sz.val
253+
234254
@property
235255
def underline(self):
236256
"""

docx/text/run.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,27 @@ def name(self, value):
400400
rPr.rFonts_ascii = value
401401
rPr.rFonts_hAnsi = value
402402

403+
@property
404+
def size(self):
405+
"""
406+
Read/write |Length| value or |None|, indicating the font height in
407+
English Metric Units (EMU). |None| indicates the font size should be
408+
inherited from the style hierarchy. |Length| is a subclass of |int|
409+
having properties for convenient conversion into points or other
410+
length units. The :class:`docx.shared.Pt` class allows convenient
411+
specification of point values::
412+
413+
>> font.size = Pt(24)
414+
>> font.size
415+
304800
416+
>> font.size.pt
417+
24.0
418+
"""
419+
rPr = self._element.rPr
420+
if rPr is None:
421+
return None
422+
return rPr.sz_val
423+
403424

404425
class _Text(object):
405426
"""

features/txt-font-props.feature

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ Feature: Get or set font properties
2626
| Avenir Black | None |
2727

2828

29-
@wip
3029
Scenario Outline: Get font size
3130
Given a font of size <size>
3231
Then font.size is <value>

tests/text/test_run.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from docx.enum.text import WD_BREAK, WD_UNDERLINE
1212
from docx.parts.document import InlineShapes
1313
from docx.shape import InlineShape
14+
from docx.shared import Pt
1415
from docx.text.paragraph import Paragraph
1516
from docx.text.run import Font, Run
1617

@@ -380,6 +381,10 @@ def it_can_change_its_typeface_name(self, name_set_fixture):
380381
print(font._element.xml)
381382
assert font._element.xml == expected_xml
382383

384+
def it_knows_its_size(self, size_get_fixture):
385+
font, expected_value = size_get_fixture
386+
assert font.size == expected_value
387+
383388
# fixtures -------------------------------------------------------
384389

385390
@pytest.fixture(params=[
@@ -408,3 +413,13 @@ def name_set_fixture(self, request):
408413
font = Font(element(r_cxml))
409414
expected_xml = xml(expected_r_cxml)
410415
return font, value, expected_xml
416+
417+
@pytest.fixture(params=[
418+
('w:r', None),
419+
('w:r/w:rPr', None),
420+
('w:r/w:rPr/w:sz{w:val=28}', Pt(14)),
421+
])
422+
def size_get_fixture(self, request):
423+
r_cxml, expected_value = request.param
424+
font = Font(element(r_cxml))
425+
return font, expected_value

0 commit comments

Comments
 (0)