Skip to content

Commit 11f5f83

Browse files
author
Steve Canny
committed
style: add StyleFactory()
* refactor xmlchemy declarations in CT_Style
1 parent d76d47c commit 11f5f83

4 files changed

Lines changed: 150 additions & 8 deletions

File tree

docx/oxml/parts/styles.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,26 @@
44
Custom element classes related to the styles part
55
"""
66

7-
from ..xmlchemy import BaseOxmlElement, ZeroOrMore, ZeroOrOne
7+
from ...enum.style import WD_STYLE_TYPE
8+
from ..xmlchemy import (
9+
BaseOxmlElement, OptionalAttribute, ZeroOrMore, ZeroOrOne
10+
)
811

912

1013
class CT_Style(BaseOxmlElement):
1114
"""
1215
A ``<w:style>`` element, representing a style definition
1316
"""
14-
pPr = ZeroOrOne('w:pPr', successors=(
15-
'w:rPr', 'w:tblPr', 'w:trPr', 'w:tcPr', 'w:tblStylePr'
16-
))
17+
_tag_seq = (
18+
'w:name', 'w:aliases', 'w:basedOn', 'w:next', 'w:link',
19+
'w:autoRedefine', 'w:hidden', 'w:uiPriority', 'w:semiHidden',
20+
'w:unhideWhenUsed', 'w:qFormat', 'w:locked', 'w:personal',
21+
'w:personalCompose', 'w:personalReply', 'w:rsid', 'w:pPr', 'w:rPr',
22+
'w:tblPr', 'w:trPr', 'w:tcPr', 'w:tblStylePr'
23+
)
24+
pPr = ZeroOrOne('w:pPr', successors=_tag_seq[17:])
25+
type = OptionalAttribute('w:type', WD_STYLE_TYPE)
26+
del _tag_seq
1727

1828

1929
class CT_Styles(BaseOxmlElement):

docx/styles/style.py

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,23 @@
88
absolute_import, division, print_function, unicode_literals
99
)
1010

11+
from ..enum.style import WD_STYLE_TYPE
1112
from ..shared import ElementProxy
1213

1314

1415
def StyleFactory(style_elm):
1516
"""
16-
Return a style object of the appropriate |_BaseStyle| subclass, according
17-
to it style type.
17+
Return a style object of the appropriate |BaseStyle| subclass, according
18+
to the type of *style_elm*.
1819
"""
19-
raise NotImplementedError
20+
style_cls = {
21+
WD_STYLE_TYPE.PARAGRAPH: _ParagraphStyle,
22+
WD_STYLE_TYPE.CHARACTER: _CharacterStyle,
23+
WD_STYLE_TYPE.TABLE: _TableStyle,
24+
WD_STYLE_TYPE.LIST: _NumberingStyle
25+
}[style_elm.type]
26+
27+
return style_cls(style_elm)
2028

2129

2230
class BaseStyle(ElementProxy):
@@ -26,3 +34,35 @@ class BaseStyle(ElementProxy):
2634
"""
2735

2836
__slots__ = ()
37+
38+
39+
class _CharacterStyle(BaseStyle):
40+
"""
41+
A character style.
42+
"""
43+
44+
__slots__ = ()
45+
46+
47+
class _ParagraphStyle(_CharacterStyle):
48+
"""
49+
A paragraph style.
50+
"""
51+
52+
__slots__ = ()
53+
54+
55+
class _TableStyle(_ParagraphStyle):
56+
"""
57+
A table style.
58+
"""
59+
60+
__slots__ = ()
61+
62+
63+
class _NumberingStyle(BaseStyle):
64+
"""
65+
A numbering style.
66+
"""
67+
68+
__slots__ = ()

tests/styles/test_style.py

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
# encoding: utf-8
2+
3+
"""
4+
Test suite for the docx.styles.style module
5+
"""
6+
7+
from __future__ import (
8+
absolute_import, division, print_function, unicode_literals
9+
)
10+
11+
import pytest
12+
13+
from docx.styles.style import (
14+
_CharacterStyle, _ParagraphStyle, _NumberingStyle, StyleFactory,
15+
_TableStyle
16+
)
17+
18+
from ..unitutil.cxml import element
19+
from ..unitutil.mock import class_mock, instance_mock
20+
21+
22+
class DescribeStyleFactory(object):
23+
24+
def it_constructs_the_right_type_of_style(self, factory_fixture):
25+
style_elm, StyleCls_, style_ = factory_fixture
26+
style = StyleFactory(style_elm)
27+
StyleCls_.assert_called_once_with(style_elm)
28+
assert style is style_
29+
30+
# fixtures -------------------------------------------------------
31+
32+
@pytest.fixture(params=['paragraph', 'character', 'table', 'numbering'])
33+
def factory_fixture(
34+
self, request, paragraph_style_, _ParagraphStyle_,
35+
character_style_, _CharacterStyle_, table_style_, _TableStyle_,
36+
numbering_style_, _NumberingStyle_):
37+
type_attr_val = request.param
38+
StyleCls_, style_mock = {
39+
'paragraph': (_ParagraphStyle_, paragraph_style_),
40+
'character': (_CharacterStyle_, character_style_),
41+
'table': (_TableStyle_, table_style_),
42+
'numbering': (_NumberingStyle_, numbering_style_),
43+
}[request.param]
44+
style_cxml = 'w:style{w:type=%s}' % type_attr_val
45+
style_elm = element(style_cxml)
46+
return style_elm, StyleCls_, style_mock
47+
48+
# fixture components -----------------------------------
49+
50+
@pytest.fixture
51+
def _ParagraphStyle_(self, request, paragraph_style_):
52+
return class_mock(
53+
request, 'docx.styles.style._ParagraphStyle',
54+
return_value=paragraph_style_
55+
)
56+
57+
@pytest.fixture
58+
def paragraph_style_(self, request):
59+
return instance_mock(request, _ParagraphStyle)
60+
61+
@pytest.fixture
62+
def _CharacterStyle_(self, request, character_style_):
63+
return class_mock(
64+
request, 'docx.styles.style._CharacterStyle',
65+
return_value=character_style_
66+
)
67+
68+
@pytest.fixture
69+
def character_style_(self, request):
70+
return instance_mock(request, _CharacterStyle)
71+
72+
@pytest.fixture
73+
def _TableStyle_(self, request, table_style_):
74+
return class_mock(
75+
request, 'docx.styles.style._TableStyle',
76+
return_value=table_style_
77+
)
78+
79+
@pytest.fixture
80+
def table_style_(self, request):
81+
return instance_mock(request, _TableStyle)
82+
83+
@pytest.fixture
84+
def _NumberingStyle_(self, request, numbering_style_):
85+
return class_mock(
86+
request, 'docx.styles.style._NumberingStyle',
87+
return_value=numbering_style_
88+
)
89+
90+
@pytest.fixture
91+
def numbering_style_(self, request):
92+
return instance_mock(request, _NumberingStyle)

tests/styles/test_styles.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# encoding: utf-8
22

33
"""
4-
Test suite for the docx.styles module
4+
Test suite for the docx.styles.styles module
55
"""
66

77
from __future__ import (

0 commit comments

Comments
 (0)