Skip to content

docx_plus.comments.registry

Per-document registries for a comment's two id namespaces.

CommentIdRegistryw:id

Comment ids live in a separate uniqueness namespace from SDT, bookmark, and note ids — comment 5 does not collide with bookmark 5. The registry seeds itself from both the comments part and any orphaned body-side range markers so partially-deleted comments can't trigger id reuse.

DurableIdRegistryw16cid:durableId

A comment has three identifiers and only the durable id is stable:

Identifier Where Stability
w:id comments.xml A position-dependent index Word renumbers freely
w14:paraId comment body paragraph Changes whenever the body is rewritten
w16cid:durableId commentsIds.xml Stable for the life of the comment

Anything citing a comment from outside the document — a permalink, an external review tracker, a diff between two revisions — needs the third. Read it back through AnchoredComment.durable_id.

Word writes it as 8 uppercase hex digits (ST_LongHexNumber), the same rendering as w14:paraId — verified against a Word-authored file, which produced values like 33EF1546. Use next_hex(), not next().

Unlike paraId, a durable id is scoped to its one part, so the registry seeds from commentsIds.xml alone.

Architecture walkthrough: Durable ids and author presence.

docx_plus.comments.registry

Comment id registries — w:id and w16cid:durableId.

Comment w:id lives in a separate uniqueness namespace from SDT ids, bookmark ids, and note ids (a comment with id 5 does not collide with a bookmark with id 5). This module ships a tiny subclass of :class:~docx_plus.core.ids._IdRegistryBase that seeds itself from the comment ids already present in comments.xml and from any orphaned body-side markers (w:commentRangeStart, w:commentRangeEnd, w:commentReference) still in the body. The latter matters because hand-edited or partially-deleted documents can leave any one of those markers behind on its own, and it should still block id reuse.

This module imports only from docx_plus.core (SPEC §9.1).

CommentIdRegistry

CommentIdRegistry(doc: Document)

Bases: _IdRegistryBase

Tracks issued comment w:id values for one document-edit session.

Source code in docx_plus/core/ids.py
def __init__(self, doc: Document) -> None:
    """Scan ``doc`` for IDs already issued in this namespace.

    Args:
        doc: A python-docx :class:`~docx.document.Document`.
    """
    self._issued: set[int] = set()
    self._seed_from_document(doc)

DurableIdRegistry

DurableIdRegistry(doc: Document)

Bases: _IdRegistryBase

Tracks issued w16cid:durableId values for one edit session.

A durable id is a comment's stable identity. w:id is a position-dependent index Word renumbers freely, and w14:paraId changes whenever a comment's body is rewritten — neither survives as a citable handle. commentsIds.xml exists to give each comment one that does, which is what a permalink into a review thread needs.

Word writes durableId as 8 uppercase hex digits, the same ST_LongHexNumber rendering as w14:paraId — verified against a Word-authored file, which produced values like 33EF1546. Use :meth:~docx_plus.core.ids._IdRegistryBase.next_hex, not :meth:~docx_plus.core.ids._IdRegistryBase.next.

Seeds from commentsIds.xml only. Unlike paraId, a durable id is scoped to that one part, so it cannot collide with an id in the body or in any other part.

Source code in docx_plus/core/ids.py
def __init__(self, doc: Document) -> None:
    """Scan ``doc`` for IDs already issued in this namespace.

    Args:
        doc: A python-docx :class:`~docx.document.Document`.
    """
    self._issued: set[int] = set()
    self._seed_from_document(doc)