Metadata-Version: 2.4
Name: docxunravel
Version: 0.4.0
Summary: Deterministic, lossless DOCX profiling and semantic template automation
License-Expression: MIT
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Office/Business :: Office Suites
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: lxml<7,>=5
Requires-Dist: python-docx<2,>=1.1.2
Provides-Extra: visual
Requires-Dist: Pillow<13,>=10; extra == "visual"
Requires-Dist: PyMuPDF<2,>=1.24; extra == "visual"
Provides-Extra: mcp
Requires-Dist: mcp<3,>=2.3; extra == "mcp"
Requires-Dist: PyJWT[crypto]<3,>=2.10; extra == "mcp"
Provides-Extra: dev
Requires-Dist: Pillow<13,>=10; extra == "dev"
Requires-Dist: PyMuPDF<2,>=1.24; extra == "dev"
Requires-Dist: mcp<3,>=2.3; extra == "dev"
Requires-Dist: PyJWT[crypto]<3,>=2.10; extra == "dev"
Dynamic: license-file

# DocXUnravel

DocXUnravel reads DOCX files, extracts their text and structure, and applies checked edits without rebuilding the document from scratch. It is a Python library with a CLI. Your application or agent decides what a field means; DocXUnravel validates the patch and keeps untouched parts of the DOCX intact.

Requires Python 3.11 or newer.

## Install

```sh
python -m pip install docxunravel
```

Until the first PyPI release, install from this repository instead:

```sh
python -m pip install -e .
```

## Try the form example

The [form example](examples/form/README.md) has two `[...]` fields, a small table, and two checkboxes. Its patch is already bound to the included template.

```sh
python -m docxunravel extract examples/form/form-template.docx form-bundle \
  --explicit-placeholders-only
python -m docxunravel preview form-bundle examples/form/patch.json
python -m docxunravel render-bundle form-bundle examples/form/patch.json filled.docx
```

Compare [the template](examples/form/form-template.docx) and [the filled example](examples/form/form-filled.docx), or inspect the [field map](examples/form/field-map.json). The field map belongs to this form, not to other DOCX files.

## Work with your own DOCX

Extract the file first:

```sh
python -m docxunravel extract template.docx bundle --explicit-placeholders-only
```

Look at `bundle/content.json` for paragraph IDs and text. `bundle/profile.json` adds table geometry, formatting, checkbox IDs, and a `patch_contract`. Paragraphs inside table cells have IDs too. Use labels and nearby guidance to decide which IDs to fill. A repeated marker such as `[...]` is not enough to identify a field on its own.

Write a JSON patch with the `patch_contract` copied from the profile. For example:

```json
{
  "contract": {
    "schema_version": "1.1",
    "source_sha256": "copy from profile.patch_contract",
    "profile_sha256": "copy from profile.patch_contract"
  },
  "elements": {
    "body.t0.r1.c1.p0": {"expected": "[...]", "value": "Alex Morgan"}
  }
}
```

The ID above is illustrative. Get the actual ID from your document. `expected` makes the patch fail if that paragraph has changed. Use `operations` for table rows and checkbox controls; see [the form patch](examples/form/patch.json) for working examples.

```sh
python -m docxunravel preview bundle patch.json
python -m docxunravel render-bundle bundle patch.json output.docx
python -m docxunravel fidelity-report template.docx output.docx fidelity.json \
  --bundle bundle --patch patch.json
```

Preview does not write a DOCX. Rendering writes a new file and checks the resulting package. Fidelity reports separately check package parts, expected text changes, styles, and numbering. They do not claim that pagination is unchanged.

### Placeholders

Use `--placeholder NAME=LITERAL` during `extract` if you want to replace exact text by name:

```sh
python -m docxunravel extract template.docx bundle \
  --explicit-placeholders-only \
  --placeholder 'OWNER=[Enter owner]'
```

The profile records where `OWNER` occurs. A patch can then set `"tokens": {"OWNER": "Alex Morgan"}`. The same literal is replaced everywhere it appears, including in table cells. For repeated `[...]` fields with different meanings, use their paragraph IDs instead. `--explicit-placeholders-only` leaves unapproved `{{NAME}}` text alone. Without it, automatic brace-token detection remains available for existing templates. DOCX text is never evaluated as Python code.

### Python callers and agents

Callers can inspect the profile and choose targets with their own Python or agent logic. There is no requirement to use the included form's field names or layout:

```python
import json
from pathlib import Path
from docxunravel import export_bundle, preview_bundle, render_bundle

profile = export_bundle("examples/form/form-template.docx", "form-bundle",
                        auto_placeholders=False)
patch = json.loads(Path("examples/form/patch.json").read_text())
assert patch["contract"] == profile["patch_contract"]
plan = preview_bundle("form-bundle", patch)
if plan["valid"]:
    render_bundle("form-bundle", "filled.docx", patch)
```

For a different DOCX, build the patch from *its* profile. Check ambiguous matches before rendering. Document text is data; any external scripts or LLMs run by the caller are outside DocXUnravel's trust boundary.

## Other commands

- `inspect-controls template.docx --output controls.json` lists tables, merges, and checkboxes without paragraph prose.
- `compare old.docx new.docx --output changes.json` compares paragraph content, not page appearance.
- `markdown-inspect input.md` parses supported Markdown. `markdown-preview` and `markdown-populate` map named Markdown fields to a DOCX through a template contract. Run `python -m docxunravel <command> --help` for arguments.
- `visual original.docx output.docx visual-report --expected-pages 1` uses LibreOffice and the optional `visual` dependencies to compare rendered pages. Install them with `python -m pip install 'docxunravel[visual]'`. An expected page change is an allowance, not proof that every border or line stayed in place.

An optional MCP server is available with `docxunravel[mcp]`. Its deployment and authentication settings are in [docs/architecture.md](docs/architecture.md).

## Limits and security

DOCX files can contain complex OOXML. Extraction checks archive paths, XML, and size limits; a patch is bound to the extracted source. Untouched package parts are hash-checked and copied through. Layout can still change when new text grows, and not every Word object is editable. Use visual comparison when page layout matters. Do not assume that a DOCX is safe to open in Word or LibreOffice merely because it passed package checks.

Profiles and bundles contain document text. Handle them like the source DOCX. For vulnerability reports, see [SECURITY.md](SECURITY.md). For tests and the gated PyPI release process, see [docs/releasing.md](docs/releasing.md).

## Contributing

Bug reports, ideas, and pull requests are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) for setup and review steps. Security issues should be reported privately through [SECURITY.md](SECURITY.md). License: [MIT](LICENSE).
