Skip to content

Commit 7fc1c2c

Browse files
author
Steve Canny
committed
style: add Styles.__getitem__()
1 parent 11f5f83 commit 7fc1c2c

4 files changed

Lines changed: 73 additions & 5 deletions

File tree

docx/oxml/parts/styles.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,24 @@ class CT_Styles(BaseOxmlElement):
3333
"""
3434
style = ZeroOrMore('w:style', successors=())
3535

36-
def style_having_styleId(self, styleId):
36+
def get_by_id(self, styleId):
3737
"""
3838
Return the ``<w:style>`` child element having ``styleId`` attribute
39-
matching *styleId*.
39+
matching *styleId*, or |None| if not found.
4040
"""
41-
xpath = './w:style[@w:styleId="%s"]' % styleId
41+
xpath = 'w:style[@w:styleId="%s"]' % styleId
4242
try:
4343
return self.xpath(xpath)[0]
4444
except IndexError:
45-
raise KeyError('no <w:style> element with styleId %s' % styleId)
45+
return None
46+
47+
def get_by_name(self, name):
48+
"""
49+
Return the ``<w:style>`` child element having ``<w:name>`` child
50+
element with value *name*, or |None| if not found.
51+
"""
52+
xpath = 'w:style[w:name/@w:val="%s"]' % name
53+
try:
54+
return self.xpath(xpath)[0]
55+
except IndexError:
56+
return None

docx/styles/styles.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,16 @@ class Styles(ElementProxy):
2121

2222
__slots__ = ()
2323

24+
def __getitem__(self, key):
25+
"""
26+
Enables dictionary-style access by style id or UI name.
27+
"""
28+
for get in (self._element.get_by_id, self._element.get_by_name):
29+
style_elm = get(key)
30+
if style_elm is not None:
31+
return StyleFactory(style_elm)
32+
raise KeyError("no style with id or name '%s'" % key)
33+
2434
def __iter__(self):
2535
return (StyleFactory(style) for style in self._element.style_lst)
2636

features/doc-styles.feature

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ Feature: Access document styles
1515
| no styles part | 4 |
1616

1717

18-
@wip
1918
Scenario: Access style in style collection
2019
Given a document having a styles part
2120
Then I can iterate over its styles

tests/styles/test_styles.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,56 @@ 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
39+
style = styles[key]
40+
assert style._element is expected_element
41+
42+
def it_can_get_a_style_by_name(self, get_by_name_fixture):
43+
styles, key, expected_element = get_by_name_fixture
44+
style = styles[key]
45+
assert style._element is expected_element
46+
47+
def it_raises_on_style_not_found(self, get_raises_fixture):
48+
styles, key = get_raises_fixture
49+
with pytest.raises(KeyError):
50+
styles[key]
51+
3752
# fixture --------------------------------------------------------
3853

54+
@pytest.fixture(params=[
55+
('w:styles/(w:style{%s,w:styleId=Foobar},w:style,w:style)', 0),
56+
('w:styles/(w:style,w:style{%s,w:styleId=Foobar},w:style)', 1),
57+
('w:styles/(w:style,w:style,w:style{%s,w:styleId=Foobar})', 2),
58+
])
59+
def get_by_id_fixture(self, request):
60+
styles_cxml_tmpl, style_idx = request.param
61+
styles_cxml = styles_cxml_tmpl % 'w:type=paragraph'
62+
styles = Styles(element(styles_cxml))
63+
expected_element = styles._element[style_idx]
64+
return styles, 'Foobar', expected_element
65+
66+
@pytest.fixture(params=[
67+
('w:styles/(w:style%s/w:name{w:val=foo},w:style,w:style)', 0),
68+
('w:styles/(w:style,w:style%s/w:name{w:val=foo},w:style)', 1),
69+
('w:styles/(w:style,w:style,w:style%s/w:name{w:val=foo})', 2),
70+
])
71+
def get_by_name_fixture(self, request):
72+
styles_cxml_tmpl, style_idx = request.param
73+
styles_cxml = styles_cxml_tmpl % '{w:type=character}'
74+
styles = Styles(element(styles_cxml))
75+
expected_element = styles._element[style_idx]
76+
return styles, 'foo', expected_element
77+
78+
@pytest.fixture(params=[
79+
('w:styles/(w:style,w:style/w:name{w:val=foo},w:style)'),
80+
('w:styles/(w:style{w:styleId=foo},w:style,w:style)'),
81+
])
82+
def get_raises_fixture(self, request):
83+
styles_cxml = request.param
84+
styles = Styles(element(styles_cxml))
85+
return styles, 'bar'
86+
3987
@pytest.fixture(params=[
4088
('w:styles', 0),
4189
('w:styles/w:style', 1),

0 commit comments

Comments
 (0)