"""Test data for relationship-related unit tests."""
from docx.opc.constants import NAMESPACE as NS
from docx.opc.constants import RELATIONSHIP_TYPE as RT
from docx.opc.oxml import parse_xml
from docx.opc.rel import Relationships
class BaseBuilder:
"""
Provides common behavior for all data builders.
"""
@property
def element(self):
"""Return element based on XML generated by builder"""
return parse_xml(self.xml)
def with_indent(self, indent):
"""Add integer `indent` spaces at beginning of element XML"""
self._indent = indent
return self
class RelationshipsBuilder:
"""Builder class for test Relationships"""
partname_tmpls = {
RT.SLIDE_MASTER: "/ppt/slideMasters/slideMaster%d.xml",
RT.SLIDE: "/ppt/slides/slide%d.xml",
}
def __init__(self):
self.relationships = []
self.next_rel_num = 1
self.next_partnums = {}
def _next_partnum(self, reltype):
if reltype not in self.next_partnums:
self.next_partnums[reltype] = 1
partnum = self.next_partnums[reltype]
self.next_partnums[reltype] = partnum + 1
return partnum
@property
def next_rId(self):
rId = "rId%d" % self.next_rel_num
self.next_rel_num += 1
return rId
def _next_tuple_partname(self, reltype):
partname_tmpl = self.partname_tmpls[reltype]
partnum = self._next_partnum(reltype)
return partname_tmpl % partnum
def build(self):
rels = Relationships()
for rel in self.relationships:
rels.add_rel(rel)
return rels
class CT_DefaultBuilder(BaseBuilder):
"""
Test data builder for CT_Default (Default) XML element that appears in
`[Content_Types].xml`.
"""
def __init__(self):
"""Establish instance variables with default values"""
self._content_type = "application/xml"
self._extension = "xml"
self._indent = 0
self._namespace = ' xmlns="%s"' % NS.OPC_CONTENT_TYPES
def with_content_type(self, content_type):
"""Set ContentType attribute to `content_type`"""
self._content_type = content_type
return self
def with_extension(self, extension):
"""Set Extension attribute to `extension`"""
self._extension = extension
return self
def without_namespace(self):
"""Don't include an 'xmlns=' attribute"""
self._namespace = ""
return self
@property
def xml(self):
"""Return Default element"""
tmpl = '%s\n'
indent = " " * self._indent
return tmpl % (indent, self._namespace, self._extension, self._content_type)
class CT_OverrideBuilder(BaseBuilder):
"""
Test data builder for CT_Override (Override) XML element that appears in
`[Content_Types].xml`.
"""
def __init__(self):
"""Establish instance variables with default values"""
self._content_type = "app/vnd.type"
self._indent = 0
self._namespace = ' xmlns="%s"' % NS.OPC_CONTENT_TYPES
self._partname = "/part/name.xml"
def with_content_type(self, content_type):
"""Set ContentType attribute to `content_type`"""
self._content_type = content_type
return self
def with_partname(self, partname):
"""Set PartName attribute to `partname`"""
self._partname = partname
return self
def without_namespace(self):
"""Don't include an 'xmlns=' attribute"""
self._namespace = ""
return self
@property
def xml(self):
"""Return Override element"""
tmpl = '%s\n'
indent = " " * self._indent
return tmpl % (indent, self._namespace, self._partname, self._content_type)
class CT_RelationshipBuilder(BaseBuilder):
"""
Test data builder for CT_Relationship (Relationship) XML element that
appears in .rels files
"""
def __init__(self):
"""Establish instance variables with default values"""
self._rId = "rId9"
self._reltype = "ReLtYpE"
self._target = "docProps/core.xml"
self._target_mode = None
self._indent = 0
self._namespace = ' xmlns="%s"' % NS.OPC_RELATIONSHIPS
def with_rId(self, rId):
"""Set Id attribute to `rId`"""
self._rId = rId
return self
def with_reltype(self, reltype):
"""Set Type attribute to `reltype`"""
self._reltype = reltype
return self
def with_target(self, target):
"""Set XXX attribute to `target`"""
self._target = target
return self
def with_target_mode(self, target_mode):
"""Set TargetMode attribute to `target_mode`"""
self._target_mode = None if target_mode == "Internal" else target_mode
return self
def without_namespace(self):
"""Don't include an 'xmlns=' attribute"""
self._namespace = ""
return self
@property
def target_mode(self):
if self._target_mode is None:
return ""
return ' TargetMode="%s"' % self._target_mode
@property
def xml(self):
"""Return Relationship element"""
tmpl = '%s\n'
indent = " " * self._indent
return tmpl % (
indent,
self._namespace,
self._rId,
self._reltype,
self._target,
self.target_mode,
)
class CT_RelationshipsBuilder(BaseBuilder):
"""
Test data builder for CT_Relationships (Relationships) XML element, the
root element in .rels files.
"""
def __init__(self):
"""Establish instance variables with default values"""
self._rels = (
("rId1", "http://reltype1", "docProps/core.xml", "Internal"),
("rId2", "http://linktype", "http://some/link", "External"),
("rId3", "http://reltype2", "../slides/slide1.xml", "Internal"),
)
@property
def xml(self):
"""
Return XML string based on settings accumulated via method calls.
"""
xml = '\n' % NS.OPC_RELATIONSHIPS
for rId, reltype, target, target_mode in self._rels:
xml += (
a_Relationship()
.with_rId(rId)
.with_reltype(reltype)
.with_target(target)
.with_target_mode(target_mode)
.with_indent(2)
.without_namespace()
.xml
)
xml += "\n"
return xml
class CT_TypesBuilder(BaseBuilder):
"""
Test data builder for CT_Types () XML element, the root element in
[Content_Types].xml files
"""
def __init__(self):
"""Establish instance variables with default values"""
self._defaults = (
("xml", "application/xml"),
("jpeg", "image/jpeg"),
)
self._empty = False
self._overrides = (
("/docProps/core.xml", "app/vnd.type1"),
("/ppt/presentation.xml", "app/vnd.type2"),
("/docProps/thumbnail.jpeg", "image/jpeg"),
)
def empty(self):
self._empty = True
return self
@property
def xml(self):
"""
Return XML string based on settings accumulated via method calls
"""
if self._empty:
return '\n' % NS.OPC_CONTENT_TYPES
xml = '\n' % NS.OPC_CONTENT_TYPES
for extension, content_type in self._defaults:
xml += (
a_Default()
.with_extension(extension)
.with_content_type(content_type)
.with_indent(2)
.without_namespace()
.xml
)
for partname, content_type in self._overrides:
xml += (
an_Override()
.with_partname(partname)
.with_content_type(content_type)
.with_indent(2)
.without_namespace()
.xml
)
xml += "\n"
return xml
def a_Default():
return CT_DefaultBuilder()
def a_Relationship():
return CT_RelationshipBuilder()
def a_Relationships():
return CT_RelationshipsBuilder()
def a_Types():
return CT_TypesBuilder()
def an_Override():
return CT_OverrideBuilder()