about summary refs log tree commit diff
path: root/.venv/lib/python3.12/site-packages/docx/opc/phys_pkg.py
diff options
context:
space:
mode:
Diffstat (limited to '.venv/lib/python3.12/site-packages/docx/opc/phys_pkg.py')
-rw-r--r--.venv/lib/python3.12/site-packages/docx/opc/phys_pkg.py119
1 files changed, 119 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/docx/opc/phys_pkg.py b/.venv/lib/python3.12/site-packages/docx/opc/phys_pkg.py
new file mode 100644
index 00000000..5ec32237
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/docx/opc/phys_pkg.py
@@ -0,0 +1,119 @@
+"""Provides a general interface to a `physical` OPC package, such as a zip file."""
+
+import os
+from zipfile import ZIP_DEFLATED, ZipFile, is_zipfile
+
+from docx.opc.exceptions import PackageNotFoundError
+from docx.opc.packuri import CONTENT_TYPES_URI
+
+
+class PhysPkgReader:
+    """Factory for physical package reader objects."""
+
+    def __new__(cls, pkg_file):
+        # if `pkg_file` is a string, treat it as a path
+        if isinstance(pkg_file, str):
+            if os.path.isdir(pkg_file):
+                reader_cls = _DirPkgReader
+            elif is_zipfile(pkg_file):
+                reader_cls = _ZipPkgReader
+            else:
+                raise PackageNotFoundError("Package not found at '%s'" % pkg_file)
+        else:  # assume it's a stream and pass it to Zip reader to sort out
+            reader_cls = _ZipPkgReader
+
+        return super(PhysPkgReader, cls).__new__(reader_cls)
+
+
+class PhysPkgWriter:
+    """Factory for physical package writer objects."""
+
+    def __new__(cls, pkg_file):
+        return super(PhysPkgWriter, cls).__new__(_ZipPkgWriter)
+
+
+class _DirPkgReader(PhysPkgReader):
+    """Implements |PhysPkgReader| interface for an OPC package extracted into a
+    directory."""
+
+    def __init__(self, path):
+        """`path` is the path to a directory containing an expanded package."""
+        super(_DirPkgReader, self).__init__()
+        self._path = os.path.abspath(path)
+
+    def blob_for(self, pack_uri):
+        """Return contents of file corresponding to `pack_uri` in package directory."""
+        path = os.path.join(self._path, pack_uri.membername)
+        with open(path, "rb") as f:
+            blob = f.read()
+        return blob
+
+    def close(self):
+        """Provides interface consistency with |ZipFileSystem|, but does nothing, a
+        directory file system doesn't need closing."""
+        pass
+
+    @property
+    def content_types_xml(self):
+        """Return the `[Content_Types].xml` blob from the package."""
+        return self.blob_for(CONTENT_TYPES_URI)
+
+    def rels_xml_for(self, source_uri):
+        """Return rels item XML for source with `source_uri`, or None if the item has no
+        rels item."""
+        try:
+            rels_xml = self.blob_for(source_uri.rels_uri)
+        except IOError:
+            rels_xml = None
+        return rels_xml
+
+
+class _ZipPkgReader(PhysPkgReader):
+    """Implements |PhysPkgReader| interface for a zip file OPC package."""
+
+    def __init__(self, pkg_file):
+        super(_ZipPkgReader, self).__init__()
+        self._zipf = ZipFile(pkg_file, "r")
+
+    def blob_for(self, pack_uri):
+        """Return blob corresponding to `pack_uri`.
+
+        Raises |ValueError| if no matching member is present in zip archive.
+        """
+        return self._zipf.read(pack_uri.membername)
+
+    def close(self):
+        """Close the zip archive, releasing any resources it is using."""
+        self._zipf.close()
+
+    @property
+    def content_types_xml(self):
+        """Return the `[Content_Types].xml` blob from the zip package."""
+        return self.blob_for(CONTENT_TYPES_URI)
+
+    def rels_xml_for(self, source_uri):
+        """Return rels item XML for source with `source_uri` or None if no rels item is
+        present."""
+        try:
+            rels_xml = self.blob_for(source_uri.rels_uri)
+        except KeyError:
+            rels_xml = None
+        return rels_xml
+
+
+class _ZipPkgWriter(PhysPkgWriter):
+    """Implements |PhysPkgWriter| interface for a zip file OPC package."""
+
+    def __init__(self, pkg_file):
+        super(_ZipPkgWriter, self).__init__()
+        self._zipf = ZipFile(pkg_file, "w", compression=ZIP_DEFLATED)
+
+    def close(self):
+        """Close the zip archive, flushing any pending physical writes and releasing any
+        resources it's using."""
+        self._zipf.close()
+
+    def write(self, pack_uri, blob):
+        """Write `blob` to this zip package with the membername corresponding to
+        `pack_uri`."""
+        self._zipf.writestr(pack_uri.membername, blob)