Skip to content

Commit 96273f2

Browse files
author
Steve Canny
committed
dml: add ColorFormat.type
1 parent 3c839ee commit 96273f2

File tree

7 files changed

+114
-4
lines changed

7 files changed

+114
-4
lines changed

docx/dml/color.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
absolute_import, division, print_function, unicode_literals
99
)
1010

11+
from ..enum.dml import MSO_COLOR_TYPE
12+
from ..oxml.simpletypes import ST_HexColorAuto
1113
from ..shared import ElementProxy
1214

1315

@@ -21,3 +23,23 @@ class ColorFormat(ElementProxy):
2123

2224
def __init__(self, rPr_parent):
2325
super(ColorFormat, self).__init__(rPr_parent)
26+
27+
@property
28+
def type(self):
29+
"""
30+
Read-only. A member of :ref:`MsoColorType`, one of RGB, THEME, or
31+
AUTO, corresponding to the way this color is defined. Its value is
32+
|None| if no color is applied at this level, which causes the
33+
effective color to be inherited from the style hierarchy.
34+
"""
35+
rPr = self._element.rPr
36+
if rPr is None:
37+
return None
38+
color = rPr.color
39+
if color is None:
40+
return None
41+
if color.themeColor is not None:
42+
return MSO_COLOR_TYPE.THEME
43+
if color.val == ST_HexColorAuto.AUTO:
44+
return MSO_COLOR_TYPE.AUTO
45+
return MSO_COLOR_TYPE.RGB

docx/oxml/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,11 +145,13 @@ def OxmlElement(nsptag_str, attrs=None, nsdecls=None):
145145
register_element_cls('w:vMerge', CT_VMerge)
146146

147147
from .text.font import (
148-
CT_Fonts, CT_HpsMeasure, CT_RPr, CT_Underline, CT_VerticalAlignRun
148+
CT_Color, CT_Fonts, CT_HpsMeasure, CT_RPr, CT_Underline,
149+
CT_VerticalAlignRun
149150
)
150151
register_element_cls('w:b', CT_OnOff)
151152
register_element_cls('w:bCs', CT_OnOff)
152153
register_element_cls('w:caps', CT_OnOff)
154+
register_element_cls('w:color', CT_Color)
153155
register_element_cls('w:cs', CT_OnOff)
154156
register_element_cls('w:dstrike', CT_OnOff)
155157
register_element_cls('w:emboss', CT_OnOff)

docx/oxml/simpletypes.py

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
)
1212

1313
from ..exceptions import InvalidXmlError
14-
from ..shared import Emu, Pt, Twips
14+
from ..shared import Emu, Pt, RGBColor, Twips
1515

1616

1717
class BaseSimpleType(object):
@@ -237,6 +237,41 @@ class ST_DrawingElementId(XsdUnsignedInt):
237237
pass
238238

239239

240+
class ST_HexColor(BaseStringType):
241+
242+
@classmethod
243+
def convert_from_xml(cls, str_value):
244+
if str_value == 'auto':
245+
return ST_HexColorAuto.AUTO
246+
return RGBColor.from_string(str_value)
247+
248+
@classmethod
249+
def convert_to_xml(cls, value):
250+
"""
251+
Keep alpha hex numerals all uppercase just for consistency.
252+
"""
253+
# expecting 3-tuple of ints in range 0-255
254+
return '%02X%02X%02X' % value
255+
256+
@classmethod
257+
def validate(cls, value):
258+
# must be an RGBColor object ---
259+
if not isinstance(value, RGBColor):
260+
raise ValueError(
261+
"rgb color value must be RGBColor object, got %s %s"
262+
% (type(value), value)
263+
)
264+
265+
266+
class ST_HexColorAuto(XsdStringEnumeration):
267+
"""
268+
Value for `w:color/[@val="auto"] attribute setting
269+
"""
270+
AUTO = 'auto'
271+
272+
_members = (AUTO,)
273+
274+
240275
class ST_HpsMeasure(XsdUnsignedLong):
241276
"""
242277
Half-point measure, e.g. 24.0 represents 12.0 points.

docx/oxml/text/font.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,26 @@
44
Custom element classes related to run properties (font).
55
"""
66

