# encoding: utf-8
"""
Test suite for docx.opc.part module
"""
from __future__ import (
absolute_import, division, print_function, unicode_literals
)
import pytest
from docx.opc.package import OpcPackage
from docx.opc.packuri import PackURI
from docx.opc.part import Part, PartFactory, XmlPart
from docx.opc.rel import _Relationship, Relationships
from docx.oxml.xmlchemy import BaseOxmlElement
from ..unitutil.cxml import element
from ..unitutil.mock import (
class_mock, cls_attr_mock, function_mock, initializer_mock,
instance_mock, loose_mock, Mock
)
class DescribePart(object):
def it_can_be_constructed_by_PartFactory(self, load_fixture):
partname_, content_type_, blob_, package_, __init_ = load_fixture
part = Part.load(partname_, content_type_, blob_, package_)
__init_.assert_called_once_with(
partname_, content_type_, blob_, package_
)
assert isinstance(part, Part)
def it_knows_its_partname(self, partname_get_fixture):
part, expected_partname = partname_get_fixture
assert part.partname == expected_partname
def it_can_change_its_partname(self, partname_set_fixture):
part, new_partname = partname_set_fixture
part.partname = new_partname
assert part.partname == new_partname
def it_knows_its_content_type(self, content_type_fixture):
part, expected_content_type = content_type_fixture
assert part.content_type == expected_content_type
def it_knows_the_package_it_belongs_to(self, package_get_fixture):
part, expected_package = package_get_fixture
assert part.package == expected_package
def it_can_be_notified_after_unmarshalling_is_complete(self, part):
part.after_unmarshal()
def it_can_be_notified_before_marshalling_is_started(self, part):
part.before_marshal()
def it_uses_the_load_blob_as_its_blob(self, blob_fixture):
part, load_blob = blob_fixture
assert part.blob is load_blob
# fixtures ---------------------------------------------
@pytest.fixture
def blob_fixture(self, blob_):
part = Part(None, None, blob_, None)
return part, blob_
@pytest.fixture
def content_type_fixture(self):
content_type = 'content/type'
part = Part(None, content_type, None, None)
return part, content_type
@pytest.fixture
def load_fixture(
self, request, partname_, content_type_, blob_, package_,
__init_):
return (partname_, content_type_, blob_, package_, __init_)
@pytest.fixture
def package_get_fixture(self, package_):
part = Part(None, None, None, package_)
return part, package_
@pytest.fixture
def part(self):
part = Part(None, None)
return part
@pytest.fixture
def partname_get_fixture(self):
partname = PackURI('/part/name')
part = Part(partname, None, None, None)
return part, partname
@pytest.fixture
def partname_set_fixture(self):
old_partname = PackURI('/old/part/name')
new_partname = PackURI('/new/part/name')
part = Part(old_partname, None, None, None)
return part, new_partname
# fixture components ---------------------------------------------
@pytest.fixture
def blob_(self, request):
return instance_mock(request, bytes)
@pytest.fixture
def content_type_(self, request):
return instance_mock(request, str)
@pytest.fixture
def __init_(self, request):
return initializer_mock(request, Part)
@pytest.fixture
def package_(self, request):
return instance_mock(request, OpcPackage)
@pytest.fixture
def partname_(self, request):
return instance_mock(request, PackURI)
class DescribePartRelationshipManagementInterface(object):
def it_provides_access_to_its_relationships(self, rels_fixture):
part, Relationships_, partname_, rels_ = rels_fixture
rels = part.rels
Relationships_.assert_called_once_with(partname_.baseURI)
assert rels is rels_
def it_can_load_a_relationship(self, load_rel_fixture):
part, rels_, reltype_, target_, rId_ = load_rel_fixture
part.load_rel(reltype_, target_, rId_)
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):
part, target_, reltype_, rId_ = relate_to_part_fixture
rId = part.relate_to(target_, reltype_)
part.rels.get_or_add.assert_called_once_with(reltype_, target_)
assert rId is rId_
def it_can_establish_an_external_relationship(
self, relate_to_url_fixture):
part, url_, reltype_, rId_ = relate_to_url_fixture
rId = part.relate_to(url_, reltype_, is_external=True)
part.rels.get_or_add_ext_rel.assert_called_once_with(reltype_, url_)
assert rId is rId_
def it_can_drop_a_relationship(self, drop_rel_fixture):
part, rId, rel_should_be_gone = drop_rel_fixture
part.drop_rel(rId)
if rel_should_be_gone:
assert rId not in part.rels
else:
assert rId in part.rels
def it_can_find_a_related_part_by_reltype(self, related_part_fixture):
part, reltype_, related_part_ = related_part_fixture
related_part = part.part_related_by(reltype_)
part.rels.part_with_reltype.assert_called_once_with(reltype_)
assert related_part is related_part_
def it_can_find_a_related_part_by_rId(self, related_parts_fixture):
part, related_parts_ = related_parts_fixture
assert part.related_parts is related_parts_
def it_can_find_the_uri_of_an_external_relationship(
self, target_ref_fixture):
part, rId_, url_ = target_ref_fixture
url = part.target_ref(rId_)
assert url == url_
# fixtures ---------------------------------------------
@pytest.fixture(params=[
('w:p', True),
('w:p/r:a{r:id=rId42}', True),
('w:p/r:a{r:id=rId42}/r:b{r:id=rId42}', False),
])
def drop_rel_fixture(self, request, part):
part_cxml, rel_should_be_dropped = request.param
rId = 'rId42'
part._element = element(part_cxml)
part._rels = {rId: None}
return part, rId, rel_should_be_dropped
@pytest.fixture
def load_rel_fixture(self, part, rels_, reltype_, part_, rId_):
part._rels = rels_
return part, rels_, reltype_, part_, rId_
@pytest.fixture
def relate_to_part_fixture(
self, request, part, reltype_, part_, rels_, rId_):
part._rels = rels_
target_ = part_
return part, target_, reltype_, rId_
@pytest.fixture
def relate_to_url_fixture(
self, request, part, rels_, url_, reltype_, rId_):
part._rels = rels_
return part, url_, reltype_, rId_
@pytest.fixture
def related_part_fixture(self, request, part, rels_, reltype_, part_):
part._rels = rels_
return part, reltype_, part_
@pytest.fixture
def related_parts_fixture(self, request, part, rels_, related_parts_):
part._rels = rels_
return part, related_parts_
@pytest.fixture
def rels_fixture(self, Relationships_, partname_, rels_):
part = Part(partname_, None)
return part, Relationships_, partname_, rels_
@pytest.fixture
def target_ref_fixture(self, request, part, rId_, rel_, url_):
part._rels = {rId_: rel_}
return part, rId_, url_
# fixture components ---------------------------------------------
@pytest.fixture
def part(self):
return Part(None, None)
@pytest.fixture
def part_(self, request):
return instance_mock(request, Part)
@pytest.fixture
def partname_(self, request):
return instance_mock(request, PackURI)
@pytest.fixture
def Relationships_(self, request, rels_):
return class_mock(
request, 'docx.opc.part.Relationships', return_value=rels_
)
@pytest.fixture
def rel_(self, request, rId_, url_):
return instance_mock(
request, _Relationship, rId=rId_, target_ref=url_
)
@pytest.fixture
def rels_(self, request, part_, rel_, rId_, related_parts_):
rels_ = instance_mock(request, Relationships)
rels_.part_with_reltype.return_value = part_
rels_.get_or_add.return_value = rel_
rels_.get_or_add_ext_rel.return_value = rId_
rels_.related_parts = related_parts_
return rels_
@pytest.fixture
def related_parts_(self, request):
return instance_mock(request, dict)
@pytest.fixture
def reltype_(self, request):
return instance_mock(request, str)
@pytest.fixture
def rId_(self, request):
return instance_mock(request, str)
@pytest.fixture
def url_(self, request):
return instance_mock(request, str)
class DescribePartFactory(object):
def it_constructs_part_from_selector_if_defined(
self, cls_selector_fixture):
# fixture ----------------------
(cls_selector_fn_, part_load_params, CustomPartClass_,
part_of_custom_type_) = cls_selector_fixture
partname, content_type, reltype, blob, package = part_load_params
# exercise ---------------------
PartFactory.part_class_selector = cls_selector_fn_
part = PartFactory(partname, content_type, reltype, blob, package)
# verify -----------------------
cls_selector_fn_.assert_called_once_with(content_type, reltype)
CustomPartClass_.load.assert_called_once_with(
partname, content_type, blob, package
)
assert part is part_of_custom_type_
def it_constructs_custom_part_type_for_registered_content_types(
self, part_args_, CustomPartClass_, part_of_custom_type_):
# fixture ----------------------
partname, content_type, reltype, package, blob = part_args_
# exercise ---------------------
PartFactory.part_type_for[content_type] = CustomPartClass_
part = PartFactory(partname, content_type, reltype, blob, package)
# verify -----------------------
CustomPartClass_.load.assert_called_once_with(
partname, content_type, blob, package
)
assert part is part_of_custom_type_
def it_constructs_part_using_default_class_when_no_custom_registered(
self, part_args_2_, DefaultPartClass_, part_of_default_type_):
partname, content_type, reltype, blob, package = part_args_2_
part = PartFactory(partname, content_type, reltype, blob, package)
DefaultPartClass_.load.assert_called_once_with(
partname, content_type, blob, package
)
assert part is part_of_default_type_
# fixtures ---------------------------------------------
@pytest.fixture
def blob_(self, request):
return instance_mock(request, str)
@pytest.fixture
def blob_2_(self, request):
return instance_mock(request, str)
@pytest.fixture
def cls_method_fn_(self, request, cls_selector_fn_):
return function_mock(
request, 'docx.opc.part.cls_method_fn',
return_value=cls_selector_fn_
)
@pytest.fixture
def cls_selector_fixture(
self, request, cls_selector_fn_, cls_method_fn_, part_load_params,
CustomPartClass_, part_of_custom_type_):
def reset_part_class_selector():
PartFactory.part_class_selector = original_part_class_selector
original_part_class_selector = PartFactory.part_class_selector
request.addfinalizer(reset_part_class_selector)
return (
cls_selector_fn_, part_load_params, CustomPartClass_,
part_of_custom_type_
)
@pytest.fixture
def cls_selector_fn_(self, request, CustomPartClass_):
cls_selector_fn_ = loose_mock(request)
# Python 3 version
cls_selector_fn_.return_value = CustomPartClass_
# Python 2 version
cls_selector_fn_.__func__ = loose_mock(
request, name='__func__', return_value=cls_selector_fn_
)
return cls_selector_fn_
@pytest.fixture
def content_type_(self, request):
return instance_mock(request, str)
@pytest.fixture
def content_type_2_(self, request):
return instance_mock(request, str)
@pytest.fixture
def CustomPartClass_(self, request, part_of_custom_type_):
CustomPartClass_ = Mock(name='CustomPartClass', spec=Part)
CustomPartClass_.load.return_value = part_of_custom_type_
return CustomPartClass_
@pytest.fixture
def DefaultPartClass_(self, request, part_of_default_type_):
DefaultPartClass_ = cls_attr_mock(
request, PartFactory, 'default_part_type'
)
DefaultPartClass_.load.return_value = part_of_default_type_
return DefaultPartClass_
@pytest.fixture
def package_(self, request):
return instance_mock(request, OpcPackage)
@pytest.fixture
def package_2_(self, request):
return instance_mock(request, OpcPackage)
@pytest.fixture
def part_load_params(
self, partname_, content_type_, reltype_, blob_, package_):
return partname_, content_type_, reltype_, blob_, package_
@pytest.fixture
def part_of_custom_type_(self, request):
return instance_mock(request, Part)
@pytest.fixture
def part_of_default_type_(self, request):
return instance_mock(request, Part)
@pytest.fixture
def partname_(self, request):
return instance_mock(request, PackURI)
@pytest.fixture
def partname_2_(self, request):
return instance_mock(request, PackURI)
@pytest.fixture
def part_args_(
self, request, partname_, content_type_, reltype_, package_,
blob_):
return partname_, content_type_, reltype_, blob_, package_
@pytest.fixture
def part_args_2_(
self, request, partname_2_, content_type_2_, reltype_2_,
package_2_, blob_2_):
return partname_2_, content_type_2_, reltype_2_, blob_2_, package_2_
@pytest.fixture
def reltype_(self, request):
return instance_mock(request, str)
@pytest.fixture
def reltype_2_(self, request):
return instance_mock(request, str)
class DescribeXmlPart(object):
def it_can_be_constructed_by_PartFactory(self, load_fixture):
partname_, content_type_, blob_, package_ = load_fixture[:4]
element_, parse_xml_, __init_ = load_fixture[4:]
# exercise ---------------------
part = XmlPart.load(partname_, content_type_, blob_, package_)
# verify -----------------------
parse_xml_.assert_called_once_with(blob_)
__init_.assert_called_once_with(
partname_, content_type_, element_, package_
)
assert isinstance(part, XmlPart)
def it_can_serialize_to_xml(self, blob_fixture):
xml_part, element_, serialize_part_xml_ = blob_fixture
blob = xml_part.blob
serialize_part_xml_.assert_called_once_with(element_)
assert blob is serialize_part_xml_.return_value
def it_knows_its_the_part_for_its_child_objects(self, part_fixture):
xml_part = part_fixture
assert xml_part.part is xml_part
# fixtures -------------------------------------------------------
@pytest.fixture
def blob_fixture(self, request, element_, serialize_part_xml_):
xml_part = XmlPart(None, None, element_, None)
return xml_part, element_, serialize_part_xml_
@pytest.fixture
def load_fixture(
self, request, partname_, content_type_, blob_, package_,
element_, parse_xml_, __init_):
return (
partname_, content_type_, blob_, package_, element_, parse_xml_,
__init_
)
@pytest.fixture
def part_fixture(self):
return XmlPart(None, None, None, None)
# fixture components ---------------------------------------------
@pytest.fixture
def blob_(self, request):
return instance_mock(request, str)
@pytest.fixture
def content_type_(self, request):
return instance_mock(request, str)
@pytest.fixture
def element_(self, request):
return instance_mock(request, BaseOxmlElement)
@pytest.fixture
def __init_(self, request):
return initializer_mock(request, XmlPart)
@pytest.fixture
def package_(self, request):
return instance_mock(request, OpcPackage)
@pytest.fixture
def parse_xml_(self, request, element_):
return function_mock(
request, 'docx.opc.part.parse_xml', return_value=element_
)
@pytest.fixture
def partname_(self, request):
return instance_mock(request, PackURI)
@pytest.fixture
def serialize_part_xml_(self, request):
return function_mock(
request, 'docx.opc.part.serialize_part_xml'
)