Skip to content

Commit 99aeee4

Browse files
author
Steve Canny
committed
style: add Styles.default()
1 parent 8995fe3 commit 99aeee4

File tree

4 files changed

+55
-3
lines changed

4 files changed

+55
-3
lines changed

docx/oxml/parts/styles.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"""
66

77
from ...enum.style import WD_STYLE_TYPE
8-
from ..simpletypes import ST_String
8+
from ..simpletypes import ST_OnOff, ST_String
99
from ..xmlchemy import (
1010
BaseOxmlElement, OptionalAttribute, ZeroOrMore, ZeroOrOne
1111
)
@@ -26,6 +26,7 @@ class CT_Style(BaseOxmlElement):
2626
pPr = ZeroOrOne('w:pPr', successors=_tag_seq[17:])
2727
type = OptionalAttribute('w:type', WD_STYLE_TYPE)
2828
styleId = OptionalAttribute('w:styleId', ST_String)
29+
default = OptionalAttribute('w:default', ST_OnOff)
2930
del _tag_seq
3031

3132
@property
@@ -53,6 +54,19 @@ class CT_Styles(BaseOxmlElement):
5354
"""
5455
style = ZeroOrMore('w:style', successors=())
5556

57+
def default_for(self, style_type):
58+
"""
59+
Return `w:style[@w:type="*{style_type}*][-1]` or |None| if not found.
60+
"""
61+
default_styles_for_type = [
62+
s for s in self._iter_styles()
63+
if s.type == style_type and s.default
64+
]
65+
if not default_styles_for_type:
66+
return None
67+
# spec calls for last default in document order
68+
return default_styles_for_type[-1]
69+
5670
def get_by_id(self, styleId):
5771
"""
5872
Return the ``<w:style>`` child element having ``styleId`` attribute
@@ -74,3 +88,9 @@ def get_by_name(self, name):
7488
return self.xpath(xpath)[0]
7589
except IndexError:
7690
return None
91+
92+
def _iter_styles(self):
93+
"""
94+
Generate each of the `w:style` child elements in document order.
95+
"""
96+
return (style for style in self.xpath('w:style'))

docx/styles/styles.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,10 @@ def default(self, style_type):
4343
Return the default style for *style_type* or |None| if no default is
4444
defined for that type (not common).
4545
"""
46-
raise NotImplementedError
46+
style = self._element.default_for(style_type)
47+
if style is None:
48+
return None
49+
return StyleFactory(style)
4750

4851
def get_by_id(self, style_id, style_type):
4952
"""

features/par-style-prop.feature

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ Feature: Each paragraph has a read/write style
44
I need the ability to get and set the style of a paragraph
55

66

7-
@wip
87
Scenario Outline: Get the style of a paragraph
98
Given a paragraph having <style> style
109
Then paragraph.style is <expected-value>

tests/styles/test_styles.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,15 @@ def it_raises_on_style_not_found(self, get_raises_fixture):
5050
with pytest.raises(KeyError):
5151
styles[key]
5252

53+
def it_can_get_the_default_style_for_a_type(self, default_fixture):
54+
styles, style_type, StyleFactory_ = default_fixture[:3]
55+
StyleFactory_calls, style_ = default_fixture[3:]
56+
57+
style = styles.default(style_type)
58+
59+
assert StyleFactory_.call_args_list == StyleFactory_calls
60+
assert style is style_
61+
5362
def it_can_get_a_style_of_type_by_id(self, get_by_id_fixture):
5463
styles, style_id, style_type = get_by_id_fixture[:3]
5564
default_calls, _get_by_id_calls, style_ = get_by_id_fixture[3:]
@@ -72,6 +81,27 @@ def it_gets_a_style_by_id_to_help(self, _get_by_id_fixture):
7281

7382
# fixture --------------------------------------------------------
7483

84+
@pytest.fixture(params=[
85+
('w:styles',
86+
False, WD_STYLE_TYPE.CHARACTER),
87+
('w:styles/w:style{w:type=paragraph,w:default=1}',
88+
True, WD_STYLE_TYPE.PARAGRAPH),
89+
('w:styles/(w:style{w:type=table,w:default=1},w:style{w:type=table,w'
90+
':default=1})',
91+
True, WD_STYLE_TYPE.TABLE),
92+
])
93+
def default_fixture(self, request, StyleFactory_, style_):
94+
styles_cxml, is_defined, style_type = request.param
95+
styles_elm = element(styles_cxml)
96+
styles = Styles(styles_elm)
97+
StyleFactory_calls = [call(styles_elm[-1])] if is_defined else []
98+
StyleFactory_.return_value = style_
99+
expected_value = style_ if is_defined else None
100+
return (
101+
styles, style_type, StyleFactory_, StyleFactory_calls,
102+
expected_value
103+
)
104+
75105
@pytest.fixture(params=[None, 'Foo'])
76106
def get_by_id_fixture(self, request, default_, _get_by_id_, style_):
77107
style_id, style_type = request.param, 1

0 commit comments

Comments
 (0)