about summary refs log tree commit diff
path: root/.venv/lib/python3.12/site-packages/docx/opc/package.py
diff options
context:
space:
mode:
authorS. Solomon Darnell2025-03-28 21:52:21 -0500
committerS. Solomon Darnell2025-03-28 21:52:21 -0500
commit4a52a71956a8d46fcb7294ac71734504bb09bcc2 (patch)
treeee3dc5af3b6313e921cd920906356f5d4febc4ed /.venv/lib/python3.12/site-packages/docx/opc/package.py
parentcc961e04ba734dd72309fb548a2f97d67d578813 (diff)
downloadgn-ai-master.tar.gz
two version of R2R are here HEAD master
Diffstat (limited to '.venv/lib/python3.12/site-packages/docx/opc/package.py')
-rw-r--r--.venv/lib/python3.12/site-packages/docx/opc/package.py220
1 files changed, 220 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/docx/opc/package.py b/.venv/lib/python3.12/site-packages/docx/opc/package.py
new file mode 100644
index 00000000..3b1eef25
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/docx/opc/package.py
@@ -0,0 +1,220 @@
+"""Objects that implement reading and writing OPC packages."""
+
+from __future__ import annotations
+
+from typing import IO, TYPE_CHECKING, Iterator, cast
+
+from docx.opc.constants import RELATIONSHIP_TYPE as RT
+from docx.opc.packuri import PACKAGE_URI, PackURI
+from docx.opc.part import PartFactory
+from docx.opc.parts.coreprops import CorePropertiesPart
+from docx.opc.pkgreader import PackageReader
+from docx.opc.pkgwriter import PackageWriter
+from docx.opc.rel import Relationships
+from docx.shared import lazyproperty
+
+if TYPE_CHECKING:
+    from docx.opc.coreprops import CoreProperties
+    from docx.opc.part import Part
+    from docx.opc.rel import _Relationship  # pyright: ignore[reportPrivateUsage]
+
+
+class OpcPackage:
+    """Main API class for |python-opc|.
+
+    A new instance is constructed by calling the :meth:`open` class method with a path
+    to a package file or file-like object containing one.
+    """
+
+    def __init__(self):
+        super(OpcPackage, self).__init__()
+
+    def after_unmarshal(self):
+        """Entry point for any post-unmarshaling processing.
+
+        May be overridden by subclasses without forwarding call to super.
+        """
+        # don't place any code here, just catch call if not overridden by
+        # subclass
+        pass
+
+    @property
+    def core_properties(self) -> CoreProperties:
+        """|CoreProperties| object providing read/write access to the Dublin Core
+        properties for this document."""
+        return self._core_properties_part.core_properties
+
+    def iter_rels(self) -> Iterator[_Relationship]:
+        """Generate exactly one reference to each relationship in the package by
+        performing a depth-first traversal of the rels graph."""
+
+        def walk_rels(
+            source: OpcPackage | Part, visited: list[Part] | None = None
+        ) -> Iterator[_Relationship]:
+            visited = [] if visited is None else visited
+            for rel in source.rels.values():
+                yield rel
+                if rel.is_external:
+                    continue
+                part = rel.target_part
+                if part in visited:
+                    continue
+                visited.append(part)
+                new_source = part
+                for rel in walk_rels(new_source, visited):
+                    yield rel
+
+        for rel in walk_rels(self):
+            yield rel
+
+    def iter_parts(self) -> Iterator[Part]:
+        """Generate exactly one reference to each of the parts in the package by
+        performing a depth-first traversal of the rels graph."""
+
+        def walk_parts(source, visited=[]):
+            for rel in source.rels.values():
+                if rel.is_external:
+                    continue
+                part = rel.target_part
+                if part in visited:
+                    continue
+                visited.append(part)
+                yield part
+                new_source = part
+                for part in walk_parts(new_source, visited):
+                    yield part
+
+        for part in walk_parts(self):
+            yield part
+
+    def load_rel(self, reltype: str, target: Part | str, rId: str, is_external: bool = False):
+        """Return newly added |_Relationship| instance of `reltype` between this part
+        and `target` with key `rId`.
+
+        Target mode is set to ``RTM.EXTERNAL`` if `is_external` is |True|. Intended for
+        use during load from a serialized package, where the rId is well known. Other
+        methods exist for adding a new relationship to the package during processing.
+        """
+        return self.rels.add_relationship(reltype, target, rId, is_external)
+
+    @property
+    def main_document_part(self):
+        """Return a reference to the main document part for this package.
+
+        Examples include a document part for a WordprocessingML package, a presentation
+        part for a PresentationML package, or a workbook part for a SpreadsheetML
+        package.
+        """
+        return self.part_related_by(RT.OFFICE_DOCUMENT)
+
+    def next_partname(self, template: str) -> PackURI:
+        """Return a |PackURI| instance representing partname matching `template`.
+
+        The returned part-name has the next available numeric suffix to distinguish it
+        from other parts of its type. `template` is a printf (%)-style template string
+        containing a single replacement item, a '%d' to be used to insert the integer
+        portion of the partname. Example: "/word/header%d.xml"
+        """
+        partnames = {part.partname for part in self.iter_parts()}
+        for n in range(1, len(partnames) + 2):
+            candidate_partname = template % n
+            if candidate_partname not in partnames:
+                return PackURI(candidate_partname)
+
+    @classmethod
+    def open(cls, pkg_file: str | IO[bytes]) -> OpcPackage:
+        """Return an |OpcPackage| instance loaded with the contents of `pkg_file`."""
+        pkg_reader = PackageReader.from_file(pkg_file)
+        package = cls()
+        Unmarshaller.unmarshal(pkg_reader, package, PartFactory)
+        return package
+
+    def part_related_by(self, reltype: str) -> Part:
+        """Return part to which this package has a relationship of `reltype`.
+
+        Raises |KeyError| if no such relationship is found and |ValueError| if more than
+        one such relationship is found.
+        """
+        return self.rels.part_with_reltype(reltype)
+
+    @property
+    def parts(self) -> list[Part]:
+        """Return a list containing a reference to each of the parts in this package."""
+        return list(self.iter_parts())
+
+    def relate_to(self, part: Part, reltype: str):
+        """Return rId key of new or existing relationship to `part`.
+
+        If a relationship of `reltype` to `part` already exists, its rId is returned. Otherwise a
+        new relationship is created and that rId is returned.
+        """
+        rel = self.rels.get_or_add(reltype, part)
+        return rel.rId
+
+    @lazyproperty
+    def rels(self):
+        """Return a reference to the |Relationships| instance holding the collection of
+        relationships for this package."""
+        return Relationships(PACKAGE_URI.baseURI)
+
+    def save(self, pkg_file: str | IO[bytes]):
+        """Save this package to `pkg_file`.
+
+        `pkg_file` can be either a file-path or a file-like object.
+        """
+        for part in self.parts:
+            part.before_marshal()
+        PackageWriter.write(pkg_file, self.rels, self.parts)
+
+    @property
+    def _core_properties_part(self) -> CorePropertiesPart:
+        """|CorePropertiesPart| object related to this package.
+
+        Creates a default core properties part if one is not present (not common).
+        """
+        try:
+            return cast(CorePropertiesPart, self.part_related_by(RT.CORE_PROPERTIES))
+        except KeyError:
+            core_properties_part = CorePropertiesPart.default(self)
+            self.relate_to(core_properties_part, RT.CORE_PROPERTIES)
+            return core_properties_part
+
+
+class Unmarshaller:
+    """Hosts static methods for unmarshalling a package from a |PackageReader|."""
+
+    @staticmethod
+    def unmarshal(pkg_reader, package, part_factory):
+        """Construct graph of parts and realized relationships based on the contents of
+        `pkg_reader`, delegating construction of each part to `part_factory`.
+
+        Package relationships are added to `pkg`.
+        """
+        parts = Unmarshaller._unmarshal_parts(pkg_reader, package, part_factory)
+        Unmarshaller._unmarshal_relationships(pkg_reader, package, parts)
+        for part in parts.values():
+            part.after_unmarshal()
+        package.after_unmarshal()
+
+    @staticmethod
+    def _unmarshal_parts(pkg_reader, package, part_factory):
+        """Return a dictionary of |Part| instances unmarshalled from `pkg_reader`, keyed
+        by partname.
+
+        Side-effect is that each part in `pkg_reader` is constructed using
+        `part_factory`.
+        """
+        parts = {}
+        for partname, content_type, reltype, blob in pkg_reader.iter_sparts():
+            parts[partname] = part_factory(partname, content_type, reltype, blob, package)
+        return parts
+
+    @staticmethod
+    def _unmarshal_relationships(pkg_reader, package, parts):
+        """Add a relationship to the source object corresponding to each of the
+        relationships in `pkg_reader` with its target_part set to the actual target part
+        in `parts`."""
+        for source_uri, srel in pkg_reader.iter_srels():
+            source = package if source_uri == "/" else parts[source_uri]
+            target = srel.target_ref if srel.is_external else parts[srel.target_partname]
+            source.load_rel(srel.reltype, target, srel.rId, srel.is_external)