Skip to content

Commit adf878e

Browse files
author
Steve Canny
committed
style: add DocumentPart._styles_part
* resequence Part.package property
1 parent 5b25f14 commit adf878e

File tree

4 files changed

+62
-8
lines changed

4 files changed

+62
-8
lines changed

docx/opc/part.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,13 @@ def load_rel(self, reltype, target, rId, is_external=False):
8989
"""
9090
return self.rels.add_relationship(reltype, target, rId, is_external)
9191

92+
@property
93+
def package(self):
94+
"""
95+
|OpcPackage| instance this part belongs to.
96+
"""
97+
return self._package
98+
9299
@property
93100
def partname(self):
94101
"""
@@ -104,13 +111,6 @@ def partname(self, partname):
104111
raise TypeError(tmpl % type(partname).__name__)
105112
self._partname = partname
106113

107-
@property
108-
def package(self):
109-
"""
110-
|OpcPackage| instance this part belongs to.
111-
"""
112-
return self._package
113-
114114
def part_related_by(self, reltype):
115115
"""
116116
Return part to which this part has a relationship of *reltype*.

docx/parts/document.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from ..section import Section
1818
from ..shape import InlineShape
1919
from ..shared import lazyproperty, Parented
20+
from .styles import StylesPart
2021

2122

2223
class DocumentPart(XmlPart):
@@ -125,7 +126,12 @@ def _styles_part(self):
125126
Instance of |StylesPart| for this document. Creates an empty styles
126127
part if one is not present.
127128
"""
128-
raise NotImplementedError
129+
try:
130+
return self.part_related_by(RT.STYLES)
131+
except KeyError:
132+
styles_part = StylesPart.default(self.package)
133+
self.relate_to(styles_part, RT.STYLES)
134+
return styles_part
129135

130136

131137
class _Body(BlockItemContainer):

docx/parts/styles.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,14 @@ class StylesPart(XmlPart):
1717
Proxy for the styles.xml part containing style definitions for a document
1818
or glossary.
1919
"""
20+
@classmethod
21+
def default(cls, package):
22+
"""
23+
Return a newly created styles part, containing a default set of
24+
elements.
25+
"""
26+
raise NotImplementedError
27+
2028
@classmethod
2129
def new(cls):
2230
"""

tests/parts/test_document.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,23 @@ def it_knows_the_next_available_xml_id(self, next_id_fixture):
105105
document, expected_id = next_id_fixture
106106
assert document.next_id == expected_id
107107

108+
def it_provides_access_to_its_styles_part_to_help(
109+
self, styles_part_get_fixture):
110+
document_part, styles_part_ = styles_part_get_fixture
111+
styles_part = document_part._styles_part
112+
document_part.part_related_by.assert_called_once_with(RT.STYLES)
113+
assert styles_part is styles_part_
114+
115+
def it_creates_default_styles_part_if_not_present_to_help(
116+
self, styles_part_create_fixture):
117+
document_part, StylesPart_, styles_part_ = styles_part_create_fixture
118+
styles_part = document_part._styles_part
119+
StylesPart_.default.assert_called_once_with(document_part.package)
120+
document_part.relate_to.assert_called_once_with(
121+
styles_part_, RT.STYLES
122+
)
123+
assert styles_part is styles_part_
124+
108125
# fixtures -------------------------------------------------------
109126

110127
@pytest.fixture
@@ -181,6 +198,21 @@ def styles_fixture(self, _styles_part_prop_, styles_part_, styles_):
181198
styles_part_.styles = styles_
182199
return document_part, styles_
183200

201+
@pytest.fixture
202+
def styles_part_create_fixture(
203+
self, package_, part_related_by_, StylesPart_, styles_part_,
204+
relate_to_):
205+
document_part = DocumentPart(None, None, None, package_)
206+
part_related_by_.side_effect = KeyError
207+
StylesPart_.default.return_value = styles_part_
208+
return document_part, StylesPart_, styles_part_
209+
210+
@pytest.fixture
211+
def styles_part_get_fixture(self, part_related_by_, styles_part_):
212+
document_part = DocumentPart(None, None, None, None)
213+
part_related_by_.return_value = styles_part_
214+
return document_part, styles_part_
215+
184216
@pytest.fixture
185217
def tables_fixture(self, document_part_body_, body_, tables_):
186218
document_part = DocumentPart(None, None, None, None)
@@ -257,6 +289,10 @@ def package_(self, request):
257289
def paragraphs_(self, request):
258290
return instance_mock(request, list)
259291

292+
@pytest.fixture
293+
def part_related_by_(self, request):
294+
return method_mock(request, DocumentPart, 'part_related_by')
295+
260296
@pytest.fixture
261297
def relate_to_(self, request, rId_):
262298
relate_to_ = method_mock(request, DocumentPart, 'relate_to')
@@ -293,6 +329,10 @@ def start_type_(self, request):
293329
def styles_(self, request):
294330
return instance_mock(request, Styles)
295331

332+
@pytest.fixture
333+
def StylesPart_(self, request):
334+
return class_mock(request, 'docx.parts.document.StylesPart')
335+
296336
@pytest.fixture
297337
def styles_part_(self, request):
298338
return instance_mock(request, StylesPart)

0 commit comments

Comments
 (0)