docx-editor¶
Pure Python library for Word document track changes and comments, without requiring Microsoft Word.
Note: The PyPI package is named
docx-editorbecausedocx-editwas too similar to an existing package.
Features¶
- Hash-Anchored Paragraph References: target edits with paragraph refs like
P2#f3c1 - Batch Editing: apply multiple paragraph-scoped edits with upfront hash validation
- Paragraph Rewrite: rewrite a paragraph and generate tracked changes from the diff
- Track Changes: Replace, delete, and insert text with revision tracking
- Comments: Add, reply, resolve, and delete comments
- Rationale Notes:
note=on an edit anchors a comment explaining the redline on exactly the revisions it creates — and deletes it when they are resolved - Revision Management: Accept/reject tracked changes at three granularities — individual revisions, groups (one logical edit), and changesets (one whole
batch_edit/batch_rewritecall) - Cross-Boundary Editing: Find and replace text spanning multiple XML elements
- Cross-Platform: Works on Linux, macOS, and Windows
- No Dependencies: Only requires
defusedxmlfor secure XML parsing
Installation¶
pip install docx-editor # editing: track changes, comments, revisions
pip install "docx-editor[create]" # + python-docx, for creating new documents
pip install "docx-editor[session]" # + docx-session persistent CLI
On a modern Debian/Ubuntu (or any interpreter marked PEP-668
externally-managed), a bare pip install into the system Python is refused — install
into a virtualenv instead:
python3 -m venv .venv && . .venv/bin/activate # errors "ensurepip is not available"?
# first: apt install python3-venv
pip install docx-editor
# or with uv: uv venv && uv pip install docx-editor
# or pipx for just the CLI: pipx install "docx-editor[session]"
Quick Start¶
from docx_editor import Document
with Document.open("contract.docx", author="Legal Team") as doc:
# List paragraphs to get hash-anchored references.
for paragraph in doc.list_paragraphs():
print(paragraph)
# Example output:
# P1#a7b2| Introduction to the contract...
# P2#f3c1| Payment is due within 30 days...
# Edit methods require a paragraph ref and return the updated ref.
# Pass occurrence= (0-based) to disambiguate repeated text; omitting it
# requires a unique match, else AmbiguousTextError.
ref = doc.replace("30 days", "60 days", paragraph="P2#f3c1")
ref = doc.insert_after("Payment", " terms", paragraph=ref)
doc.delete("obsolete text", paragraph="P5#d4e5")
# Comments and revision management.
doc.add_comment("Section 5", "Please review")
revisions = doc.list_revisions()
if revisions:
doc.accept_revision(revisions[0].id)
doc.save()
Context Manager¶
from docx_editor import Document
with Document.open("contract.docx") as doc:
ref = doc.list_paragraphs()[0].split("|", 1)[0]
doc.replace("old term", "new term", paragraph=ref)
doc.save()
# Automatically closes and cleans up workspace