Metadata-Version: 2.4
Name: paper-docx
Version: 0.1.0
Summary: Create, read, and update Microsoft Word .docx files.
Author: Paper Instruments, Inc.
Author-email: Steve Canny <stcanny@gmail.com>
Maintainer: Paper Instruments, Inc.
License: MIT
Project-URL: Changelog, https://github.com/The-LLM-Data-Company/paper-docx/blob/main/HISTORY.rst
Project-URL: Documentation, https://github.com/The-LLM-Data-Company/paper-docx
Project-URL: Homepage, https://github.com/The-LLM-Data-Company/paper-docx
Project-URL: Issues, https://github.com/The-LLM-Data-Company/paper-docx/issues
Project-URL: Repository, https://github.com/The-LLM-Data-Company/paper-docx
Keywords: docx,office,openxml,word
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Topic :: Office/Business :: Office Suites
Classifier: Topic :: Software Development :: Libraries
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: lxml>=3.1.0
Requires-Dist: typing_extensions>=4.9.0
Dynamic: license-file

# 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`](https://github.com/python-openxml/python-docx) and a drop-in
replacement. The distribution is renamed; the import name stays `docx`, so
existing code keeps working unchanged.

```python
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:

```python
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:

```bash
pip install paper-docx
```

Confirm the install:

```bash
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](https://python-docx.readthedocs.io/).

## 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`](LICENSE).
