about summary refs log tree commit diff
path: root/.venv/lib/python3.12/site-packages/docx/opc
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
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')
-rw-r--r--.venv/lib/python3.12/site-packages/docx/opc/__init__.py0
-rw-r--r--.venv/lib/python3.12/site-packages/docx/opc/constants.py532
-rw-r--r--.venv/lib/python3.12/site-packages/docx/opc/coreprops.py141
-rw-r--r--.venv/lib/python3.12/site-packages/docx/opc/exceptions.py12
-rw-r--r--.venv/lib/python3.12/site-packages/docx/opc/oxml.py248
-rw-r--r--.venv/lib/python3.12/site-packages/docx/opc/package.py220
-rw-r--r--.venv/lib/python3.12/site-packages/docx/opc/packuri.py110
-rw-r--r--.venv/lib/python3.12/site-packages/docx/opc/part.py247
-rw-r--r--.venv/lib/python3.12/site-packages/docx/opc/parts/__init__.py0
-rw-r--r--.venv/lib/python3.12/site-packages/docx/opc/parts/coreprops.py48
-rw-r--r--.venv/lib/python3.12/site-packages/docx/opc/phys_pkg.py119
-rw-r--r--.venv/lib/python3.12/site-packages/docx/opc/pkgreader.py258
-rw-r--r--.venv/lib/python3.12/site-packages/docx/opc/pkgwriter.py115
-rw-r--r--.venv/lib/python3.12/site-packages/docx/opc/rel.py155
-rw-r--r--.venv/lib/python3.12/site-packages/docx/opc/shared.py31
-rw-r--r--.venv/lib/python3.12/site-packages/docx/opc/spec.py24
16 files changed, 2260 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/docx/opc/__init__.py b/.venv/lib/python3.12/site-packages/docx/opc/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/docx/opc/__init__.py
diff --git a/.venv/lib/python3.12/site-packages/docx/opc/constants.py b/.venv/lib/python3.12/site-packages/docx/opc/constants.py
new file mode 100644
index 00000000..89d3c16c
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/docx/opc/constants.py
@@ -0,0 +1,532 @@
+"""Constant values related to the Open Packaging Convention.
+
+In particular it includes content types and relationship types.
+"""
+
+
+class CONTENT_TYPE:
+    """Content type URIs (like MIME-types) that specify a part's format."""
+
+    BMP = "image/bmp"
+    DML_CHART = "application/vnd.openxmlformats-officedocument.drawingml.chart+xml"
+    DML_CHARTSHAPES = (
+        "application/vnd.openxmlformats-officedocument.drawingml.chartshapes+xml"
+    )
+    DML_DIAGRAM_COLORS = (
+        "application/vnd.openxmlformats-officedocument.drawingml.diagramColors+xml"
+    )
+    DML_DIAGRAM_DATA = (
+        "application/vnd.openxmlformats-officedocument.drawingml.diagramData+xml"
+    )
+    DML_DIAGRAM_LAYOUT = (
+        "application/vnd.openxmlformats-officedocument.drawingml.diagramLayout+xml"
+    )
+    DML_DIAGRAM_STYLE = (
+        "application/vnd.openxmlformats-officedocument.drawingml.diagramStyle+xml"
+    )
+    GIF = "image/gif"
+    JPEG = "image/jpeg"
+    MS_PHOTO = "image/vnd.ms-photo"
+    OFC_CUSTOM_PROPERTIES = (
+        "application/vnd.openxmlformats-officedocument.custom-properties+xml"
+    )
+    OFC_CUSTOM_XML_PROPERTIES = (
+        "application/vnd.openxmlformats-officedocument.customXmlProperties+xml"
+    )
+    OFC_DRAWING = "application/vnd.openxmlformats-officedocument.drawing+xml"
+    OFC_EXTENDED_PROPERTIES = (
+        "application/vnd.openxmlformats-officedocument.extended-properties+xml"
+    )
+    OFC_OLE_OBJECT = "application/vnd.openxmlformats-officedocument.oleObject"
+    OFC_PACKAGE = "application/vnd.openxmlformats-officedocument.package"
+    OFC_THEME = "application/vnd.openxmlformats-officedocument.theme+xml"
+    OFC_THEME_OVERRIDE = (
+        "application/vnd.openxmlformats-officedocument.themeOverride+xml"
+    )
+    OFC_VML_DRAWING = "application/vnd.openxmlformats-officedocument.vmlDrawing"
+    OPC_CORE_PROPERTIES = "application/vnd.openxmlformats-package.core-properties+xml"
+    OPC_DIGITAL_SIGNATURE_CERTIFICATE = (
+        "application/vnd.openxmlformats-package.digital-signature-certificate"
+    )
+    OPC_DIGITAL_SIGNATURE_ORIGIN = (
+        "application/vnd.openxmlformats-package.digital-signature-origin"
+    )
+    OPC_DIGITAL_SIGNATURE_XMLSIGNATURE = (
+        "application/vnd.openxmlformats-package.digital-signature-xmlsignature+xml"
+    )
+    OPC_RELATIONSHIPS = "application/vnd.openxmlformats-package.relationships+xml"
+    PML_COMMENTS = (
+        "application/vnd.openxmlformats-officedocument.presentationml.comments+xml"
+    )
+    PML_COMMENT_AUTHORS = (
+        "application/vnd.openxmlformats-officedocument.presentationml.commen"
+        "tAuthors+xml"
+    )
+    PML_HANDOUT_MASTER = (
+        "application/vnd.openxmlformats-officedocument.presentationml.handou"
+        "tMaster+xml"
+    )
+    PML_NOTES_MASTER = (
+        "application/vnd.openxmlformats-officedocument.presentationml.notesM"
+        "aster+xml"
+    )
+    PML_NOTES_SLIDE = (
+        "application/vnd.openxmlformats-officedocument.presentationml.notesSlide+xml"
+    )
+    PML_PRESENTATION_MAIN = (
+        "application/vnd.openxmlformats-officedocument.presentationml.presen"
+        "tation.main+xml"
+    )
+    PML_PRES_PROPS = (
+        "application/vnd.openxmlformats-officedocument.presentationml.presProps+xml"
+    )
+    PML_PRINTER_SETTINGS = (
+        "application/vnd.openxmlformats-officedocument.presentationml.printe"
+        "rSettings"
+    )
+    PML_SLIDE = "application/vnd.openxmlformats-officedocument.presentationml.slide+xml"
+    PML_SLIDESHOW_MAIN = (
+        "application/vnd.openxmlformats-officedocument.presentationml.slides"
+        "how.main+xml"
+    )
+    PML_SLIDE_LAYOUT = (
+        "application/vnd.openxmlformats-officedocument.presentationml.slideL"
+        "ayout+xml"
+    )
+    PML_SLIDE_MASTER = (
+        "application/vnd.openxmlformats-officedocument.presentationml.slideM"
+        "aster+xml"
+    )
+    PML_SLIDE_UPDATE_INFO = (
+        "application/vnd.openxmlformats-officedocument.presentationml.slideU"
+        "pdateInfo+xml"
+    )
+    PML_TABLE_STYLES = (
+        "application/vnd.openxmlformats-officedocument.presentationml.tableS"
+        "tyles+xml"
+    )
+    PML_TAGS = "application/vnd.openxmlformats-officedocument.presentationml.tags+xml"
+    PML_TEMPLATE_MAIN = (
+        "application/vnd.openxmlformats-officedocument.presentationml.templa"
+        "te.main+xml"
+    )
+    PML_VIEW_PROPS = (
+        "application/vnd.openxmlformats-officedocument.presentationml.viewProps+xml"
+    )
+    PNG = "image/png"
+    SML_CALC_CHAIN = (
+        "application/vnd.openxmlformats-officedocument.spreadsheetml.calcChain+xml"
+    )
+    SML_CHARTSHEET = (
+        "application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml"
+    )
+    SML_COMMENTS = (
+        "application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml"
+    )
+    SML_CONNECTIONS = (
+        "application/vnd.openxmlformats-officedocument.spreadsheetml.connections+xml"
+    )
+    SML_CUSTOM_PROPERTY = (
+        "application/vnd.openxmlformats-officedocument.spreadsheetml.customProperty"
+    )
+    SML_DIALOGSHEET = (
+        "application/vnd.openxmlformats-officedocument.spreadsheetml.dialogsheet+xml"
+    )
+    SML_EXTERNAL_LINK = (
+        "application/vnd.openxmlformats-officedocument.spreadsheetml.externa"
+        "lLink+xml"
+    )
+    SML_PIVOT_CACHE_DEFINITION = (
+        "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCa"
+        "cheDefinition+xml"
+    )
+    SML_PIVOT_CACHE_RECORDS = (
+        "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCa"
+        "cheRecords+xml"
+    )
+    SML_PIVOT_TABLE = (
+        "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotTable+xml"
+    )
+    SML_PRINTER_SETTINGS = (
+        "application/vnd.openxmlformats-officedocument.spreadsheetml.printerSettings"
+    )
+    SML_QUERY_TABLE = (
+        "application/vnd.openxmlformats-officedocument.spreadsheetml.queryTable+xml"
+    )
+    SML_REVISION_HEADERS = (
+        "application/vnd.openxmlformats-officedocument.spreadsheetml.revisio"
+        "nHeaders+xml"
+    )
+    SML_REVISION_LOG = (
+        "application/vnd.openxmlformats-officedocument.spreadsheetml.revisionLog+xml"
+    )
+    SML_SHARED_STRINGS = (
+        "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedS"
+        "trings+xml"
+    )
+    SML_SHEET = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
+    SML_SHEET_MAIN = (
+        "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"
+    )
+    SML_SHEET_METADATA = (
+        "application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMe"
+        "tadata+xml"
+    )
+    SML_STYLES = (
+        "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"
+    )
+    SML_TABLE = "application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml"
+    SML_TABLE_SINGLE_CELLS = (
+        "application/vnd.openxmlformats-officedocument.spreadsheetml.tableSi"
+        "ngleCells+xml"
+    )
+    SML_TEMPLATE_MAIN = (
+        "application/vnd.openxmlformats-officedocument.spreadsheetml.templat"
+        "e.main+xml"
+    )
+    SML_USER_NAMES = (
+        "application/vnd.openxmlformats-officedocument.spreadsheetml.userNames+xml"
+    )
+    SML_VOLATILE_DEPENDENCIES = (
+        "application/vnd.openxmlformats-officedocument.spreadsheetml.volatil"
+        "eDependencies+xml"
+    )
+    SML_WORKSHEET = (
+        "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"
+    )
+    TIFF = "image/tiff"
+    WML_COMMENTS = (
+        "application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml"
+    )
+    WML_DOCUMENT = (
+        "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
+    )
+    WML_DOCUMENT_GLOSSARY = (
+        "application/vnd.openxmlformats-officedocument.wordprocessingml.docu"
+        "ment.glossary+xml"
+    )
+    WML_DOCUMENT_MAIN = (
+        "application/vnd.openxmlformats-officedocument.wordprocessingml.docu"
+        "ment.main+xml"
+    )
+    WML_ENDNOTES = (
+        "application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml"
+    )
+    WML_FONT_TABLE = (
+        "application/vnd.openxmlformats-officedocument.wordprocessingml.font"
+        "Table+xml"
+    )
+    WML_FOOTER = (
+        "application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml"
+    )
+    WML_FOOTNOTES = (
+        "application/vnd.openxmlformats-officedocument.wordprocessingml.foot"
+        "notes+xml"
+    )
+    WML_HEADER = (
+        "application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml"
+    )
+    WML_NUMBERING = (
+        "application/vnd.openxmlformats-officedocument.wordprocessingml.numb"
+        "ering+xml"
+    )
+    WML_PRINTER_SETTINGS = (
+        "application/vnd.openxmlformats-officedocument.wordprocessingml.prin"
+        "terSettings"
+    )
+    WML_SETTINGS = (
+        "application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml"
+    )
+    WML_STYLES = (
+        "application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml"
+    )
+    WML_WEB_SETTINGS = (
+        "application/vnd.openxmlformats-officedocument.wordprocessingml.webS"
+        "ettings+xml"
+    )
+    XML = "application/xml"
+    X_EMF = "image/x-emf"
+    X_FONTDATA = "application/x-fontdata"
+    X_FONT_TTF = "application/x-font-ttf"
+    X_WMF = "image/x-wmf"
+
+
+class NAMESPACE:
+    """Constant values for OPC XML namespaces."""
+
+    DML_WORDPROCESSING_DRAWING = (
+        "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"
+    )
+    OFC_RELATIONSHIPS = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+    )
+    OPC_RELATIONSHIPS = "http://schemas.openxmlformats.org/package/2006/relationships"
+    OPC_CONTENT_TYPES = "http://schemas.openxmlformats.org/package/2006/content-types"
+    WML_MAIN = "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
+
+
+class RELATIONSHIP_TARGET_MODE:
+    """Open XML relationship target modes."""
+
+    EXTERNAL = "External"
+    INTERNAL = "Internal"
+
+
+class RELATIONSHIP_TYPE:
+    AUDIO = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/audio"
+    A_F_CHUNK = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships/aFChunk"
+    )
+    CALC_CHAIN = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+        "/calcChain"
+    )
+    CERTIFICATE = (
+        "http://schemas.openxmlformats.org/package/2006/relationships/digita"
+        "l-signature/certificate"
+    )
+    CHART = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart"
+    CHARTSHEET = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+        "/chartsheet"
+    )
+    CHART_USER_SHAPES = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+        "/chartUserShapes"
+    )
+    COMMENTS = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+        "/comments"
+    )
+    COMMENT_AUTHORS = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+        "/commentAuthors"
+    )
+    CONNECTIONS = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+        "/connections"
+    )
+    CONTROL = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships/control"
+    )
+    CORE_PROPERTIES = (
+        "http://schemas.openxmlformats.org/package/2006/relationships/metada"
+        "ta/core-properties"
+    )
+    CUSTOM_PROPERTIES = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+        "/custom-properties"
+    )
+    CUSTOM_PROPERTY = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+        "/customProperty"
+    )
+    CUSTOM_XML = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+        "/customXml"
+    )
+    CUSTOM_XML_PROPS = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+        "/customXmlProps"
+    )
+    DIAGRAM_COLORS = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+        "/diagramColors"
+    )
+    DIAGRAM_DATA = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+        "/diagramData"
+    )
+    DIAGRAM_LAYOUT = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+        "/diagramLayout"
+    )
+    DIAGRAM_QUICK_STYLE = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+        "/diagramQuickStyle"
+    )
+    DIALOGSHEET = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+        "/dialogsheet"
+    )
+    DRAWING = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing"
+    )
+    ENDNOTES = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+        "/endnotes"
+    )
+    EXTENDED_PROPERTIES = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+        "/extended-properties"
+    )
+    EXTERNAL_LINK = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+        "/externalLink"
+    )
+    FONT = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/font"
+    FONT_TABLE = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+        "/fontTable"
+    )
+    FOOTER = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer"
+    )
+    FOOTNOTES = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+        "/footnotes"
+    )
+    GLOSSARY_DOCUMENT = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+        "/glossaryDocument"
+    )
+    HANDOUT_MASTER = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+        "/handoutMaster"
+    )
+    HEADER = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships/header"
+    )
+    HYPERLINK = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+        "/hyperlink"
+    )
+    IMAGE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"
+    NOTES_MASTER = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+        "/notesMaster"
+    )
+    NOTES_SLIDE = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+        "/notesSlide"
+    )
+    NUMBERING = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+        "/numbering"
+    )
+    OFFICE_DOCUMENT = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+        "/officeDocument"
+    )
+    OLE_OBJECT = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+        "/oleObject"
+    )
+    ORIGIN = (
+        "http://schemas.openxmlformats.org/package/2006/relationships/digita"
+        "l-signature/origin"
+    )
+    PACKAGE = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships/package"
+    )
+    PIVOT_CACHE_DEFINITION = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+        "/pivotCacheDefinition"
+    )
+    PIVOT_CACHE_RECORDS = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+        "/spreadsheetml/pivotCacheRecords"
+    )
+    PIVOT_TABLE = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+        "/pivotTable"
+    )
+    PRES_PROPS = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+        "/presProps"
+    )
+    PRINTER_SETTINGS = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+        "/printerSettings"
+    )
+    QUERY_TABLE = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+        "/queryTable"
+    )
+    REVISION_HEADERS = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+        "/revisionHeaders"
+    )
+    REVISION_LOG = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+        "/revisionLog"
+    )
+    SETTINGS = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+        "/settings"
+    )
+    SHARED_STRINGS = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+        "/sharedStrings"
+    )
+    SHEET_METADATA = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+        "/sheetMetadata"
+    )
+    SIGNATURE = (
+        "http://schemas.openxmlformats.org/package/2006/relationships/digita"
+        "l-signature/signature"
+    )
+    SLIDE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide"
+    SLIDE_LAYOUT = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+        "/slideLayout"
+    )
+    SLIDE_MASTER = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+        "/slideMaster"
+    )
+    SLIDE_UPDATE_INFO = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+        "/slideUpdateInfo"
+    )
+    STYLES = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles"
+    )
+    TABLE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/table"
+    TABLE_SINGLE_CELLS = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+        "/tableSingleCells"
+    )
+    TABLE_STYLES = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+        "/tableStyles"
+    )
+    TAGS = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/tags"
+    THEME = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme"
+    THEME_OVERRIDE = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+        "/themeOverride"
+    )
+    THUMBNAIL = (
+        "http://schemas.openxmlformats.org/package/2006/relationships/metada"
+        "ta/thumbnail"
+    )
+    USERNAMES = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+        "/usernames"
+    )
+    VIDEO = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/video"
+    VIEW_PROPS = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+        "/viewProps"
+    )
+    VML_DRAWING = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+        "/vmlDrawing"
+    )
+    VOLATILE_DEPENDENCIES = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+        "/volatileDependencies"
+    )
+    WEB_SETTINGS = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+        "/webSettings"
+    )
+    WORKSHEET_SOURCE = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+        "/worksheetSource"
+    )
+    XML_MAPS = (
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships/xmlMaps"
+    )
diff --git a/.venv/lib/python3.12/site-packages/docx/opc/coreprops.py b/.venv/lib/python3.12/site-packages/docx/opc/coreprops.py
new file mode 100644
index 00000000..c564550d
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/docx/opc/coreprops.py
@@ -0,0 +1,141 @@
+"""Provides CoreProperties, Dublin-Core attributes of the document.
+
+These are broadly-standardized attributes like author, last-modified, etc.
+"""
+
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
+
+from docx.oxml.coreprops import CT_CoreProperties
+
+if TYPE_CHECKING:
+    from docx.oxml.coreprops import CT_CoreProperties
+
+
+class CoreProperties:
+    """Corresponds to part named ``/docProps/core.xml``, containing the core document
+    properties for this document package."""
+
+    def __init__(self, element: CT_CoreProperties):
+        self._element = element
+
+    @property
+    def author(self):
+        return self._element.author_text
+
+    @author.setter
+    def author(self, value: str):
+        self._element.author_text = value
+
+    @property
+    def category(self):
+        return self._element.category_text
+
+    @category.setter
+    def category(self, value: str):
+        self._element.category_text = value
+
+    @property
+    def comments(self):
+        return self._element.comments_text
+
+    @comments.setter
+    def comments(self, value: str):
+        self._element.comments_text = value
+
+    @property
+    def content_status(self):
+        return self._element.contentStatus_text
+
+    @content_status.setter
+    def content_status(self, value: str):
+        self._element.contentStatus_text = value
+
+    @property
+    def created(self):
+        return self._element.created_datetime
+
+    @created.setter
+    def created(self, value):
+        self._element.created_datetime = value
+
+    @property
+    def identifier(self):
+        return self._element.identifier_text
+
+    @identifier.setter
+    def identifier(self, value: str):
+        self._element.identifier_text = value
+
+    @property
+    def keywords(self):
+        return self._element.keywords_text
+
+    @keywords.setter
+    def keywords(self, value: str):
+        self._element.keywords_text = value
+
+    @property
+    def language(self):
+        return self._element.language_text
+
+    @language.setter
+    def language(self, value: str):
+        self._element.language_text = value
+
+    @property
+    def last_modified_by(self):
+        return self._element.lastModifiedBy_text
+
+    @last_modified_by.setter
+    def last_modified_by(self, value: str):
+        self._element.lastModifiedBy_text = value
+
+    @property
+    def last_printed(self):
+        return self._element.lastPrinted_datetime
+
+    @last_printed.setter
+    def last_printed(self, value):
+        self._element.lastPrinted_datetime = value
+
+    @property
+    def modified(self):
+        return self._element.modified_datetime
+
+    @modified.setter
+    def modified(self, value):
+        self._element.modified_datetime = value
+
+    @property
+    def revision(self):
+        return self._element.revision_number
+
+    @revision.setter
+    def revision(self, value):
+        self._element.revision_number = value
+
+    @property
+    def subject(self):
+        return self._element.subject_text
+
+    @subject.setter
+    def subject(self, value: str):
+        self._element.subject_text = value
+
+    @property
+    def title(self):
+        return self._element.title_text
+
+    @title.setter
+    def title(self, value: str):
+        self._element.title_text = value
+
+    @property
+    def version(self):
+        return self._element.version_text
+
+    @version.setter
+    def version(self, value: str):
+        self._element.version_text = value
diff --git a/.venv/lib/python3.12/site-packages/docx/opc/exceptions.py b/.venv/lib/python3.12/site-packages/docx/opc/exceptions.py
new file mode 100644
index 00000000..c5583d30
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/docx/opc/exceptions.py
@@ -0,0 +1,12 @@
+"""Exceptions specific to python-opc.
+
+The base exception class is OpcError.
+"""
+
+
+class OpcError(Exception):
+    """Base error class for python-opc."""
+
+
+class PackageNotFoundError(OpcError):
+    """Raised when a package cannot be found at the specified path."""
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
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)
diff --git a/.venv/lib/python3.12/site-packages/docx/opc/packuri.py b/.venv/lib/python3.12/site-packages/docx/opc/packuri.py
new file mode 100644
index 00000000..fdbb67ed
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/docx/opc/packuri.py
@@ -0,0 +1,110 @@
+"""Provides the PackURI value type.
+
+Also some useful known pack URI strings such as PACKAGE_URI.
+"""
+
+from __future__ import annotations
+
+import posixpath
+import re
+
+
+class PackURI(str):
+    """Provides access to pack URI components such as the baseURI and the filename
+    slice.
+
+    Behaves as |str| otherwise.
+    """
+
+    _filename_re = re.compile("([a-zA-Z]+)([1-9][0-9]*)?")
+
+    def __new__(cls, pack_uri_str: str):
+        if pack_uri_str[0] != "/":
+            tmpl = "PackURI must begin with slash, got '%s'"
+            raise ValueError(tmpl % pack_uri_str)
+        return str.__new__(cls, pack_uri_str)
+
+    @staticmethod
+    def from_rel_ref(baseURI: str, relative_ref: str) -> PackURI:
+        """The absolute PackURI formed by translating `relative_ref` onto `baseURI`."""
+        joined_uri = posixpath.join(baseURI, relative_ref)
+        abs_uri = posixpath.abspath(joined_uri)
+        return PackURI(abs_uri)
+
+    @property
+    def baseURI(self) -> str:
+        """The base URI of this pack URI, the directory portion, roughly speaking.
+
+        E.g. ``'/ppt/slides'`` for ``'/ppt/slides/slide1.xml'``. For the package pseudo-
+        partname '/', baseURI is '/'.
+        """
+        return posixpath.split(self)[0]
+
+    @property
+    def ext(self) -> str:
+        """The extension portion of this pack URI, e.g. ``'xml'`` for ``'/word/document.xml'``.
+
+        Note the period is not included.
+        """
+        # raw_ext is either empty string or starts with period, e.g. '.xml'
+        raw_ext = posixpath.splitext(self)[1]
+        return raw_ext[1:] if raw_ext.startswith(".") else raw_ext
+
+    @property
+    def filename(self):
+        """The "filename" portion of this pack URI, e.g. ``'slide1.xml'`` for
+        ``'/ppt/slides/slide1.xml'``.
+
+        For the package pseudo-partname '/', filename is ''.
+        """
+        return posixpath.split(self)[1]
+
+    @property
+    def idx(self):
+        """Return partname index as integer for tuple partname or None for singleton
+        partname, e.g. ``21`` for ``'/ppt/slides/slide21.xml'`` and |None| for
+        ``'/ppt/presentation.xml'``."""
+        filename = self.filename
+        if not filename:
+            return None
+        name_part = posixpath.splitext(filename)[0]  # filename w/ext removed
+        match = self._filename_re.match(name_part)
+        if match is None:
+            return None
+        if match.group(2):
+            return int(match.group(2))
+        return None
+
+    @property
+    def membername(self):
+        """The pack URI with the leading slash stripped off, the form used as the Zip
+        file membername for the package item.
+
+        Returns '' for the package pseudo-partname '/'.
+        """
+        return self[1:]
+
+    def relative_ref(self, baseURI: str):
+        """Return string containing relative reference to package item from `baseURI`.
+
+        E.g. PackURI('/ppt/slideLayouts/slideLayout1.xml') would return
+        '../slideLayouts/slideLayout1.xml' for baseURI '/ppt/slides'.
+        """
+        # workaround for posixpath bug in 2.6, doesn't generate correct
+        # relative path when `start` (second) parameter is root ('/')
+        return self[1:] if baseURI == "/" else posixpath.relpath(self, baseURI)
+
+    @property
+    def rels_uri(self):
+        """The pack URI of the .rels part corresponding to the current pack URI.
+
+        Only produces sensible output if the pack URI is a partname or the package
+        pseudo-partname '/'.
+        """
+        rels_filename = "%s.rels" % self.filename
+        rels_uri_str = posixpath.join(self.baseURI, "_rels", rels_filename)
+        return PackURI(rels_uri_str)
+
+
+PACKAGE_URI = PackURI("/")
+CONTENT_TYPES_URI = PackURI("/[Content_Types].xml")
diff --git a/.venv/lib/python3.12/site-packages/docx/opc/part.py b/.venv/lib/python3.12/site-packages/docx/opc/part.py
new file mode 100644
index 00000000..cbb4ab55
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/docx/opc/part.py
@@ -0,0 +1,247 @@
+# pyright: reportImportCycles=false
+
+"""Open Packaging Convention (OPC) objects related to package parts."""
+
+from __future__ import annotations
+
+from typing import TYPE_CHECKING, Callable, Type, cast
+
+from docx.opc.oxml import serialize_part_xml
+from docx.opc.packuri import PackURI
+from docx.opc.rel import Relationships
+from docx.opc.shared import cls_method_fn
+from docx.oxml.parser import parse_xml
+from docx.shared import lazyproperty
+
+if TYPE_CHECKING:
+    from docx.oxml.xmlchemy import BaseOxmlElement
+    from docx.package import Package
+
+
+class Part:
+    """Base class for package parts.
+
+    Provides common properties and methods, but intended to be subclassed in client code
+    to implement specific part behaviors.
+    """
+
+    def __init__(
+        self,
+        partname: PackURI,
+        content_type: str,
+        blob: bytes | None = None,
+        package: Package | None = None,
+    ):
+        super(Part, self).__init__()
+        self._partname = partname
+        self._content_type = content_type
+        self._blob = blob
+        self._package = package
+
+    def after_unmarshal(self):
+        """Entry point for post-unmarshaling processing, for example to parse the part
+        XML.
+
+        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
+
+    def before_marshal(self):
+        """Entry point for pre-serialization processing, for example to finalize part
+        naming if necessary.
+
+        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 blob(self) -> bytes:
+        """Contents of this package part as a sequence of bytes.
+
+        May be text or binary. Intended to be overridden by subclasses. Default behavior
+        is to return load blob.
+        """
+        return self._blob or b""
+
+    @property
+    def content_type(self):
+        """Content type of this part."""
+        return self._content_type
+
+    def drop_rel(self, rId: str):
+        """Remove the relationship identified by `rId` if its reference count is less
+        than 2.
+
+        Relationships with a reference count of 0 are implicit relationships.
+        """
+        if self._rel_ref_count(rId) < 2:
+            del self.rels[rId]
+
+    @classmethod
+    def load(cls, partname: PackURI, content_type: str, blob: bytes, package: Package):
+        return cls(partname, content_type, blob, package)
+
+    def load_rel(self, reltype: str, target: Part | str, rId: str, is_external: bool = False):
+        """Return newly added |_Relationship| instance of `reltype`.
+
+        The new relationship relates the `target` part to this part 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 a part when manipulating a part.
+        """
+        return self.rels.add_relationship(reltype, target, rId, is_external)
+
+    @property
+    def package(self):
+        """|OpcPackage| instance this part belongs to."""
+        return self._package
+
+    @property
+    def partname(self):
+        """|PackURI| instance holding partname of this part, e.g.
+        '/ppt/slides/slide1.xml'."""
+        return self._partname
+
+    @partname.setter
+    def partname(self, partname: str):
+        if not isinstance(partname, PackURI):
+            tmpl = "partname must be instance of PackURI, got '%s'"
+            raise TypeError(tmpl % type(partname).__name__)
+        self._partname = partname
+
+    def part_related_by(self, reltype: str) -> Part:
+        """Return part to which this part has a relationship of `reltype`.
+
+        Raises |KeyError| if no such relationship is found and |ValueError| if more than
+        one such relationship is found. Provides ability to resolve implicitly related
+        part, such as Slide -> SlideLayout.
+        """
+        return self.rels.part_with_reltype(reltype)
+
+    def relate_to(self, target: Part | str, reltype: str, is_external: bool = False) -> str:
+        """Return rId key of relationship of `reltype` to `target`.
+
+        The returned `rId` is from an existing relationship if there is one, otherwise a
+        new relationship is created.
+        """
+        if is_external:
+            return self.rels.get_or_add_ext_rel(reltype, cast(str, target))
+        else:
+            rel = self.rels.get_or_add(reltype, cast(Part, target))
+            return rel.rId
+
+    @property
+    def related_parts(self):
+        """Dictionary mapping related parts by rId, so child objects can resolve
+        explicit relationships present in the part XML, e.g. sldIdLst to a specific
+        |Slide| instance."""
+        return self.rels.related_parts
+
+    @lazyproperty
+    def rels(self):
+        """|Relationships| instance holding the relationships for this part."""
+        # -- prevent breakage in `python-docx-template` by retaining legacy `._rels` attribute --
+        self._rels = Relationships(self._partname.baseURI)
+        return self._rels
+
+    def target_ref(self, rId: str) -> str:
+        """Return URL contained in target ref of relationship identified by `rId`."""
+        rel = self.rels[rId]
+        return rel.target_ref
+
+    def _rel_ref_count(self, rId: str) -> int:
+        """Return the count of references in this part to the relationship identified by `rId`.
+
+        Only an XML part can contain references, so this is 0 for `Part`.
+        """
+        return 0
+
+
+class PartFactory:
+    """Provides a way for client code to specify a subclass of |Part| to be constructed
+    by |Unmarshaller| based on its content type and/or a custom callable.
+
+    Setting ``PartFactory.part_class_selector`` to a callable object will cause that
+    object to be called with the parameters ``content_type, reltype``, once for each
+    part in the package. If the callable returns an object, it is used as the class for
+    that part. If it returns |None|, part class selection falls back to the content type
+    map defined in ``PartFactory.part_type_for``. If no class is returned from either of
+    these, the class contained in ``PartFactory.default_part_type`` is used to construct
+    the part, which is by default ``opc.package.Part``.
+    """
+
+    part_class_selector: Callable[[str, str], Type[Part] | None] | None
+    part_type_for: dict[str, Type[Part]] = {}
+    default_part_type = Part
+
+    def __new__(
+        cls,
+        partname: PackURI,
+        content_type: str,
+        reltype: str,
+        blob: bytes,
+        package: Package,
+    ):
+        PartClass: Type[Part] | None = None
+        if cls.part_class_selector is not None:
+            part_class_selector = cls_method_fn(cls, "part_class_selector")
+            PartClass = part_class_selector(content_type, reltype)
+        if PartClass is None:
+            PartClass = cls._part_cls_for(content_type)
+        return PartClass.load(partname, content_type, blob, package)
+
+    @classmethod
+    def _part_cls_for(cls, content_type: str):
+        """Return the custom part class registered for `content_type`, or the default
+        part class if no custom class is registered for `content_type`."""
+        if content_type in cls.part_type_for:
+            return cls.part_type_for[content_type]
+        return cls.default_part_type
+
+
+class XmlPart(Part):
+    """Base class for package parts containing an XML payload, which is most of them.
+
+    Provides additional methods to the |Part| base class that take care of parsing and
+    reserializing the XML payload and managing relationships to other parts.
+    """
+
+    def __init__(
+        self, partname: PackURI, content_type: str, element: BaseOxmlElement, package: Package
+    ):
+        super(XmlPart, self).__init__(partname, content_type, package=package)
+        self._element = element
+
+    @property
+    def blob(self):
+        return serialize_part_xml(self._element)
+
+    @property
+    def element(self):
+        """The root XML element of this XML part."""
+        return self._element
+
+    @classmethod
+    def load(cls, partname: PackURI, content_type: str, blob: bytes, package: Package):
+        element = parse_xml(blob)
+        return cls(partname, content_type, element, package)
+
+    @property
+    def part(self):
+        """Part of the parent protocol, "children" of the document will not know the
+        part that contains them so must ask their parent object.
+
+        That chain of delegation ends here for child objects.
+        """
+        return self
+
+    def _rel_ref_count(self, rId: str) -> int:
+        """Return the count of references in this part's XML to the relationship
+        identified by `rId`."""
+        rIds = cast("list[str]", self._element.xpath("//@r:id"))
+        return len([_rId for _rId in rIds if _rId == rId])
diff --git a/.venv/lib/python3.12/site-packages/docx/opc/parts/__init__.py b/.venv/lib/python3.12/site-packages/docx/opc/parts/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/docx/opc/parts/__init__.py
diff --git a/.venv/lib/python3.12/site-packages/docx/opc/parts/coreprops.py b/.venv/lib/python3.12/site-packages/docx/opc/parts/coreprops.py
new file mode 100644
index 00000000..fda01121
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/docx/opc/parts/coreprops.py
@@ -0,0 +1,48 @@
+"""Core properties part, corresponds to ``/docProps/core.xml`` part in package."""
+
+from __future__ import annotations
+
+import datetime as dt
+from typing import TYPE_CHECKING
+
+from docx.opc.constants import CONTENT_TYPE as CT
+from docx.opc.coreprops import CoreProperties
+from docx.opc.packuri import PackURI
+from docx.opc.part import XmlPart
+from docx.oxml.coreprops import CT_CoreProperties
+
+if TYPE_CHECKING:
+    from docx.opc.package import OpcPackage
+
+
+class CorePropertiesPart(XmlPart):
+    """Corresponds to part named ``/docProps/core.xml``.
+
+    The "core" is short for "Dublin Core" and contains document metadata relatively common across
+    documents of all types, not just DOCX.
+    """
+
+    @classmethod
+    def default(cls, package: OpcPackage):
+        """Return a new |CorePropertiesPart| object initialized with default values for
+        its base properties."""
+        core_properties_part = cls._new(package)
+        core_properties = core_properties_part.core_properties
+        core_properties.title = "Word Document"
+        core_properties.last_modified_by = "python-docx"
+        core_properties.revision = 1
+        core_properties.modified = dt.datetime.now(dt.timezone.utc)
+        return core_properties_part
+
+    @property
+    def core_properties(self):
+        """A |CoreProperties| object providing read/write access to the core properties
+        contained in this core properties part."""
+        return CoreProperties(self.element)
+
+    @classmethod
+    def _new(cls, package: OpcPackage) -> CorePropertiesPart:
+        partname = PackURI("/docProps/core.xml")
+        content_type = CT.OPC_CORE_PROPERTIES
+        coreProperties = CT_CoreProperties.new()
+        return CorePropertiesPart(partname, content_type, coreProperties, package)
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)
diff --git a/.venv/lib/python3.12/site-packages/docx/opc/pkgreader.py b/.venv/lib/python3.12/site-packages/docx/opc/pkgreader.py
new file mode 100644
index 00000000..f00e7b5f
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/docx/opc/pkgreader.py
@@ -0,0 +1,258 @@
+"""Low-level, read-only API to a serialized Open Packaging Convention (OPC) package."""
+
+from docx.opc.constants import RELATIONSHIP_TARGET_MODE as RTM
+from docx.opc.oxml import parse_xml
+from docx.opc.packuri import PACKAGE_URI, PackURI
+from docx.opc.phys_pkg import PhysPkgReader
+from docx.opc.shared import CaseInsensitiveDict
+
+
+class PackageReader:
+    """Provides access to the contents of a zip-format OPC package via its
+    :attr:`serialized_parts` and :attr:`pkg_srels` attributes."""
+
+    def __init__(self, content_types, pkg_srels, sparts):
+        super(PackageReader, self).__init__()
+        self._pkg_srels = pkg_srels
+        self._sparts = sparts
+
+    @staticmethod
+    def from_file(pkg_file):
+        """Return a |PackageReader| instance loaded with contents of `pkg_file`."""
+        phys_reader = PhysPkgReader(pkg_file)
+        content_types = _ContentTypeMap.from_xml(phys_reader.content_types_xml)
+        pkg_srels = PackageReader._srels_for(phys_reader, PACKAGE_URI)
+        sparts = PackageReader._load_serialized_parts(
+            phys_reader, pkg_srels, content_types
+        )
+        phys_reader.close()
+        return PackageReader(content_types, pkg_srels, sparts)
+
+    def iter_sparts(self):
+        """Generate a 4-tuple `(partname, content_type, reltype, blob)` for each of the
+        serialized parts in the package."""
+        for s in self._sparts:
+            yield (s.partname, s.content_type, s.reltype, s.blob)
+
+    def iter_srels(self):
+        """Generate a 2-tuple `(source_uri, srel)` for each of the relationships in the
+        package."""
+        for srel in self._pkg_srels:
+            yield (PACKAGE_URI, srel)
+        for spart in self._sparts:
+            for srel in spart.srels:
+                yield (spart.partname, srel)
+
+    @staticmethod
+    def _load_serialized_parts(phys_reader, pkg_srels, content_types):
+        """Return a list of |_SerializedPart| instances corresponding to the parts in
+        `phys_reader` accessible by walking the relationship graph starting with
+        `pkg_srels`."""
+        sparts = []
+        part_walker = PackageReader._walk_phys_parts(phys_reader, pkg_srels)
+        for partname, blob, reltype, srels in part_walker:
+            content_type = content_types[partname]
+            spart = _SerializedPart(partname, content_type, reltype, blob, srels)
+            sparts.append(spart)
+        return tuple(sparts)
+
+    @staticmethod
+    def _srels_for(phys_reader, source_uri):
+        """Return |_SerializedRelationships| instance populated with relationships for
+        source identified by `source_uri`."""
+        rels_xml = phys_reader.rels_xml_for(source_uri)
+        return _SerializedRelationships.load_from_xml(source_uri.baseURI, rels_xml)
+
+    @staticmethod
+    def _walk_phys_parts(phys_reader, srels, visited_partnames=None):
+        """Generate a 4-tuple `(partname, blob, reltype, srels)` for each of the parts
+        in `phys_reader` by walking the relationship graph rooted at srels."""
+        if visited_partnames is None:
+            visited_partnames = []
+        for srel in srels:
+            if srel.is_external:
+                continue
+            partname = srel.target_partname
+            if partname in visited_partnames:
+                continue
+            visited_partnames.append(partname)
+            reltype = srel.reltype
+            part_srels = PackageReader._srels_for(phys_reader, partname)
+            blob = phys_reader.blob_for(partname)
+            yield (partname, blob, reltype, part_srels)
+            next_walker = PackageReader._walk_phys_parts(
+                phys_reader, part_srels, visited_partnames
+            )
+            for partname, blob, reltype, srels in next_walker:
+                yield (partname, blob, reltype, srels)
+
+
+class _ContentTypeMap:
+    """Value type providing dictionary semantics for looking up content type by part
+    name, e.g. ``content_type = cti['/ppt/presentation.xml']``."""
+
+    def __init__(self):
+        super(_ContentTypeMap, self).__init__()
+        self._overrides = CaseInsensitiveDict()
+        self._defaults = CaseInsensitiveDict()
+
+    def __getitem__(self, partname):
+        """Return content type for part identified by `partname`."""
+        if not isinstance(partname, PackURI):
+            tmpl = "_ContentTypeMap key must be <type 'PackURI'>, got %s"
+            raise KeyError(tmpl % type(partname))
+        if partname in self._overrides:
+            return self._overrides[partname]
+        if partname.ext in self._defaults:
+            return self._defaults[partname.ext]
+        tmpl = "no content type for partname '%s' in [Content_Types].xml"
+        raise KeyError(tmpl % partname)
+
+    @staticmethod
+    def from_xml(content_types_xml):
+        """Return a new |_ContentTypeMap| instance populated with the contents of
+        `content_types_xml`."""
+        types_elm = parse_xml(content_types_xml)
+        ct_map = _ContentTypeMap()
+        for o in types_elm.overrides:
+            ct_map._add_override(o.partname, o.content_type)
+        for d in types_elm.defaults:
+            ct_map._add_default(d.extension, d.content_type)
+        return ct_map
+
+    def _add_default(self, extension, content_type):
+        """Add the default mapping of `extension` to `content_type` to this content type
+        mapping."""
+        self._defaults[extension] = content_type
+
+    def _add_override(self, partname, content_type):
+        """Add the default mapping of `partname` to `content_type` to this content type
+        mapping."""
+        self._overrides[partname] = content_type
+
+
+class _SerializedPart:
+    """Value object for an OPC package part.
+
+    Provides access to the partname, content type, blob, and serialized relationships
+    for the part.
+    """
+
+    def __init__(self, partname, content_type, reltype, blob, srels):
+        super(_SerializedPart, self).__init__()
+        self._partname = partname
+        self._content_type = content_type
+        self._reltype = reltype
+        self._blob = blob
+        self._srels = srels
+
+    @property
+    def partname(self):
+        return self._partname
+
+    @property
+    def content_type(self):
+        return self._content_type
+
+    @property
+    def blob(self):
+        return self._blob
+
+    @property
+    def reltype(self):
+        """The referring relationship type of this part."""
+        return self._reltype
+
+    @property
+    def srels(self):
+        return self._srels
+
+
+class _SerializedRelationship:
+    """Value object representing a serialized relationship in an OPC package.
+
+    Serialized, in this case, means any target part is referred to via its partname
+    rather than a direct link to an in-memory |Part| object.
+    """
+
+    def __init__(self, baseURI, rel_elm):
+        super(_SerializedRelationship, self).__init__()
+        self._baseURI = baseURI
+        self._rId = rel_elm.rId
+        self._reltype = rel_elm.reltype
+        self._target_mode = rel_elm.target_mode
+        self._target_ref = rel_elm.target_ref
+
+    @property
+    def is_external(self):
+        """True if target_mode is ``RTM.EXTERNAL``"""
+        return self._target_mode == RTM.EXTERNAL
+
+    @property
+    def reltype(self):
+        """Relationship type, like ``RT.OFFICE_DOCUMENT``"""
+        return self._reltype
+
+    @property
+    def rId(self):
+        """Relationship id, like 'rId9', corresponds to the ``Id`` attribute on the
+        ``CT_Relationship`` element."""
+        return self._rId
+
+    @property
+    def target_mode(self):
+        """String in ``TargetMode`` attribute of ``CT_Relationship`` element, one of
+        ``RTM.INTERNAL`` or ``RTM.EXTERNAL``."""
+        return self._target_mode
+
+    @property
+    def target_ref(self):
+        """String in ``Target`` attribute of ``CT_Relationship`` element, a relative
+        part reference for internal target mode or an arbitrary URI, e.g. an HTTP URL,
+        for external target mode."""
+        return self._target_ref
+
+    @property
+    def target_partname(self):
+        """|PackURI| instance containing partname targeted by this relationship.
+
+        Raises ``ValueError`` on reference if target_mode is ``'External'``. Use
+        :attr:`target_mode` to check before referencing.
+        """
+        if self.is_external:
+            msg = (
+                "target_partname attribute on Relationship is undefined w"
+                'here TargetMode == "External"'
+            )
+            raise ValueError(msg)
+        # lazy-load _target_partname attribute
+        if not hasattr(self, "_target_partname"):
+            self._target_partname = PackURI.from_rel_ref(self._baseURI, self.target_ref)
+        return self._target_partname
+
+
+class _SerializedRelationships:
+    """Read-only sequence of |_SerializedRelationship| instances corresponding to the
+    relationships item XML passed to constructor."""
+
+    def __init__(self):
+        super(_SerializedRelationships, self).__init__()
+        self._srels = []
+
+    def __iter__(self):
+        """Support iteration, e.g. 'for x in srels:'."""
+        return self._srels.__iter__()
+
+    @staticmethod
+    def load_from_xml(baseURI, rels_item_xml):
+        """Return |_SerializedRelationships| instance loaded with the relationships
+        contained in `rels_item_xml`.
+
+        Returns an empty collection if `rels_item_xml` is |None|.
+        """
+        srels = _SerializedRelationships()
+        if rels_item_xml is not None:
+            rels_elm = parse_xml(rels_item_xml)
+            for rel_elm in rels_elm.Relationship_lst:
+                srels._srels.append(_SerializedRelationship(baseURI, rel_elm))
+        return srels
diff --git a/.venv/lib/python3.12/site-packages/docx/opc/pkgwriter.py b/.venv/lib/python3.12/site-packages/docx/opc/pkgwriter.py
new file mode 100644
index 00000000..e6351697
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/docx/opc/pkgwriter.py
@@ -0,0 +1,115 @@
+"""Provides low-level, write-only API to serialized (OPC) package.
+
+OPC stands for Open Packaging Convention. This is e, essentially an implementation of
+OpcPackage.save().
+"""
+
+from __future__ import annotations
+
+from typing import TYPE_CHECKING, Iterable
+
+from docx.opc.constants import CONTENT_TYPE as CT
+from docx.opc.oxml import CT_Types, serialize_part_xml
+from docx.opc.packuri import CONTENT_TYPES_URI, PACKAGE_URI
+from docx.opc.phys_pkg import PhysPkgWriter
+from docx.opc.shared import CaseInsensitiveDict
+from docx.opc.spec import default_content_types
+
+if TYPE_CHECKING:
+    from docx.opc.part import Part
+
+
+class PackageWriter:
+    """Writes a zip-format OPC package to `pkg_file`, where `pkg_file` can be either a
+    path to a zip file (a string) or a file-like object.
+
+    Its single API method, :meth:`write`, is static, so this class is not intended to be
+    instantiated.
+    """
+
+    @staticmethod
+    def write(pkg_file, pkg_rels, parts):
+        """Write a physical package (.pptx file) to `pkg_file` containing `pkg_rels` and
+        `parts` and a content types stream based on the content types of the parts."""
+        phys_writer = PhysPkgWriter(pkg_file)
+        PackageWriter._write_content_types_stream(phys_writer, parts)
+        PackageWriter._write_pkg_rels(phys_writer, pkg_rels)
+        PackageWriter._write_parts(phys_writer, parts)
+        phys_writer.close()
+
+    @staticmethod
+    def _write_content_types_stream(phys_writer, parts):
+        """Write ``[Content_Types].xml`` part to the physical package with an
+        appropriate content type lookup target for each part in `parts`."""
+        cti = _ContentTypesItem.from_parts(parts)
+        phys_writer.write(CONTENT_TYPES_URI, cti.blob)
+
+    @staticmethod
+    def _write_parts(phys_writer: PhysPkgWriter, parts: Iterable[Part]):
+        """Write the blob of each part in `parts` to the package, along with a rels item
+        for its relationships if and only if it has any."""
+        for part in parts:
+            phys_writer.write(part.partname, part.blob)
+            if len(part.rels):
+                phys_writer.write(part.partname.rels_uri, part.rels.xml)
+
+    @staticmethod
+    def _write_pkg_rels(phys_writer, pkg_rels):
+        """Write the XML rels item for `pkg_rels` ('/_rels/.rels') to the package."""
+        phys_writer.write(PACKAGE_URI.rels_uri, pkg_rels.xml)
+
+
+class _ContentTypesItem:
+    """Service class that composes a content types item ([Content_Types].xml) based on a
+    list of parts.
+
+    Not meant to be instantiated directly, its single interface method is xml_for(),
+    e.g. ``_ContentTypesItem.xml_for(parts)``.
+    """
+
+    def __init__(self):
+        self._defaults = CaseInsensitiveDict()
+        self._overrides = {}
+
+    @property
+    def blob(self):
+        """Return XML form of this content types item, suitable for storage as
+        ``[Content_Types].xml`` in an OPC package."""
+        return serialize_part_xml(self._element)
+
+    @classmethod
+    def from_parts(cls, parts):
+        """Return content types XML mapping each part in `parts` to the appropriate
+        content type and suitable for storage as ``[Content_Types].xml`` in an OPC
+        package."""
+        cti = cls()
+        cti._defaults["rels"] = CT.OPC_RELATIONSHIPS
+        cti._defaults["xml"] = CT.XML
+        for part in parts:
+            cti._add_content_type(part.partname, part.content_type)
+        return cti
+
+    def _add_content_type(self, partname, content_type):
+        """Add a content type for the part with `partname` and `content_type`, using a
+        default or override as appropriate."""
+        ext = partname.ext
+        if (ext.lower(), content_type) in default_content_types:
+            self._defaults[ext] = content_type
+        else:
+            self._overrides[partname] = content_type
+
+    @property
+    def _element(self):
+        """Return XML form of this content types item, suitable for storage as
+        ``[Content_Types].xml`` in an OPC package.
+
+        Although the sequence of elements is not strictly significant, as an aid to
+        testing and readability Default elements are sorted by extension and Override
+        elements are sorted by partname.
+        """
+        _types_elm = CT_Types.new()
+        for ext in sorted(self._defaults.keys()):
+            _types_elm.add_default(ext, self._defaults[ext])
+        for partname in sorted(self._overrides.keys()):
+            _types_elm.add_override(partname, self._overrides[partname])
+        return _types_elm
diff --git a/.venv/lib/python3.12/site-packages/docx/opc/rel.py b/.venv/lib/python3.12/site-packages/docx/opc/rel.py
new file mode 100644
index 00000000..47e8860d
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/docx/opc/rel.py
@@ -0,0 +1,155 @@
+"""Relationship-related objects."""
+
+from __future__ import annotations
+
+from typing import TYPE_CHECKING, Any, Dict, cast
+
+from docx.opc.oxml import CT_Relationships
+
+if TYPE_CHECKING:
+    from docx.opc.part import Part
+
+
+class Relationships(Dict[str, "_Relationship"]):
+    """Collection object for |_Relationship| instances, having list semantics."""
+
+    def __init__(self, baseURI: str):
+        super(Relationships, self).__init__()
+        self._baseURI = baseURI
+        self._target_parts_by_rId: dict[str, Any] = {}
+
+    def add_relationship(
+        self, reltype: str, target: Part | str, rId: str, is_external: bool = False
+    ) -> "_Relationship":
+        """Return a newly added |_Relationship| instance."""
+        rel = _Relationship(rId, reltype, target, self._baseURI, is_external)
+        self[rId] = rel
+        if not is_external:
+            self._target_parts_by_rId[rId] = target
+        return rel
+
+    def get_or_add(self, reltype: str, target_part: Part) -> _Relationship:
+        """Return relationship of `reltype` to `target_part`, newly added if not already
+        present in collection."""
+        rel = self._get_matching(reltype, target_part)
+        if rel is None:
+            rId = self._next_rId
+            rel = self.add_relationship(reltype, target_part, rId)
+        return rel
+
+    def get_or_add_ext_rel(self, reltype: str, target_ref: str) -> str:
+        """Return rId of external relationship of `reltype` to `target_ref`, newly added
+        if not already present in collection."""
+        rel = self._get_matching(reltype, target_ref, is_external=True)
+        if rel is None:
+            rId = self._next_rId
+            rel = self.add_relationship(reltype, target_ref, rId, is_external=True)
+        return rel.rId
+
+    def part_with_reltype(self, reltype: str) -> Part:
+        """Return target part of rel with matching `reltype`, raising |KeyError| if not
+        found and |ValueError| if more than one matching relationship is found."""
+        rel = self._get_rel_of_type(reltype)
+        return rel.target_part
+
+    @property
+    def related_parts(self):
+        """Dict mapping rIds to target parts for all the internal relationships in the
+        collection."""
+        return self._target_parts_by_rId
+
+    @property
+    def xml(self) -> str:
+        """Serialize this relationship collection into XML suitable for storage as a
+        .rels file in an OPC package."""
+        rels_elm = CT_Relationships.new()
+        for rel in self.values():
+            rels_elm.add_rel(rel.rId, rel.reltype, rel.target_ref, rel.is_external)
+        return rels_elm.xml
+
+    def _get_matching(
+        self, reltype: str, target: Part | str, is_external: bool = False
+    ) -> _Relationship | None:
+        """Return relationship of matching `reltype`, `target`, and `is_external` from
+        collection, or None if not found."""
+
+        def matches(rel: _Relationship, reltype: str, target: Part | str, is_external: bool):
+            if rel.reltype != reltype:
+                return False
+            if rel.is_external != is_external:
+                return False
+            rel_target = rel.target_ref if rel.is_external else rel.target_part
+            if rel_target != target:
+                return False
+            return True
+
+        for rel in self.values():
+            if matches(rel, reltype, target, is_external):
+                return rel
+        return None
+
+    def _get_rel_of_type(self, reltype: str):
+        """Return single relationship of type `reltype` from the collection.
+
+        Raises |KeyError| if no matching relationship is found. Raises |ValueError| if
+        more than one matching relationship is found.
+        """
+        matching = [rel for rel in self.values() if rel.reltype == reltype]
+        if len(matching) == 0:
+            tmpl = "no relationship of type '%s' in collection"
+            raise KeyError(tmpl % reltype)
+        if len(matching) > 1:
+            tmpl = "multiple relationships of type '%s' in collection"
+            raise ValueError(tmpl % reltype)
+        return matching[0]
+
+    @property
+    def _next_rId(self) -> str:  # pyright: ignore[reportReturnType]
+        """Next available rId in collection, starting from 'rId1' and making use of any
+        gaps in numbering, e.g. 'rId2' for rIds ['rId1', 'rId3']."""
+        for n in range(1, len(self) + 2):
+            rId_candidate = "rId%d" % n  # like 'rId19'
+            if rId_candidate not in self:
+                return rId_candidate
+
+
+class _Relationship:
+    """Value object for relationship to part."""
+
+    def __init__(
+        self, rId: str, reltype: str, target: Part | str, baseURI: str, external: bool = False
+    ):
+        super(_Relationship, self).__init__()
+        self._rId = rId
+        self._reltype = reltype
+        self._target = target
+        self._baseURI = baseURI
+        self._is_external = bool(external)
+
+    @property
+    def is_external(self) -> bool:
+        return self._is_external
+
+    @property
+    def reltype(self) -> str:
+        return self._reltype
+
+    @property
+    def rId(self) -> str:
+        return self._rId
+
+    @property
+    def target_part(self) -> Part:
+        if self._is_external:
+            raise ValueError(
+                "target_part property on _Relationship is undef" "ined when target mode is External"
+            )
+        return cast("Part", self._target)
+
+    @property
+    def target_ref(self) -> str:
+        if self._is_external:
+            return cast(str, self._target)
+        else:
+            target = cast("Part", self._target)
+            return target.partname.relative_ref(self._baseURI)
diff --git a/.venv/lib/python3.12/site-packages/docx/opc/shared.py b/.venv/lib/python3.12/site-packages/docx/opc/shared.py
new file mode 100644
index 00000000..9d4c0a6d
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/docx/opc/shared.py
@@ -0,0 +1,31 @@
+"""Objects shared by opc modules."""
+
+from __future__ import annotations
+
+from typing import Any, Dict, TypeVar
+
+_T = TypeVar("_T")
+
+
+class CaseInsensitiveDict(Dict[str, Any]):
+    """Mapping type that behaves like dict except that it matches without respect to the
+    case of the key.
+
+    E.g. cid['A'] == cid['a']. Note this is not general-purpose, just complete enough to
+    satisfy opc package needs. It assumes str keys, and that it is created empty; keys
+    passed in constructor are not accounted for
+    """
+
+    def __contains__(self, key):
+        return super(CaseInsensitiveDict, self).__contains__(key.lower())
+
+    def __getitem__(self, key):
+        return super(CaseInsensitiveDict, self).__getitem__(key.lower())
+
+    def __setitem__(self, key, value):
+        return super(CaseInsensitiveDict, self).__setitem__(key.lower(), value)
+
+
+def cls_method_fn(cls: type, method_name: str):
+    """Return method of `cls` having `method_name`."""
+    return getattr(cls, method_name)
diff --git a/.venv/lib/python3.12/site-packages/docx/opc/spec.py b/.venv/lib/python3.12/site-packages/docx/opc/spec.py
new file mode 100644
index 00000000..011a4825
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/docx/opc/spec.py
@@ -0,0 +1,24 @@
+"""Provides mappings that embody aspects of the Open XML spec ISO/IEC 29500."""
+
+from docx.opc.constants import CONTENT_TYPE as CT
+
+default_content_types = (
+    ("bin", CT.PML_PRINTER_SETTINGS),
+    ("bin", CT.SML_PRINTER_SETTINGS),
+    ("bin", CT.WML_PRINTER_SETTINGS),
+    ("bmp", CT.BMP),
+    ("emf", CT.X_EMF),
+    ("fntdata", CT.X_FONTDATA),
+    ("gif", CT.GIF),
+    ("jpe", CT.JPEG),
+    ("jpeg", CT.JPEG),
+    ("jpg", CT.JPEG),
+    ("png", CT.PNG),
+    ("rels", CT.OPC_RELATIONSHIPS),
+    ("tif", CT.TIFF),
+    ("tiff", CT.TIFF),
+    ("wdp", CT.MS_PHOTO),
+    ("wmf", CT.X_WMF),
+    ("xlsx", CT.SML_SHEET),
+    ("xml", CT.XML),
+)