Repository URL to install this package:
|
Version:
0.8.9 ▾
|
# encoding: utf-8
"""Unit test suite for docx.opc.package module"""
from __future__ import absolute_import, division, print_function, unicode_literals
import pytest
from docx.opc.constants import RELATIONSHIP_TYPE as RT
from docx.opc.coreprops import CoreProperties
from docx.opc.package import OpcPackage, Unmarshaller
from docx.opc.packuri import PACKAGE_URI, PackURI
from docx.opc.part import Part
from docx.opc.parts.coreprops import CorePropertiesPart
from docx.opc.pkgreader import PackageReader
from docx.opc.rel import _Relationship, Relationships
from ..unitutil.mock import (
call,
class_mock,
instance_mock,
loose_mock,
method_mock,
Mock,
patch,
PropertyMock,
property_mock,
)
class DescribeOpcPackage(object):
def it_can_open_a_pkg_file(self, PackageReader_, PartFactory_,
Unmarshaller_):
# mockery ----------------------
pkg_file = Mock(name='pkg_file')
pkg_reader = PackageReader_.from_file.return_value
# exercise ---------------------
pkg = OpcPackage.open(pkg_file)
# verify -----------------------
PackageReader_.from_file.assert_called_once_with(pkg_file)
Unmarshaller_.unmarshal.assert_called_once_with(pkg_reader, pkg,
PartFactory_)
assert isinstance(pkg, OpcPackage)
def it_initializes_its_rels_collection_on_first_reference(
self, Relationships_):
pkg = OpcPackage()
rels = pkg.rels
Relationships_.assert_called_once_with(PACKAGE_URI.baseURI)
assert rels == Relationships_.return_value
def it_can_add_a_relationship_to_a_part(self, pkg_with_rels_, rel_attrs_):
reltype, target, rId = rel_attrs_
pkg = pkg_with_rels_
# exercise ---------------------
pkg.load_rel(reltype, target, rId)
# verify -----------------------
pkg._rels.add_relationship.assert_called_once_with(
reltype, target, rId, False
)
def it_can_establish_a_relationship_to_another_part(
self, relate_to_part_fixture_):
pkg, part_, reltype, rId = relate_to_part_fixture_
_rId = pkg.relate_to(part_, reltype)
pkg.rels.get_or_add.assert_called_once_with(reltype, part_)
assert _rId == rId
def it_can_provide_a_list_of_the_parts_it_contains(self):
# mockery ----------------------
parts = [Mock(name='part1'), Mock(name='part2')]
pkg = OpcPackage()
# verify -----------------------
with patch.object(OpcPackage, 'iter_parts', return_value=parts):
assert pkg.parts == [parts[0], parts[1]]
def it_can_iterate_over_parts_by_walking_rels_graph(self):
# +----------+ +--------+
# | pkg_rels |-----> | part_1 |
# +----------+ +--------+
# | | ^
# v v |
# external +--------+
# | part_2 |
# +--------+
part1, part2 = (Mock(name='part1'), Mock(name='part2'))
part1.rels = {
1: Mock(name='rel1', is_external=False, target_part=part2)
}
part2.rels = {
1: Mock(name='rel2', is_external=False, target_part=part1)
}
pkg = OpcPackage()
pkg._rels = {
1: Mock(name='rel3', is_external=False, target_part=part1),
2: Mock(name='rel4', is_external=True),
}
# verify -----------------------
assert part1 in pkg.iter_parts()
assert part2 in pkg.iter_parts()
assert len([p for p in pkg.iter_parts()]) == 2
def it_can_find_the_next_available_vector_partname(
self, next_partname_fixture, iter_parts_, PackURI_, packuri_
):
"""A vector partname is one with a numeric suffix, like header42.xml."""
parts_, expected_value = next_partname_fixture
iter_parts_.return_value = iter(parts_)
PackURI_.return_value = packuri_
package = OpcPackage()
partname = package.next_partname(template="/foo/bar/baz%d.xml")
PackURI_.assert_called_once_with(expected_value)
assert partname is packuri_
def it_can_find_a_part_related_by_reltype(self, related_part_fixture_):
pkg, reltype, related_part_ = related_part_fixture_
related_part = pkg.part_related_by(reltype)
pkg.rels.part_with_reltype.assert_called_once_with(reltype)
assert related_part is related_part_
def it_can_save_to_a_pkg_file(
self, pkg_file_, PackageWriter_, parts, parts_):
pkg = OpcPackage()
pkg.save(pkg_file_)
for part in parts_:
part.before_marshal.assert_called_once_with()
PackageWriter_.write.assert_called_once_with(
pkg_file_, pkg._rels, parts_
)
def it_provides_access_to_the_core_properties(self, core_props_fixture):
opc_package, core_properties_ = core_props_fixture
core_properties = opc_package.core_properties
assert core_properties is core_properties_
def it_provides_access_to_the_core_properties_part_to_help(
self, core_props_part_fixture):
opc_package, core_properties_part_ = core_props_part_fixture
core_properties_part = opc_package._core_properties_part
assert core_properties_part is core_properties_part_
def it_creates_a_default_core_props_part_if_none_present(
self, part_related_by_, CorePropertiesPart_, relate_to_, core_properties_part_
):
part_related_by_.side_effect = KeyError
CorePropertiesPart_.default.return_value = core_properties_part_
opc_package = OpcPackage()
core_properties_part = opc_package._core_properties_part
CorePropertiesPart_.default.assert_called_once_with(opc_package)
relate_to_.assert_called_once_with(
opc_package, core_properties_part_, RT.CORE_PROPERTIES
)
assert core_properties_part is core_properties_part_
# fixtures ---------------------------------------------
@pytest.fixture
def core_props_fixture(
self, _core_properties_part_prop_, core_properties_part_,
core_properties_):
opc_package = OpcPackage()
_core_properties_part_prop_.return_value = core_properties_part_
core_properties_part_.core_properties = core_properties_
return opc_package, core_properties_
@pytest.fixture
def core_props_part_fixture(
self, part_related_by_, core_properties_part_):
opc_package = OpcPackage()
part_related_by_.return_value = core_properties_part_
return opc_package, core_properties_part_
@pytest.fixture(
params=[((), 1), ((1,), 2), ((1, 2), 3), ((2, 3), 1), ((1, 3), 2)]
)
def next_partname_fixture(self, request, iter_parts_):
existing_partname_ns, next_partname_n = request.param
parts_ = [
instance_mock(
request, Part, name="part[%d]" % idx, partname="/foo/bar/baz%d.xml" % n
)
for idx, n in enumerate(existing_partname_ns)
]
expected_value = "/foo/bar/baz%d.xml" % next_partname_n
return parts_, expected_value
@pytest.fixture
def relate_to_part_fixture_(self, request, pkg, rels_, reltype):
rId = 'rId99'
rel_ = instance_mock(request, _Relationship, name='rel_', rId=rId)
rels_.get_or_add.return_value = rel_
pkg._rels = rels_
part_ = instance_mock(request, Part, name='part_')
return pkg, part_, reltype, rId
@pytest.fixture
def related_part_fixture_(self, request, rels_, reltype):
related_part_ = instance_mock(request, Part, name='related_part_')
rels_.part_with_reltype.return_value = related_part_
pkg = OpcPackage()
pkg._rels = rels_
return pkg, reltype, related_part_
# fixture components -----------------------------------
@pytest.fixture
def CorePropertiesPart_(self, request):
return class_mock(request, 'docx.opc.package.CorePropertiesPart')
@pytest.fixture
def core_properties_(self, request):
return instance_mock(request, CoreProperties)
@pytest.fixture
def core_properties_part_(self, request):
return instance_mock(request, CorePropertiesPart)
@pytest.fixture
def _core_properties_part_prop_(self, request):
return property_mock(request, OpcPackage, '_core_properties_part')
@pytest.fixture
def iter_parts_(self, request):
return method_mock(request, OpcPackage, "iter_parts")
@pytest.fixture
def PackageReader_(self, request):
return class_mock(request, 'docx.opc.package.PackageReader')
@pytest.fixture
def PackURI_(self, request):
return class_mock(request, "docx.opc.package.PackURI")
@pytest.fixture
def packuri_(self, request):
return instance_mock(request, PackURI)
@pytest.fixture
def PackageWriter_(self, request):
return class_mock(request, 'docx.opc.package.PackageWriter')
@pytest.fixture
def PartFactory_(self, request):
return class_mock(request, 'docx.opc.package.PartFactory')
@pytest.fixture
def part_related_by_(self, request):
return method_mock(request, OpcPackage, 'part_related_by')
@pytest.fixture
def parts(self, request, parts_):
"""
Return a mock patching property OpcPackage.parts, reversing the
patch after each use.
"""
_patch = patch.object(
OpcPackage, 'parts', new_callable=PropertyMock,
return_value=parts_
)
request.addfinalizer(_patch.stop)
return _patch.start()
@pytest.fixture
def parts_(self, request):
part_ = instance_mock(request, Part, name='part_')
part_2_ = instance_mock(request, Part, name='part_2_')
return [part_, part_2_]
@pytest.fixture
def pkg(self, request):
return OpcPackage()
@pytest.fixture
def pkg_file_(self, request):
return loose_mock(request)
@pytest.fixture
def pkg_with_rels_(self, request, rels_):
pkg = OpcPackage()
pkg._rels = rels_
return pkg
@pytest.fixture
def Relationships_(self, request):
return class_mock(request, 'docx.opc.package.Relationships')
@pytest.fixture
def rel_attrs_(self, request):
reltype = 'http://rel/type'
target_ = instance_mock(request, Part, name='target_')
rId = 'rId99'
return reltype, target_, rId
@pytest.fixture
def relate_to_(self, request):
return method_mock(request, OpcPackage, 'relate_to')
@pytest.fixture
def rels_(self, request):
return instance_mock(request, Relationships)
@pytest.fixture
def reltype(self, request):
return 'http://rel/type'
@pytest.fixture
def Unmarshaller_(self, request):
return class_mock(request, 'docx.opc.package.Unmarshaller')
class DescribeUnmarshaller(object):
def it_can_unmarshal_from_a_pkg_reader(
self,
pkg_reader_,
pkg_,
part_factory_,
_unmarshal_parts_,
_unmarshal_relationships_,
parts_dict_,
):
_unmarshal_parts_.return_value = parts_dict_
Unmarshaller.unmarshal(pkg_reader_, pkg_, part_factory_)
_unmarshal_parts_.assert_called_once_with(pkg_reader_, pkg_, part_factory_)
_unmarshal_relationships_.assert_called_once_with(
pkg_reader_, pkg_, parts_dict_
)
for part in parts_dict_.values():
part.after_unmarshal.assert_called_once_with()
pkg_.after_unmarshal.assert_called_once_with()
def it_can_unmarshal_parts(
self, pkg_reader_, pkg_, part_factory_, parts_dict_, partnames_,
content_types_, reltypes_, blobs_):
# fixture ----------------------
partname_, partname_2_ = partnames_
content_type_, content_type_2_ = content_types_
reltype_, reltype_2_ = reltypes_
blob_, blob_2_ = blobs_
# exercise ---------------------
parts = Unmarshaller._unmarshal_parts(
pkg_reader_, pkg_, part_factory_
)
# verify -----------------------
assert (
part_factory_.call_args_list == [
call(partname_, content_type_, reltype_, blob_, pkg_),
call(partname_2_, content_type_2_, reltype_2_, blob_2_, pkg_)
]
)
assert parts == parts_dict_
def it_can_unmarshal_relationships(self):
# test data --------------------
reltype = 'http://reltype'
# mockery ----------------------
pkg_reader = Mock(name='pkg_reader')
pkg_reader.iter_srels.return_value = (
('/', Mock(name='srel1', rId='rId1', reltype=reltype,
target_partname='partname1', is_external=False)),
('/', Mock(name='srel2', rId='rId2', reltype=reltype,
target_ref='target_ref_1', is_external=True)),
('partname1', Mock(name='srel3', rId='rId3', reltype=reltype,
target_partname='partname2', is_external=False)),
('partname2', Mock(name='srel4', rId='rId4', reltype=reltype,
target_ref='target_ref_2', is_external=True)),
)
pkg = Mock(name='pkg')
parts = {}
for num in range(1, 3):
name = 'part%d' % num
part = Mock(name=name)
parts['partname%d' % num] = part
pkg.attach_mock(part, name)
# exercise ---------------------
Unmarshaller._unmarshal_relationships(pkg_reader, pkg, parts)
# verify -----------------------
expected_pkg_calls = [
call.load_rel(reltype, parts['partname1'], 'rId1', False),
call.load_rel(reltype, 'target_ref_1', 'rId2', True),
call.part1.load_rel(reltype, parts['partname2'], 'rId3', False),
call.part2.load_rel(reltype, 'target_ref_2', 'rId4', True),
]
assert pkg.mock_calls == expected_pkg_calls
# fixtures ---------------------------------------------
@pytest.fixture
def blobs_(self, request):
blob_ = loose_mock(request, spec=str, name='blob_')
blob_2_ = loose_mock(request, spec=str, name='blob_2_')
return blob_, blob_2_
@pytest.fixture
def content_types_(self, request):
content_type_ = loose_mock(request, spec=str, name='content_type_')
content_type_2_ = loose_mock(request, spec=str, name='content_type_2_')
return content_type_, content_type_2_
@pytest.fixture
def part_factory_(self, request, parts_):
part_factory_ = loose_mock(request, spec=Part)
part_factory_.side_effect = parts_
return part_factory_
@pytest.fixture
def partnames_(self, request):
partname_ = loose_mock(request, spec=str, name='partname_')
partname_2_ = loose_mock(request, spec=str, name='partname_2_')
return partname_, partname_2_
@pytest.fixture
def parts_(self, request):
part_ = instance_mock(request, Part, name='part_')
part_2_ = instance_mock(request, Part, name='part_2')
return part_, part_2_
@pytest.fixture
def parts_dict_(self, request, partnames_, parts_):
partname_, partname_2_ = partnames_
part_, part_2_ = parts_
return {partname_: part_, partname_2_: part_2_}
@pytest.fixture
def pkg_(self, request):
return instance_mock(request, OpcPackage)
@pytest.fixture
def pkg_reader_(
self, request, partnames_, content_types_, reltypes_, blobs_):
partname_, partname_2_ = partnames_
content_type_, content_type_2_ = content_types_
reltype_, reltype_2_ = reltypes_
blob_, blob_2_ = blobs_
iter_spart_items = (
(partname_, content_type_, reltype_, blob_),
(partname_2_, content_type_2_, reltype_2_, blob_2_),
)
pkg_reader_ = instance_mock(request, PackageReader)
pkg_reader_.iter_sparts.return_value = iter_spart_items
return pkg_reader_
@pytest.fixture
def reltypes_(self, request):
reltype_ = instance_mock(request, str, name='reltype_')
reltype_2_ = instance_mock(request, str, name='reltype_2')
return reltype_, reltype_2_
@pytest.fixture
def _unmarshal_parts_(self, request):
return method_mock(request, Unmarshaller, '_unmarshal_parts', autospec=False)
@pytest.fixture
def _unmarshal_relationships_(self, request):
return method_mock(
request, Unmarshaller, '_unmarshal_relationships', autospec=False
)