docx_plus.core.parts¶
Package part / relationship plumbing for separate OOXML parts. v0.2
capabilities (comments/, notes/) live in their own parts under
/word/comments.xml, /word/footnotes.xml, and /word/endnotes.xml,
each of which may be absent from a fresh document. get_or_create_part
is the single entry point that returns the part and its parsed XML root,
fabricating both if missing.
Internal XmlPart subclasses for footnote and endnote content types are
registered with PartFactory.part_type_for at import time so existing
documents round-trip with parsed .element rather than raw blobs.
Architecture walkthrough: Separate OOXML parts.
docx_plus.core.parts ¶
Package part / relationship helpers for separate OOXML parts.
v0.1 capabilities (styles, fields, controls, protection) mutated only the
main document part and settings.xml — both already present in every
docx. v0.2 introduces capabilities backed by separate OOXML parts that
may not exist in a fresh document:
/word/comments.xml(relationship :data:RT.COMMENTS)/word/footnotes.xml(relationship :data:RT.FOOTNOTES)/word/endnotes.xml(relationship :data:RT.ENDNOTES)/word/commentsExtended.xml(relationship :data:RT_COMMENTS_EXTENDED) — comment threading, added in v0.4/word/commentsIds.xml(relationship :data:RT_COMMENTS_IDS) and/word/people.xml(relationship :data:RT_PEOPLE) — durable comment ids and author presence, added in v0.5/word/numbering.xml(relationship :data:RT.NUMBERING) — list definitions, added in v0.5
This module provides a single :func:get_or_create_part helper that the
comments, notes, and numbering packages use to look up an
existing part or fabricate a fresh one with an empty default root.
python-docx already registers CommentsPart with
PartFactory.part_type_for[CT.WML_COMMENTS] — and NumberingPart
with CT.WML_NUMBERING — so existing comments and numbering parts
deserialize with a parsed .element. It does not register
footnote / endnote / commentsExtended / commentsIds / people part
classes, so this module installs minimal
:class:~docx.opc.part.XmlPart subclasses for those content types at
import time. Without that registration a round-tripped document with
existing footnotes would surface them as raw blobs.
Numbering is the one part here that :func:get_or_create_part must own
rather than delegating to python-docx: DocumentPart.numbering_part
fabricates through NumberingPart.new(), which is an unimplemented
stub that raises NotImplementedError, so it works only for documents
that already have the part.
SPEC §2 lists the part / relationship plumbing as a v0.2 responsibility.
COMMENTS_SPEC
module-attribute
¶
COMMENTS_SPEC = PartSpec(
partname="/word/comments.xml",
content_type=WML_COMMENTS,
relationship_type=COMMENTS,
root_xml=_comments_root(),
)
FOOTNOTES_SPEC
module-attribute
¶
FOOTNOTES_SPEC = PartSpec(
partname="/word/footnotes.xml",
content_type=WML_FOOTNOTES,
relationship_type=FOOTNOTES,
root_xml=_notes_root_with_separators("footnotes", "footnote", "separator"),
)
ENDNOTES_SPEC
module-attribute
¶
ENDNOTES_SPEC = PartSpec(
partname="/word/endnotes.xml",
content_type=WML_ENDNOTES,
relationship_type=ENDNOTES,
root_xml=_notes_root_with_separators("endnotes", "endnote", "separator"),
)
PartSpec
dataclass
¶
Identification for an OOXML part looked up or fabricated as a unit.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
partname
|
str
|
Absolute package URI, e.g. |
required |
content_type
|
str
|
Content-type URI from
:class: |
required |
relationship_type
|
str
|
Relationship-type URI from
:class: |
required |
root_xml
|
bytes
|
Complete XML bytes for a fresh, empty root element of this part (used only when creating a part that doesn't exist). |
required |
get_or_create_part ¶
Return (part, root_element) for the part identified by spec.
If the main document part already has a relationship of
spec.relationship_type, returns the related part. Otherwise
creates a fresh part with the empty default root from spec.root_xml
and wires the relationship from the document part. Idempotent — a
second call with the same spec returns the same part.
The part class is looked up in :attr:PartFactory.part_type_for so
callers get the most specific class registered for the content type
(CommentsPart for comments; the internal
:class:_FootnotesPart / :class:_EndnotesPart for the note parts).
Unknown content types fall back to :class:XmlPart.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
doc
|
Document
|
The python-docx :class: |
required |
spec
|
PartSpec
|
Identifier for the target part. Use :data: |
required |
Returns:
| Type | Description |
|---|---|
XmlPart
|
A tuple |
_Element
|
|