Skip to content

docx_plus.numbering.registry

Allocators for the two disjoint id namespaces in numbering.xml.

Both allocate with next_sequential() — the lowest free integer — rather than the random next() every other namespace uses. Word and python-docx both number lists this way, and these ids are read by humans debugging list behaviour far more often than most.

The two namespaces differ at the bottom of their range, and it matters: w:abstractNumId legitimately starts at 0 (the bundled template uses 0–8), while w:numId starts at 1 because 0 inside a w:numPr is the sentinel meaning "no numbering" — the only way a paragraph opts out of a list applied by its style.

docx_plus.numbering.registry

Numbering id registries — w:numId and w:abstractNumId.

numbering.xml carries two disjoint id namespaces. A w:abstractNum is the definition — what the levels look like — and a w:num is an instance of one, which is what a paragraph's w:numPr actually references. Two paragraphs sharing a numId continue one sequence; two num entries pointing at the same abstractNumId are independent sequences with identical formatting, which is how Word restarts a list.

Both registries allocate with :meth:~docx_plus.core.ids._IdRegistryBase.next_sequential rather than the random :meth:~docx_plus.core.ids._IdRegistryBase.next every other namespace uses. Word and python-docx both number lists with the lowest free integer, and a numbering.xml full of nine-digit ids is needlessly unreadable — these ids are read by humans debugging list behaviour far more often than most.

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

NumIdRegistry

NumIdRegistry(doc: Document)

Bases: _NumberingIdRegistryBase

Tracks issued w:num ids for one document-edit session.

w:numId is what a paragraph's w:numPr references. Note that numId 0 is not an entry id — inside a w:numPr it is the sentinel meaning "no numbering", which is how a paragraph opts out of a list its style applies. Allocation therefore starts at 1.

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)

AbstractNumIdRegistry

AbstractNumIdRegistry(doc: Document)

Bases: _NumberingIdRegistryBase

Tracks issued w:abstractNum ids for one document-edit session.

Unlike every other id namespace in the library, 0 is legal here — python-docx's own bundled template ships abstractNumId 0 through 8 — so this registry lowers :attr:_MIN_ID accordingly.

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)