Skip to main content

Lightweight DOCX comment engine based on text view API

Project description

Docxnote

简体中文

docxnote is a lightweight DOCX comment engine with only an lxml dependency, for automating Word comments.

It works directly on WordprocessingML, treating a DOCX as ZIP + XML, and exposes a text-oriented API.

Unlike typical DOCX libraries, docxnote hides Word’s Run structure entirely; everything is based on paragraph strings.


Installation

pip install docxnote

With uv:

uv add docxnote

Quick start

from docxnote import DocxDocument, Paragraph, Table

# Load document
with open("document.docx", "rb") as f:
    # By default existing comments are discarded
    doc = DocxDocument.parse(f.read())

    # To keep existing comments and add more:
    # doc = DocxDocument.parse(f.read(), keep_comments=True)

# Walk block-level content
for block in doc.blocks():
    if isinstance(block, Paragraph):
        if block.text:
            block.comment("Please review wording", end=5, author="reviewer")

    elif isinstance(block, Table):
        rows, cols = block.shape()
        for r in range(rows):
            for c in range(cols):
                cell = block[r, c]
                for inner in cell.blocks():
                    if isinstance(inner, Paragraph) and inner.text:
                        inner.comment("Needs review", end=3, author="reviewer")

# Write output
output = doc.render()
with open("output.docx", "wb") as f:
    f.write(output)

API

DocxDocument

Represents a DOCX file.

parse

DocxDocument.parse(docx_bytes, *, keep_comments=False)

Parses the DOCX and returns a document object.

  • keep_comments: Whether to keep existing comments. Default False (strips them). Use True to preserve existing comments and append new ones.

blocks

doc.blocks()

Returns block-level elements:

(Paragraph | Table, ...)

Order matches the Word document.


render

doc.render()

Returns new DOCX as bytes. Comments are written during this step.

Thread safety

A single DocxDocument instance is safe to use from multiple threads (internally serialized with a reentrant lock). Use separate instances for parallel work across threads. For multiple processes, call parse in each process.


Paragraph

Represents a Word paragraph.


Comment reading

from docxnote import Comment

Each comment attached to a paragraph is exposed as a Comment object via paragraph.comments:

for c in paragraph.comments:
    assert isinstance(c, Comment)
    print(c.start, c.end, c.text, c.author)

The start/end indices are character offsets into paragraph.text (Python slicing semantics, [start, end)). The Comment.date field corresponds to the w:date stored in comments.xml (UTC).

text

text = paragraph.text

Full paragraph text, including \n and \t.


comment

paragraph.comment(
    text,           # comment body
    start=0,        # start index (inclusive)
    end=None,       # end index (exclusive); None means end of paragraph
    *,
    author="docxnote",
    date=None,      # datetime (timezone-aware recommended); None = current system time
)

Adds a comment spanning the given character range in the paragraph. The w:date value in comments.xml is stored in UTC (…Z). A naive datetime (no tzinfo) is treated as UTC.

Example:

paragraph.comment("Needs change", start=3, end=8, author="Alice")

docxnote handles run splitting, anchors, comments.xml, and relationship updates.


Reading comments on the whole document

comments = doc.comments()
for c in comments:
    # c.paragraph is the owning Paragraph
    ...

This walks all paragraphs in the document (including inside tables and nested tables) and returns all comments in document order. Respecting keep_comments: with keep_comments=False only comments added in the current session are visible; with keep_comments=True existing comments from the DOCX are also exposed.


Table

Represents a Word table.

shape

rows, cols = table.shape()

Returns (row_count, col_count).


Cell access

cell = table[row, col]

Returns a Cell. All coordinates are addressable, including positions covered by merged cells.


Cell

Represents a table cell.

blocks

cell.blocks()

Block-level elements inside the cell:

(Paragraph | Table, ...)

Order matches Word.


bounds

top, left, bottom, right = cell.bounds()

Cell bounds (top, left, bottom, right) with half-open intervals [top, bottom) and [left, right).

For a non-merged cell, returns (r, c, r+1, c+1).


Advanced

Nested tables

for block in doc.blocks():
    if isinstance(block, Table):
        rows, cols = block.shape()
        for r in range(rows):
            for c in range(cols):
                cell = block[r, c]
                for inner_block in cell.blocks():
                    if isinstance(inner_block, Table):
                        inner_rows, inner_cols = inner_block.shape()
                        # ...

Multiple comments

paragraph.comment("Note 1", start=0, end=5, author="Alice")
paragraph.comment("Note 2", start=10, end=15, author="Bob")
paragraph.comment("Note 3", start=20, end=25, author="Carol")

Merged cells

table = [b for b in doc.blocks() if isinstance(b, Table)][0]

cell = table[0, 0]
top, left, bottom, right = cell.bounds()

if bottom - top > 1 or right - left > 1:
    print(f"Merged cell spans {bottom - top} rows, {right - left} cols")

Tests

Test documents are generated with python-docx; no checked-in DOCX fixtures. See tests/README.md.


SKILL

This repo includes SKILL.md to help coding agents use docxnote correctly. From the project root, download it into the agent skill folder (replace main if your default branch differs). On Windows PowerShell, use curl.exe if curl is aliased to Invoke-WebRequest.

Cursor

mkdir -p .cursor/docxnote
curl -fsSL -o .cursor/docxnote/SKILL.md https://raw.githubusercontent.com/touken928/docxnote/main/SKILL.md

Claude Code

mkdir -p .claude/docxnote
curl -fsSL -o .claude/docxnote/SKILL.md https://raw.githubusercontent.com/touken928/docxnote/main/SKILL.md

Point your agent at that file for install steps, suggested patterns, and caveats.


License

Licensed under the Apache License, Version 2.0. See LICENSE in the repository root.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

docxnote-0.2.0.tar.gz (11.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

docxnote-0.2.0-py3-none-any.whl (14.7 kB view details)

Uploaded Python 3

File details

Details for the file docxnote-0.2.0.tar.gz.

File metadata

  • Download URL: docxnote-0.2.0.tar.gz
  • Upload date:
  • Size: 11.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for docxnote-0.2.0.tar.gz
Algorithm Hash digest
SHA256 373e54ac06940bb4e48e96da20491f71ae4b1d00b77bfb1617a95061e28157fe
MD5 f2422676f332f64e8b8ee274ea447719
BLAKE2b-256 913da853f10c1cea2f71f56770bdd7142754d0e7bd990eca5e39d9d4278a14e0

See more details on using hashes here.

Provenance

The following attestation bundles were made for docxnote-0.2.0.tar.gz:

Publisher: publish.yml on touken928/docxnote

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file docxnote-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: docxnote-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 14.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for docxnote-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 91be04e3ca637895362b811f79a5f11b9d1555f0f727bb8d8adf1422e14d6f18
MD5 f5c795a5aa806f3d68e25fd314fdef44
BLAKE2b-256 f798540e243ef91286edc28b2a73ce9a172d177f1aefa5ce96ebb3d857c0efec

See more details on using hashes here.

Provenance

The following attestation bundles were made for docxnote-0.2.0-py3-none-any.whl:

Publisher: publish.yml on touken928/docxnote

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page