If you maintain a document pipeline, the failure you remember is never the one that crashed. It is the one that "mostly worked": numbering that drifted, comments that vanished, a redline that opened strangely in Word. So when people ask how safe-docx compares to python-docx, the honest answer starts by saying what python-docx is genuinely good at — and then drawing the line where its job ends and brownfield editing begins.
python-docx is a generation and modification library
python-docx is a mature, well-loved library for creating Word documents and making structural edits — adding paragraphs, styling runs, building tables, setting section properties. If your task is "produce a new .docx from data," it is a natural fit, and nothing here is a criticism of it at that job.
What it is not built for is tracked changes. Word records edits as OOXML revision markers — <w:ins> for insertions, <w:del> for deletions, move wrappers, and property-change records — and python-docx does not expose those as first-class objects. Producing review-ready redlines, or reading the revisions already in a document, sits outside its model. That gap is long-standing and well known in the community, which is why people reach for XML-level workarounds when they need it.
Brownfield editing has a different contract
safe-docx starts from the opposite end of the stack. The job is to take an existing .docx — one a lawyer or counterparty authored, with its own styles, numbering, comments, and possibly existing tracked changes — and edit it surgically while preserving everything the edit did not touch. Two requirements fall out of that:
Round-trip fidelity. Parsing and re-serializing the document must not perturb the parts you did not edit. Element structure, attributes, and text have to survive the trip byte-for-byte where nothing changed. The XML round-trip scenarios exercise exactly this — parse, serialize, and confirm the structure is preserved.
Revision semantics as a first-class output. Edits can be wrapped as tracked changes so they show up in Word's review pane next to any human revisions, and two versions can be compared into a tracked-changes document via
compare_documents. Existing revisions can be read back out as structured JSON withextract_revisions, or resolved with the accept-changes primitives — see the accept-tracked-changes scenario for how a move is resolved into destination-only text.
Where each one belongs
This is not "better library, worse library." It is a stack question:
- Generating a new document from data or a template? A generation-first library such as python-docx (Python) or
docx(JS) is the right layer. - Editing an existing document and returning a clean redline, with comments and styles intact? That is the brownfield-editing problem safe-docx is built for, and where tracked-changes support has to be designed in, not bolted on.
The feature-by-feature breakdown — tracked-change handling, OOXML coverage, and round-trip behavior — is on the safe-docx vs python-docx comparison. And because the claims above should be inspectable rather than taken on faith, the underlying behaviors are written up as evaluation scenarios with real fixtures and expected output, with the full test run in the public Allure report. Where the edges still are is stated plainly in known limitations.