Skip to content

Commit 004ac14

Browse files
committed
hdr: add BaseStoryPart.get_style_id()
1 parent faccb45 commit 004ac14

File tree

4 files changed

+100
-44
lines changed

4 files changed

+100
-44
lines changed

docx/parts/hdrftr.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@
77
import os
88

99
from docx.opc.constants import CONTENT_TYPE as CT
10-
from docx.opc.part import XmlPart
1110
from docx.oxml import parse_xml
11+
from docx.parts.story import BaseStoryPart
1212

1313

14-
class FooterPart(XmlPart):
14+
class FooterPart(BaseStoryPart):
1515
"""Definition of a section footer."""
1616

1717
@classmethod
@@ -33,7 +33,7 @@ def _default_footer_xml(cls):
3333
return xml_bytes
3434

3535

36-
class HeaderPart(XmlPart):
36+
class HeaderPart(BaseStoryPart):
3737
"""Definition of a section header."""
3838

3939
@classmethod

docx/parts/story.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# encoding: utf-8
2+
3+
"""|BaseStoryPart| and related objects"""
4+
5+
from __future__ import absolute_import, division, print_function, unicode_literals
6+
7+
from docx.opc.part import XmlPart
8+
from docx.shared import lazyproperty
9+
10+
11+
class BaseStoryPart(XmlPart):
12+
"""Base class for story parts.
13+
14+
A story part is one that can contain textual content, such as the document-part and
15+
header or footer parts. These all share content behaviors like `.paragraphs`,
16+
`.add_paragraph()`, `.add_table()` etc.
17+
"""
18+
19+
def get_style_id(self, style_or_name, style_type):
20+
"""Return str style_id for *style_or_name* of *style_type*.
21+
22+
Returns |None| if the style resolves to the default style for *style_type* or if
23+
*style_or_name* is itself |None|. Raises if *style_or_name* is a style of the
24+
wrong type or names a style not present in the document.
25+
"""
26+
return self._document_part.get_style_id(style_or_name, style_type)
27+
28+
@lazyproperty
29+
def _document_part(self):
30+
"""|DocumentPart| object for this package."""
31+
raise NotImplementedError

tests/parts/test_document.py

Lines changed: 22 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import pytest
88

9+
from docx.enum.style import WD_STYLE_TYPE
910
from docx.image.image import Image
1011
from docx.opc.constants import RELATIONSHIP_TYPE as RT
1112
from docx.opc.coreprops import CoreProperties
@@ -19,7 +20,6 @@
1920
from docx.settings import Settings
2021
from docx.styles.style import BaseStyle
2122
from docx.styles.styles import Styles
22-
from docx.text.paragraph import Paragraph
2323

