Skip to main content

Create, read, and update Microsoft Word .docx files.

Project description

paper-docx

paper-docx is an agent-first Python library for safely inspecting, editing, reviewing, and composing existing Microsoft Word (.docx) documents. It is a strict-superset hard fork of python-docx and a drop-in replacement. The distribution is renamed; the import name stays docx, so existing code keeps working unchanged.

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

Why it exists

python-docx is excellent at creating documents. Its lossless package layer, disciplined XML mapping, and years of absorbed edge cases are why this fork builds on it.

The harder problem is changing a contract or other real-world document without losing formatting, revisions, fields, or content outside the body. Hand-edited XML can produce silent corruption: a file that opens fine and is quietly wrong. An agent cannot eyeball the result, so it needs the document's structure and every edit outcome as typed, machine-readable data. It also needs the library to refuse rather than guess.

Safety contract

Every added operation either does exactly what it claims or refuses atomically. Mutating operations validate fully before they change anything. If an operation cannot proceed safely, it raises a typed PaperRefusal and leaves the document byte-for-byte unchanged in memory and on disk. Callers can catch PaperRefusal separately from programmer errors, which remain plain ValueError or TypeError. Comparison and rewrite paths preserve meaningful whitespace, including trailing spaces inside runs.

A short example

Create a native 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.'

compare emits markup Word renders as tracked changes. Accepting the redline reproduces the revised document; rejecting it reproduces the original. That round-trip guarantee holds across every part of the file.

What it adds

Reading and editing one document

  • docx.story traverses the body, headers, footers, footnotes, endnotes, comments, tracked insertions, content controls, and text boxes. Callers can view the document as it stands, before pending revisions, or all at once.
  • docx.search finds normalized text across Word's run fragmentation. A returned Span can replace the matched text while preserving unaffected runs, emit the replacement as a tracked change, or anchor a comment.
  • docx.blocks inserts, deletes, or replaces whole paragraphs relative to a text anchor, plainly or as a tracked change.
  • docx.tableops / docx.numbering provide cell, row, and list edits that refuse on unsafe structures such as merged cells, nested tables, or undefined numbering.
  • docx.controls fills content controls with the correct value type and clears placeholder state so Word treats them as filled.
  • docx.bookmarks / docx.fields create bookmarks over a span and author page numbers, dates, cross-references, and tables of contents as fields with placeholder results.
  • docx.formatting resolves effective formatting through document defaults, styles, and direct formatting, with provenance for each value.

Reviewing and finalizing

  • doc.revisions enumerates and resolves tracked changes across every part: insertions, deletions, run and paragraph format changes, table-row revisions, and moves. Unresolvable markup is listed by name.
  • doc.finalize() / doc.scrub() accepts or rejects all revisions, then removes reviewing residue and reports exactly what was removed.
  • docx.protection respects Restrict-Editing. Mutating operations refuse on a protected document unless the caller explicitly overrides; the setting is preserved in the document.

Working across documents

  • docx.package.compare generates a native tracked-change redline from two documents, with the accept/reject round-trip shown above.
  • docx.package.patch_save / diff_package / text_diff keeps unchanged parts byte-identical and reports changed parts and text. diagnose explains why an unreadable file cannot be opened.
  • docx.composition copies formatted content between documents, reconciles styles, numbering, media, hyperlinks, and bookmarks, and reports every part touched.
  • docx.errors exposes typed refusals, distinct from programmer errors.

Drop-in and name map

Only the distribution and repository are renamed. The importable package stays docx. This is the same distribution/import split as Pillow (pip install pillow, import PIL), and it preserves existing code, snippets, and model priors.

  • GitHub repository / PyPI distribution: paper-docx
  • Python import: docx
  • Fork sentinel: docx.__paper_version__ = "0.1.0"

Installation

Install from PyPI:

pip install paper-docx

Confirm the install:

python -c "import docx; print(docx.__paper_version__)"

Documentation

The Sphinx docs extend the upstream python-docx documentation to cover the fork's additions: start with docs/user/paper-additions.rst and the docs/api/paper-*.rst reference pages. Everything inherited from python-docx works as documented at the python-docx documentation.

How it's tested

  • Upstream's pytest and behave suites run on every commit to check compatibility with existing behavior.
  • A frozen, hash-pinned fixture corpus spans generated and LibreOffice-authored documents.
  • The contract harness checks refusal atomicity and validates the fixture corpus with a headless LibreOffice load smoke.

License

MIT, inherited from python-docx. Original work © Steve Canny and the python-docx contributors; fork additions © Paper Instruments, Inc. This fork preserves the upstream license and attribution. See LICENSE.

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

paper_docx-0.1.0.tar.gz (7.1 MB view details)

Uploaded Source

Built Distribution

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

paper_docx-0.1.0-py3-none-any.whl (360.7 kB view details)

Uploaded Python 3

File details

Details for the file paper_docx-0.1.0.tar.gz.

File metadata

  • Download URL: paper_docx-0.1.0.tar.gz
  • Upload date:
  • Size: 7.1 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for paper_docx-0.1.0.tar.gz
Algorithm Hash digest
SHA256 3c6690073aa3f5697aa9ec8a4cb5270b8b0cf7fe2d95b52514fa08258d0b7004
MD5 50c17a8bf724522a234e940aa019f69c
BLAKE2b-256 2f244b7131d6aa441d4a20bfb1325f42e89d24278274255ea4b5c055c2836a2b

See more details on using hashes here.

File details

Details for the file paper_docx-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: paper_docx-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 360.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for paper_docx-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f16707d2cd4bbca829c51a29fb0c6ebacd301393e188b99c49092c09612be844
MD5 4e68faef88912203ba35e77b37fd008d
BLAKE2b-256 22dbda529b6f323495f15c225c851c0d5ba6f1fa92c379759b4956956b331e4f

See more details on using hashes here.

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