Skip to content

Commit 2e15855

Browse files
author
Steve Canny
committed
opc: refactor _ContentTypesItem interface
* change xml_for() to from_parts() constructor and return instance instead of XML stream * bring .blob property into _ContentTypesItem to return XML stream
1 parent c6a48fb commit 2e15855

File tree

2 files changed

+45
-17
lines changed

2 files changed

+45
-17
lines changed

docx/opc/pkgwriter.py

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ def _write_content_types_stream(phys_writer, parts):
4141
Write ``[Content_Types].xml`` part to the physical package with an
4242
appropriate content type lookup target for each part in *parts*.
4343
"""
44-
phys_writer.write(CONTENT_TYPES_URI, _ContentTypesItem.xml_for(parts))
44+
cti = _ContentTypesItem.from_parts(parts)
45+
phys_writer.write(CONTENT_TYPES_URI, cti.blob)
4546

4647
@staticmethod
4748
def _write_parts(phys_writer, parts):
@@ -74,8 +75,16 @@ def __init__(self):
7475
self._defaults = CaseInsensitiveDict()
7576
self._overrides = dict()
7677

78+
@property
79+
def blob(self):
80+
"""
81+
Return XML form of this content types item, suitable for storage as
82+
``[Content_Types].xml`` in an OPC package.
83+
"""
84+
return serialize_part_xml(self._element)
85+
7786
@classmethod
78-
def xml_for(cls, parts):
87+
def from_parts(cls, parts):
7988
"""
8089
Return content types XML mapping each part in *parts* to the
8190
appropriate content type and suitable for storage as
@@ -86,7 +95,7 @@ def xml_for(cls, parts):
8695
cti._defaults['.xml'] = CT.XML
8796
for part in parts:
8897
cti._add_content_type(part.partname, part.content_type)
89-
return cti._xml()
98+
return cti
9099

91100
def _add_content_type(self, partname, content_type):
92101
"""
@@ -99,7 +108,8 @@ def _add_content_type(self, partname, content_type):
99108
else:
100109
self._overrides[partname] = content_type
101110

102-
def _xml(self):
111+
@property
112+
def _element(self):
103113
"""
104114
Return XML form of this content types item, suitable for storage as
105115
``[Content_Types].xml`` in an OPC package. Although the sequence of
@@ -112,4 +122,4 @@ def _xml(self):
112122
_types_elm.add_default(ext, self._defaults[ext])
113123
for partname in sorted(self._overrides.keys()):
114124
_types_elm.add_override(partname, self._overrides[partname])
115-
return serialize_part_xml(_types_elm)
125+
return _types_elm

tests/opc/test_pkgwriter.py

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,13 @@
99
from mock import call, MagicMock, Mock, patch
1010

1111
from docx.opc.constants import CONTENT_TYPE as CT
12-
from docx.opc.oxml import oxml_fromstring
1312
from docx.opc.package import Part
1413
from docx.opc.packuri import PackURI
1514
from docx.opc.phys_pkg import _ZipPkgWriter
1615
from docx.opc.pkgwriter import _ContentTypesItem, PackageWriter
1716

1817
from .unitdata.types import a_Default, a_Types, an_Override
19-
from ..unitutil import instance_mock, method_mock
18+
from ..unitutil import class_mock, instance_mock, method_mock
2019

2120

2221
class DescribePackageWriter(object):
@@ -40,11 +39,13 @@ def it_can_write_a_package(self, PhysPkgWriter_, _write_methods):
4039
phys_writer.close.assert_called_once_with()
4140

4241
def it_can_write_a_content_types_stream(self, write_cti_fixture):
43-
phys_pkg_writer_, parts_, xml_for_ = write_cti_fixture
42+
_ContentTypesItem_, parts_, phys_pkg_writer_, blob_ = (
43+
write_cti_fixture
44+
)
4445
PackageWriter._write_content_types_stream(phys_pkg_writer_, parts_)
45-
xml_for_.assert_called_once_with(parts_)
46+
_ContentTypesItem_.from_parts.assert_called_once_with(parts_)
4647
phys_pkg_writer_.write.assert_called_once_with(
47-
'/[Content_Types].xml', xml_for_.return_value
48+
'/[Content_Types].xml', blob_
4849
)
4950

5051
def it_can_write_a_pkg_rels_item(self):
@@ -76,6 +77,22 @@ def it_can_write_a_list_of_parts(self):
7677

7778
# fixtures ---------------------------------------------
7879

80+
@pytest.fixture
81+
def blob_(self, request):
82+
return instance_mock(request, str)
83+
84+
@pytest.fixture
85+
def cti_(self, request, blob_):
86+
return instance_mock(request, _ContentTypesItem, blob=blob_)
87+
88+
@pytest.fixture
89+
def _ContentTypesItem_(self, request, cti_):
90+
_ContentTypesItem_ = class_mock(
91+
request, 'docx.opc.pkgwriter._ContentTypesItem'
92+
)
93+
_ContentTypesItem_.from_parts.return_value = cti_
94+
return _ContentTypesItem_
95+
7996
@pytest.fixture
8097
def parts_(self, request):
8198
return instance_mock(request, list)
@@ -91,8 +108,9 @@ def phys_pkg_writer_(self, request):
91108
return instance_mock(request, _ZipPkgWriter)
92109

93110
@pytest.fixture
94-
def write_cti_fixture(self, phys_pkg_writer_, parts_, xml_for_):
95-
return phys_pkg_writer_, parts_, xml_for_
111+
def write_cti_fixture(
112+
self, _ContentTypesItem_, parts_, phys_pkg_writer_, blob_):
113+
return _ContentTypesItem_, parts_, phys_pkg_writer_, blob_
96114

97115
@pytest.fixture
98116
def _write_methods(self, request):
@@ -120,10 +138,9 @@ def xml_for_(self, request):
120138

121139
class Describe_ContentTypesItem(object):
122140

123-
def it_can_compose_content_types_xml(self, xml_for_fixture):
124-
parts, expected_xml = xml_for_fixture
125-
types_xml = _ContentTypesItem.xml_for(parts)
126-
types_elm = oxml_fromstring(types_xml)
141+
def it_can_compose_content_types_element(self, xml_for_fixture):
142+
cti, expected_xml = xml_for_fixture
143+
types_elm = cti._element
127144
assert types_elm.xml == expected_xml
128145

129146
# fixtures ---------------------------------------------
@@ -147,6 +164,7 @@ def _mock_part(self, request, name, partname_str, content_type):
147164
def xml_for_fixture(self, request):
148165
elm_type, partname_str, content_type = request.param
149166
part_ = self._mock_part(request, 'part_', partname_str, content_type)
167+
cti = _ContentTypesItem.from_parts([part_])
150168
# expected_xml -----------------
151169
types_bldr = a_Types().with_nsdecls()
152170
ext = partname_str.split('.')[-1].lower()
@@ -171,4 +189,4 @@ def xml_for_fixture(self, request):
171189
types_bldr.with_child(override_bldr)
172190

173191
expected_xml = types_bldr.xml()
174-
return [part_], expected_xml
192+
return cti, expected_xml

0 commit comments

Comments
 (0)