Paper Office
paper-docx

paper-docx

A python-docx fork for creating and editing Word documents safely without changing your imports.

paper-docx is a fork of python-docx for working with Word documents. It keeps the docx import name and the python-docx object model, so existing code works unchanged. It adds safe, structured editing of documents you didn't author: search across fragmented text, tracked changes, comments, comparison, and package-safe saves. When an edit cannot be made safely, it raises a typed PaperRefusal and leaves the document unchanged.

import docx                       # the import name is unchanged
doc = docx.Document("contract.docx")

Quick start

pip uninstall -y python-docx paper-docx
pip install paper-docx
paper-docx-doctor                          # verify the install

Create a Word redline from two document versions:

import tempfile, docx
from docx.package import compare

tmp = tempfile.mkdtemp()
a = docx.Document()
a.add_paragraph("Payment is due within thirty calendar days of the invoice date.")
a.save(f"{tmp}/v1.docx")
b = docx.Document()
b.add_paragraph("Payment is due within thirty business days of the invoice date.")
b.save(f"{tmp}/v2.docx")

result = compare(f"{tmp}/v1.docx", f"{tmp}/v2.docx", author="Reviewer")
[(r.revision_type, r.text) for r in result.document.revisions]
# [('deletion', 'calendar'), ('insertion', 'business')]

result.document.revisions.accept_all()
result.document.paragraphs[0].text
# 'Payment is due within thirty business days of the invoice date.'

The redline is w:ins/w:del markup that Word renders as tracked changes. Before returning, compare verifies on private copies that accepting the result reproduces the revised document and rejecting it reproduces the original. If a difference cannot be represented safely, compare raises a typed error.

The everyday case, replacing a phrase Word has fragmented across runs:

from docx.search import find_one

find_one(doc, "within 30 days").replace(
    "within 45 days", tracked=True, author="Reviewer",
)
[(r.revision_type, r.author, r.text) for r in doc.revisions]
# [('deletion', 'Reviewer', '30'), ('insertion', 'Reviewer', '45')]

Compatibility

  • PyPI distribution and GitHub repository: paper-docx
  • Python import: docx. Never import paper_docx.
  • Upstream compatibility version: docx.__version__ == "1.2.0"
  • Fork version: docx.__paper_version__

import docx raises ImportError when both distributions' metadata are installed. Paper adds validation and guarded edits, so it can reject inputs or operations that python-docx accepts.

On this page