2424
from ..oxml.parts.unitdata.document import a_body, a_document
2525
from ..oxml.unitdata.text import a_p
@@ -137,7 +137,7 @@ def it_provides_access_to_the_numbering_part(
137137
part_related_by_.assert_called_once_with(document_part, RT.NUMBERING)
138138
assert numbering_part is numbering_part_
139139

140-
def it_creates_numbering_part_if_not_present(
140+
def and_it_creates_a_numbering_part_if_not_present(
141141
self, part_related_by_, relate_to_, NumberingPart_, numbering_part_
142142
):
143143
part_related_by_.side_effect = KeyError
@@ -169,24 +169,25 @@ def it_can_create_a_new_pic_inline(self, image_, get_or_add_image_, next_id_prop
169169
image_.scaled_dimensions.assert_called_once_with(width, height)
170170
assert inline.xml == expected_xml
171171

172-
def it_can_get_a_style_by_id(self, get_style_fixture):
173-
document_part, style_id, style_type, style_ = get_style_fixture
174-
style = document_part.get_style(style_id, style_type)
175-
document_part.styles.get_by_id.assert_called_once_with(
176-
style_id, style_type
177-
)
172+
def it_can_get_a_style_by_id(self, styles_prop_, styles_, style_):
173+
styles_prop_.return_value = styles_
174+
styles_.get_by_id.return_value = style_
175+
document_part = DocumentPart(None, None, None, None)
176+
177+
style = document_part.get_style("BodyText", WD_STYLE_TYPE.PARAGRAPH)
178+
179+
styles_.get_by_id.assert_called_once_with("BodyText", WD_STYLE_TYPE.PARAGRAPH)
178180
assert style is style_
179181

180-
def it_can_get_the_id_of_a_style(self, get_style_id_fixture):
181-
document_part, style_or_name, style_type, style_id_ = (
182-
get_style_id_fixture
183-
)
184-
style_id = document_part.get_style_id(style_or_name, style_type)
182+
def it_can_get_the_id_of_a_style(self, style_, styles_prop_, styles_):
183+
styles_prop_.return_value = styles_
184+
styles_.get_style_id.return_value = "BodyCharacter"
185+
document_part = DocumentPart(None, None, None, None)
185186

186-
document_part.styles.get_style_id.assert_called_once_with(
187-
style_or_name, style_type
188-
)
189-
assert style_id is style_id_
187+
style_id = document_part.get_style_id(style_, WD_STYLE_TYPE.CHARACTER)
188+
189+
styles_.get_style_id.assert_called_once_with(style_, WD_STYLE_TYPE.CHARACTER)
190+
assert style_id == "BodyCharacter"
190191

191192
def it_provides_access_to_its_settings_part_to_help(
192193
self, part_related_by_, settings_part_
@@ -199,7 +200,7 @@ def it_provides_access_to_its_settings_part_to_help(
199200
part_related_by_.assert_called_once_with(document_part, RT.SETTINGS)
200201
assert settings_part is settings_part_
201202

202-
def it_creates_default_settings_part_if_not_present_to_help(
203+
def and_it_creates_a_default_settings_part_if_not_present(
203204
self, package_, part_related_by_, SettingsPart_, settings_part_, relate_to_
204205
):
205206
part_related_by_.side_effect = KeyError
@@ -223,7 +224,7 @@ def it_provides_access_to_its_styles_part_to_help(
223224
part_related_by_.assert_called_once_with(document_part, RT.STYLES)
224225
assert styles_part is styles_part_
225226

226-
def it_creates_default_styles_part_if_not_present_to_help(
227+
def and_it_creates_a_default_styles_part_if_not_present(
227228
self, package_, part_related_by_, StylesPart_, styles_part_, relate_to_
228229
):
229230
part_related_by_.side_effect = KeyError
@@ -244,20 +245,6 @@ def core_props_fixture(self, package_, core_properties_):
244245
package_.core_properties = core_properties_
245246
return document_part, core_properties_
246247

247-
@pytest.fixture
248-
def get_style_fixture(self, styles_prop_, style_):
249-
document_part = DocumentPart(None, None, None, None)
250-
style_id, style_type = 'Foobar', 1
251-
styles_prop_.return_value.get_by_id.return_value = style_
252-
return document_part, style_id, style_type, style_
253-
254-
@pytest.fixture
255-
def get_style_id_fixture(self, styles_prop_):
256-
document_part = DocumentPart(None, None, None, None)
257-
style_or_name, style_type, style_id_ = 'Foo Bar', 1, 'FooBar'
258-
styles_prop_.return_value.get_style_id.return_value = style_id_
259-
return document_part, style_or_name, style_type, style_id_
260-
261248
@pytest.fixture
262249
def inline_shapes_fixture(self, request, InlineShapes_):
263250
document_elm = (
@@ -364,10 +351,6 @@ def NumberingPart_(self, request):
364351
def numbering_part_(self, request):
365352
return instance_mock(request, NumberingPart)
366353

367-
@pytest.fixture
368-
def p_(self, request):
369-
return instance_mock(request, Paragraph)
370-
371354
@pytest.fixture
372355
def package_(self, request):
373356
return instance_mock(request, Package)
@@ -421,10 +404,8 @@ def styles_part_(self, request):
421404
return instance_mock(request, StylesPart)
422405

423406
@pytest.fixture
424-
def styles_prop_(self, request, styles_):
425-
return property_mock(
426-
request, DocumentPart, 'styles', return_value=styles_
427-
)
407+
def styles_prop_(self, request):
408+
return property_mock(request, DocumentPart, 'styles')
428409

429410
@pytest.fixture
430411
def _styles_part_prop_(self, request):

tests/parts/test_story.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# encoding: utf-8
2+
3+
"""Unit test suite for the docx.parts.story module"""
4+
5+
from __future__ import absolute_import, division, print_function, unicode_literals
6+
7+
import pytest
8+
9+
from docx.enum.style import WD_STYLE_TYPE
10+
from docx.parts.document import DocumentPart
11+
from docx.parts.story import BaseStoryPart
12+
from docx.styles.style import BaseStyle
13+
14+
from ..unitutil.mock import instance_mock, property_mock
15+
16+
17+
class DescribeBaseStoryPart(object):
18+
19+
def it_can_get_a_style_id_by_style_or_name_and_type(
20+
self, _document_part_prop_, document_part_, style_
21+
):
22+
style_type = WD_STYLE_TYPE.PARAGRAPH
23+
_document_part_prop_.return_value = document_part_
24+
document_part_.get_style_id.return_value = "BodyText"
25+
story_part = BaseStoryPart(None, None, None, None)
26+
27+
style_id = story_part.get_style_id(style_, style_type)
28+
29+
document_part_.get_style_id.assert_called_once_with(style_, style_type)
30+
assert style_id == "BodyText"
31+
32+
# fixture components ---------------------------------------------
33+
34+
@pytest.fixture
35+
def document_part_(self, request):
36+
return instance_mock(request, DocumentPart)
37+
38+
@pytest.fixture
39+
def _document_part_prop_(self, request):
40+
return property_mock(request, BaseStoryPart, "_document_part")
41+
42+
@pytest.fixture
43+
def style_(self, request):
44+
return instance_mock(request, BaseStyle)

0 commit comments

Comments
 (0)