7+
from ...enum.dml import MSO_THEME_COLOR
78
from ...enum.text import WD_UNDERLINE
89
from ..ns import qn
9-
from ..simpletypes import ST_HpsMeasure, ST_String, ST_VerticalAlignRun
10+
from ..simpletypes import (
11+
ST_HexColor, ST_HpsMeasure, ST_String, ST_VerticalAlignRun
12+
)
1013
from ..xmlchemy import (
1114
BaseOxmlElement, OptionalAttribute, RequiredAttribute, ZeroOrOne
1215
)
1316

1417

18+
class CT_Color(BaseOxmlElement):
19+
"""
20+
`w:color` element, specifying the color of a font and perhaps other
21+
objects.
22+
"""
23+
val = RequiredAttribute('w:val', ST_HexColor)
24+
themeColor = OptionalAttribute('w:themeColor', MSO_THEME_COLOR)
25+
26+
1527
class CT_Fonts(BaseOxmlElement):
1628
"""
1729
``<w:rFonts>`` element, specifying typeface name for the various language
@@ -60,6 +72,7 @@ class CT_RPr(BaseOxmlElement):
6072
snapToGrid = ZeroOrOne('w:snapToGrid', successors=_tag_seq[16:])
6173
vanish = ZeroOrOne('w:vanish', successors=_tag_seq[17:])
6274
webHidden = ZeroOrOne('w:webHidden', successors=_tag_seq[18:])
75+
color = ZeroOrOne('w:color', successors=_tag_seq[19:])
6376
sz = ZeroOrOne('w:sz', successors=_tag_seq[24:])
6477
u = ZeroOrOne('w:u', successors=_tag_seq[27:])
6578
vertAlign = ZeroOrOne('w:vertAlign', successors=_tag_seq[32:])

features/txt-font-color.feature

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

66

7-
@wip
87
Scenario Outline: Get font color type
98
Given a font having <type> color
109
Then font.color.type is <value>

tests/dml/__init__.py

Whitespace-only changes.

tests/dml/test_color.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# encoding: utf-8
2+
3+
"""
4+
Test suite for docx.dml.color module.
5+
"""
6+
7+
from __future__ import (
8+
absolute_import, division, print_function, unicode_literals
9+
)
10+
11+
from docx.enum.dml import MSO_COLOR_TYPE
12+
from docx.dml.color import ColorFormat
13+
14+
from ..unitutil.cxml import element
15+
16+
import pytest
17+
18+
19+
class DescribeColorFormat(object):
20+
21+
def it_knows_its_color_type(self, type_fixture):
22+
color_format, expected_value = type_fixture
23+
assert color_format.type == expected_value
24+
25+
# fixtures ---------------------------------------------
26+
27+
@pytest.fixture(params=[
28+
('w:r', None),
29+
('w:r/w:rPr', None),
30+
('w:r/w:rPr/w:color{w:val=auto}', MSO_COLOR_TYPE.AUTO),
31+
('w:r/w:rPr/w:color{w:val=4224FF}', MSO_COLOR_TYPE.RGB),
32+
('w:r/w:rPr/w:color{w:themeColor=dark1}', MSO_COLOR_TYPE.THEME),
33+
('w:r/w:rPr/w:color{w:val=F00BA9,w:themeColor=accent1}',
34+
MSO_COLOR_TYPE.THEME),
35+
])
36+
def type_fixture(self, request):
37+
r_cxml, expected_value = request.param
38+
color_format = ColorFormat(element(r_cxml))
39+
return color_format, expected_value

0 commit comments

Comments
 (0)