Skip to content

Commit a902464

Browse files
author
Steve Canny
committed
style: add Styles.get_by_id()
1 parent c0ea333 commit a902464

File tree

2 files changed

+54
-7
lines changed

2 files changed

+54
-7
lines changed

docx/styles/styles.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,29 @@ def __iter__(self):
3838
def __len__(self):
3939
return len(self._element.style_lst)
4040

41+
def default(self, style_type):
42+
"""
43+
Return the default style for *style_type* or |None| if no default is
44+
defined for that type (not common).
45+
"""
46+
raise NotImplementedError
47+
4148
def get_by_id(self, style_id, style_type):
4249
"""
4350
Return the style of *style_type* matching *style_id*. Returns the
4451
default for *style_type* if *style_id* is not found or is |None|, or
4552
if the style having *style_id* is not of *style_type*.
4653
"""
54+
if style_id is None:
55+
return self.default(style_type)
56+
return self._get_by_id(style_id, style_type)
57+
58+
def _get_by_id(self, style_id, style_type):
59+
"""
60+
Return the style of *style_type* matching *style_id*. Returns the
61+
default for *style_type* if *style_id* is not found or if the style
62+
having *style_id* is not of *style_type*.
63+
"""
4764
raise NotImplementedError
4865

4966
@staticmethod

tests/styles/test_styles.py

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from docx.styles.styles import Styles
1515

1616
from ..unitutil.cxml import element
17-
from ..unitutil.mock import call, function_mock, instance_mock
17+
from ..unitutil.mock import call, function_mock, instance_mock, method_mock
1818

1919

2020
class DescribeStyles(object):
@@ -34,13 +34,13 @@ def it_can_iterate_over_its_styles(self, iter_fixture):
3434
assert count == expected_count
3535
assert StyleFactory_.call_args_list == expected_calls
3636

37-
def it_can_get_a_style_by_id(self, get_by_id_fixture):
38-
styles, key, expected_element = get_by_id_fixture
37+
def it_can_get_a_style_by_id(self, getitem_id_fixture):
38+
styles, key, expected_element = getitem_id_fixture
3939
style = styles[key]
4040
assert style._element is expected_element
4141

42-
def it_can_get_a_style_by_name(self, get_by_name_fixture):
43-
styles, key, expected_element = get_by_name_fixture
42+
def it_can_get_a_style_by_name(self, getitem_name_fixture):
43+
styles, key, expected_element = getitem_name_fixture
4444
style = styles[key]
4545
assert style._element is expected_element
4646

@@ -49,14 +49,36 @@ def it_raises_on_style_not_found(self, get_raises_fixture):
4949
with pytest.raises(KeyError):
5050
styles[key]
5151

52+
def it_can_get_a_style_of_type_by_id(self, get_by_id_fixture):
53+
styles, style_id, style_type = get_by_id_fixture[:3]
54+
default_calls, _get_by_id_calls, style_ = get_by_id_fixture[3:]
55+
style = styles.get_by_id(style_id, style_type)
56+
assert styles.default.call_args_list == default_calls
57+
assert styles._get_by_id.call_args_list == _get_by_id_calls
58+
assert style is style_
59+
5260
# fixture --------------------------------------------------------
5361

62+
@pytest.fixture(params=[None, 'Foo'])
63+
def get_by_id_fixture(self, request, default_, _get_by_id_, style_):
64+
style_id, style_type = request.param, 1
65+
styles = Styles(None)
66+
default_calls = [call(style_type)] if style_id is None else []
67+
_get_by_id_calls = (
68+
[] if style_id is None else [call(style_id, style_type)]
69+
)
70+
default_.return_value = _get_by_id_.return_value = style_
71+
return (
72+
styles, style_id, style_type, default_calls, _get_by_id_calls,
73+
style_
74+
)
75+
5476
@pytest.fixture(params=[
5577
('w:styles/(w:style{%s,w:styleId=Foobar},w:style,w:style)', 0),
5678
('w:styles/(w:style,w:style{%s,w:styleId=Foobar},w:style)', 1),
5779
('w:styles/(w:style,w:style,w:style{%s,w:styleId=Foobar})', 2),
5880
])
59-
def get_by_id_fixture(self, request):
81+
def getitem_id_fixture(self, request):
6082
styles_cxml_tmpl, style_idx = request.param
6183
styles_cxml = styles_cxml_tmpl % 'w:type=paragraph'
6284
styles = Styles(element(styles_cxml))
@@ -68,7 +90,7 @@ def get_by_id_fixture(self, request):
6890
('w:styles/(w:style,w:style%s/w:name{w:val=foo})', 'foo', 1),
6991
('w:styles/w:style%s/w:name{w:val=heading 1}', 'Heading 1', 0),
7092
])
71-
def get_by_name_fixture(self, request):
93+
def getitem_name_fixture(self, request):
7294
styles_cxml_tmpl, key, style_idx = request.param
7395
styles_cxml = styles_cxml_tmpl % '{w:type=character}'
7496
styles = Styles(element(styles_cxml))
@@ -111,6 +133,14 @@ def len_fixture(self, request):
111133

112134
# fixture components ---------------------------------------------
113135

136+
@pytest.fixture
137+
def default_(self, request):
138+
return method_mock(request, Styles, 'default')
139+
140+
@pytest.fixture
141+
def _get_by_id_(self, request):
142+
return method_mock(request, Styles, '_get_by_id')
143+
114144
@pytest.fixture
115145
def style_(self, request):
116146
return instance_mock(request, BaseStyle)

0 commit comments

Comments
 (0)