aboutsummaryrefslogtreecommitdiff
path: root/.venv/lib/python3.12/site-packages/docx/opc/oxml.py
diff options
context:
space:
mode:
Diffstat (limited to '.venv/lib/python3.12/site-packages/docx/opc/oxml.py')
-rw-r--r--.venv/lib/python3.12/site-packages/docx/opc/oxml.py248
1 files changed, 248 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/docx/opc/oxml.py b/.venv/lib/python3.12/site-packages/docx/opc/oxml.py
new file mode 100644
index 00000000..7da72f50
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/docx/opc/oxml.py
@@ -0,0 +1,248 @@
+# pyright: reportPrivateUsage=false
+
+"""Temporary stand-in for main oxml module.
+
+This module came across with the PackageReader transplant. Probably much will get
+replaced with objects from the pptx.oxml.core and then this module will either get
+deleted or only hold the package related custom element classes.
+"""
+
+from __future__ import annotations
+
+from typing import cast
+
+from lxml import etree
+
+from docx.opc.constants import NAMESPACE as NS
+from docx.opc.constants import RELATIONSHIP_TARGET_MODE as RTM
+
+# configure XML parser
+element_class_lookup = etree.ElementNamespaceClassLookup()
+oxml_parser = etree.XMLParser(remove_blank_text=True, resolve_entities=False)
+oxml_parser.set_element_class_lookup(element_class_lookup)
+
+nsmap = {
+ "ct": NS.OPC_CONTENT_TYPES,
+ "pr": NS.OPC_RELATIONSHIPS,
+ "r": NS.OFC_RELATIONSHIPS,
+}
+
+
+# ===========================================================================
+# functions
+# ===========================================================================
+
+
+def parse_xml(text: str) -> etree._Element:
+ """`etree.fromstring()` replacement that uses oxml parser."""
+ return etree.fromstring(text, oxml_parser)
+
+
+def qn(tag):
+ """Stands for "qualified name", a utility function to turn a namespace prefixed tag
+ name into a Clark-notation qualified tag name for lxml.
+
+ For
+ example, ``qn('p:cSld')`` returns ``'{http://schemas.../main}cSld'``.
+ """
+ prefix, tagroot = tag.split(":")
+ uri = nsmap[prefix]
+ return "{%s}%s" % (uri, tagroot)
+
+
+def serialize_part_xml(part_elm: etree._Element):
+ """Serialize `part_elm` etree element to XML suitable for storage as an XML part.
+
+ That is to say, no insignificant whitespace added for readability, and an
+ appropriate XML declaration added with UTF-8 encoding specified.
+ """
+ return etree.tostring(part_elm, encoding="UTF-8", standalone=True)
+
+
+def serialize_for_reading(element):
+ """Serialize `element` to human-readable XML suitable for tests.
+
+ No XML declaration.
+ """
+ return etree.tostring(element, encoding="unicode", pretty_print=True)
+
+
+# ===========================================================================
+# Custom element classes
+# ===========================================================================
+
+
+class BaseOxmlElement(etree.ElementBase):
+ """Base class for all custom element classes, to add standardized behavior to all
+ classes in one place."""
+
+ @property
+ def xml(self):
+ """Return XML string for this element, suitable for testing purposes.
+
+ Pretty printed for readability and without an XML declaration at the top.
+ """
+ return serialize_for_reading(self)
+
+
+class CT_Default(BaseOxmlElement):
+ """``<Default>`` element, specifying the default content type to be applied to a
+ part with the specified extension."""
+
+ @property
+ def content_type(self):
+ """String held in the ``ContentType`` attribute of this ``<Default>``
+ element."""
+ return self.get("ContentType")
+
+ @property
+ def extension(self):
+ """String held in the ``Extension`` attribute of this ``<Default>`` element."""
+ return self.get("Extension")
+
+ @staticmethod
+ def new(ext, content_type):
+ """Return a new ``<Default>`` element with attributes set to parameter
+ values."""
+ xml = '<Default xmlns="%s"/>' % nsmap["ct"]
+ default = parse_xml(xml)
+ default.set("Extension", ext)
+ default.set("ContentType", content_type)
+ return default
+
+
+class CT_Override(BaseOxmlElement):
+ """``<Override>`` element, specifying the content type to be applied for a part with
+ the specified partname."""
+
+ @property
+ def content_type(self):
+ """String held in the ``ContentType`` attribute of this ``<Override>``
+ element."""
+ return self.get("ContentType")
+
+ @staticmethod
+ def new(partname, content_type):
+ """Return a new ``<Override>`` element with attributes set to parameter
+ values."""
+ xml = '<Override xmlns="%s"/>' % nsmap["ct"]
+ override = parse_xml(xml)
+ override.set("PartName", partname)
+ override.set("ContentType", content_type)
+ return override
+
+ @property
+ def partname(self):
+ """String held in the ``PartName`` attribute of this ``<Override>`` element."""
+ return self.get("PartName")
+
+
+class CT_Relationship(BaseOxmlElement):
+ """``<Relationship>`` element, representing a single relationship from a source to a
+ target part."""
+
+ @staticmethod
+ def new(rId: str, reltype: str, target: str, target_mode: str = RTM.INTERNAL):
+ """Return a new ``<Relationship>`` element."""
+ xml = '<Relationship xmlns="%s"/>' % nsmap["pr"]
+ relationship = parse_xml(xml)
+ relationship.set("Id", rId)
+ relationship.set("Type", reltype)
+ relationship.set("Target", target)
+ if target_mode == RTM.EXTERNAL:
+ relationship.set("TargetMode", RTM.EXTERNAL)
+ return relationship
+
+ @property
+ def rId(self):
+ """String held in the ``Id`` attribute of this ``<Relationship>`` element."""
+ return self.get("Id")
+
+ @property
+ def reltype(self):
+ """String held in the ``Type`` attribute of this ``<Relationship>`` element."""
+ return self.get("Type")
+
+ @property
+ def target_ref(self):
+ """String held in the ``Target`` attribute of this ``<Relationship>``
+ element."""
+ return self.get("Target")
+
+ @property
+ def target_mode(self):
+ """String held in the ``TargetMode`` attribute of this ``<Relationship>``
+ element, either ``Internal`` or ``External``.
+
+ Defaults to ``Internal``.
+ """
+ return self.get("TargetMode", RTM.INTERNAL)
+
+
+class CT_Relationships(BaseOxmlElement):
+ """``<Relationships>`` element, the root element in a .rels file."""
+
+ def add_rel(self, rId: str, reltype: str, target: str, is_external: bool = False):
+ """Add a child ``<Relationship>`` element with attributes set according to
+ parameter values."""
+ target_mode = RTM.EXTERNAL if is_external else RTM.INTERNAL
+ relationship = CT_Relationship.new(rId, reltype, target, target_mode)
+ self.append(relationship)
+
+ @staticmethod
+ def new() -> CT_Relationships:
+ """Return a new ``<Relationships>`` element."""
+ xml = '<Relationships xmlns="%s"/>' % nsmap["pr"]
+ return cast(CT_Relationships, parse_xml(xml))
+
+ @property
+ def Relationship_lst(self):
+ """Return a list containing all the ``<Relationship>`` child elements."""
+ return self.findall(qn("pr:Relationship"))
+
+ @property
+ def xml(self):
+ """Return XML string for this element, suitable for saving in a .rels stream,
+ not pretty printed and with an XML declaration at the top."""
+ return serialize_part_xml(self)
+
+
+class CT_Types(BaseOxmlElement):
+ """``<Types>`` element, the container element for Default and Override elements in
+ [Content_Types].xml."""
+
+ def add_default(self, ext, content_type):
+ """Add a child ``<Default>`` element with attributes set to parameter values."""
+ default = CT_Default.new(ext, content_type)
+ self.append(default)
+
+ def add_override(self, partname, content_type):
+ """Add a child ``<Override>`` element with attributes set to parameter
+ values."""
+ override = CT_Override.new(partname, content_type)
+ self.append(override)
+
+ @property
+ def defaults(self):
+ return self.findall(qn("ct:Default"))
+
+ @staticmethod
+ def new():
+ """Return a new ``<Types>`` element."""
+ xml = '<Types xmlns="%s"/>' % nsmap["ct"]
+ types = parse_xml(xml)
+ return types
+
+ @property
+ def overrides(self):
+ return self.findall(qn("ct:Override"))
+
+
+ct_namespace = element_class_lookup.get_namespace(nsmap["ct"])
+ct_namespace["Default"] = CT_Default
+ct_namespace["Override"] = CT_Override
+ct_namespace["Types"] = CT_Types
+
+pr_namespace = element_class_lookup.get_namespace(nsmap["pr"])
+pr_namespace["Relationship"] = CT_Relationship
+pr_namespace["Relationships"] = CT_Relationships