Skip to main content

docxaudit

PyPI test python license

Find what your converter silently dropped from a .docx. Zero dependencies.

The figure above is generated by docs/silent-losses_figure.pypip install sciglyph and run it to reproduce docs/silent-losses.png byte for byte.

Pandoc — or any LaTeX/Markdown → Word pipeline — reports success and still loses things. A table disappears. Figures render in desktop Word but not in Word for the web. A supplement that is 11 pages as PDF arrives as 17 pages as .docx, and the editor counts the .docx.

None of that shows up as an error. You find out from a reviewer.

$ docxaudit examples/sample.docx
sample.docx
  26 paragraphs · 1 tables · 3 images (3 referenced) · 4 equations (1 display) · 0 page breaks

  ERROR   [TBL_NO_GRID] table 1 has no <w:tblGrid>
          columns collapse; the reader has to AutoFit by hand
          fix: Inject an equal-width tblGrid plus a per-cell <w:tcW>, and set
               <w:tblLayout w:type="autofit"/>.

  WARN    [NO_PAGEBREAKS] 3 figures but no page breaks at all
          if the PDF puts one figure per page, the .docx will not match, and
          reviewers count the .docx

  WARN    [FONT_MISMATCH] heading font 'Calibri' differs from body font 'Consolas'

  WARN    [FONT_EA_EMPTY] theme East Asian font is empty while the body sets one
          CJK headings will fall back and stop matching the body text

That output is real: examples/sample.docx is in this repository, built from examples/sample.md with plain pandoc. Three of those problems come from nothing more exotic than converting a short paper.

Why the usual checks miss these

python-docx cannot see them. It reads paragraph text, so equations (OMML) and anything the converter dropped are simply absent from what you inspect. "The text looks fine" is not evidence.

A LibreOffice preview misleads in both directions. It invents ugly font substitutions that real Word does not have — so you waste time fixing cosmetics that were never broken — and it is forgiving enough to render documents that stricter viewers refuse. The namespace bug above renders perfectly in LibreOffice and in desktop Word, and shows nothing in Word for the web.

An AI assistant reading the file cannot check this either. These are structural properties of the OOXML, not something visible in extracted text.

docxaudit reads the raw XML and checks the specific things that ship unnoticed.

Install

pip install docxaudit

Standard library only — a fresh virtualenv gains exactly one package and nothing else. Nothing to break, nothing to audit.

What it checks

Every check corresponds to a failure that actually reached a submission.

code what goes wrong
NS_PREFIX / NS_GENERATED Post-processing re-serialised the XML and rebound namespaces to ns2:/ns3:. Word resolves by URI so it looks fine; strict viewers show neither figures nor equations.
TBL_NO_GRID Table has no <w:tblGrid> — columns collapse to a sliver in Word. Common when tables come from LaTeX booktabs.
TBL_ZERO_WIDTH Table declares width 0.
IMG_ORPHAN Images embedded in the archive with no <w:drawing> referencing them — the anchors were dropped.
NO_PAGEBREAKS \clearpage does not survive conversion, so one-figure-per-page silently becomes a different page count.
MATH_INLINE Inline maths converts least reliably; complex expressions arrive mangled.
FONT_MISMATCH Theme heading font disagrees with the body default — sans-serif headings over serif text.
FONT_EA_EMPTY Theme East Asian font is empty, so CJK headings fall back and stop matching the body.
HEADING_COLOUR Headings still carry the default template's blue, while the PDF renders them black.
DUP_PREFIX Figure Figure 1 — the source wrote a prefix and the converter added its own.
EMPTY_HEADING A heading whose text did not survive.

Compare two outputs

Give it two files and it reports structural drift — useful for the PDF-side and Word-side versions of one manuscript, or for before/after a post-processing step:

$ docxaudit before.docx after.docx
comparison
  WARN    [DRIFT_PARAGRAPHS] paragraphs: 42 in before.docx vs 36 in after.docx
  ERROR   [DRIFT_TEXT] text length differs by 11%

Check a PDF against the .docx

Structural checks catch content that vanished. They cannot catch layout drift — the same content laid out over a different number of pages. Give it both files and it renders the .docx with LibreOffice and measures the result:

$ docxaudit paper.pdf paper.docx
paper.pdf
  17 pages · 0 images · 43885 chars
paper.docx  (rendered)
  19 pages · 7 images · 35876 chars

layout comparison
  ERROR   [PAGE_COUNT] page count differs: 17 (pdf) vs 19 (docx)
          2 page(s) apart; journals count the .docx

  INFO    [VECTOR_FIGURES] the pdf draws its figures as vectors on 4 page(s);
          the docx embeds 7 raster image(s)
          expected for a LaTeX PDF - image counts are not comparable

  INFO    [TEXT_TAIL_ONLY] 313 word(s) appear only in the pdf, 81% of them in
          the final quarter
          e.g. abdalah, ajani, albu, andrearczyk
          fix: Concentrated at the end: normally the reference list in a
               different citation style, not lost content.

Requires pip install docxaudit[pdf] and LibreOffice on PATH (or set DOCXAUDIT_SOFFICE). Both are optional — the structural checks above need neither.

Comparing two renderings honestly is harder than it sounds, and most of the work here went into not crying wolf:

  • A LaTeX PDF draws figures as vector operators, not embedded images, so counting images reports zero figures for a paper that plainly has them. Figure-bearing pages are compared instead.
  • Maths re-encodes. The PDF holds Unicode mathematical alphanumerics, the .docx holds OMML. Extracted text differs for identical equations, so only ASCII prose is compared.
  • Justified text hyphenates. advan- + tage in the PDF and advantage in the .docx would read as two words missing from each side; they are rejoined first.
  • Reference lists legitimately differ. So the tool reports where the missing words are: bunched in the final quarter it says so and calls it formatting; spread through the body it calls it lost content.

In CI

Exit code is 1 when there are errors, or with --strict when there are warnings too:

- run: pip install docxaudit
- run: docxaudit build/paper.docx --strict

As a library

from docxaudit import audit

report = audit("paper.docx")
print(report.stats)                      # counts you can assert on
for f in report.errors:
    print(f.code, f.message, f.fix)

--json gives the same structure on the command line.

Scope

It checks structure, not typography. It will not tell you a figure is ugly or a caption reads badly — for that, render the document and look at it. What it does is catch the class of problem that renders fine everywhere you happen to look, and breaks somewhere you do not.

Who maintains this

Guo Cheng, University of Chinese Academy of Sciences — medical imaging and machine learning methods. This tool came out of a supplement that was 11 pages as PDF and arrived as 17 pages as .docx, which the editor counted.

Corrections, bug reports and feature requests all go to Issues. Please open one rather than emailing: a public answer helps whoever hits the same thing next, and it is searchable.

Other things from the same desk

Written while trying to get papers out, so they tend to be useful at the same points in that process:

  • scholarcheck — verify that a citation actually exists, and audit a whole .bib in CI
  • sciglyph — draw publication figures as code, in pure matplotlib
  • world-model-map — a map of open-source world models and where their authors say they break
  • kakeya-conjecture-lab — an interactive lab for the Kakeya conjecture, with a box-counting meter

License

MIT © Guo Cheng

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

docxaudit-0.1.3.tar.gz (22.8 kB view details)

Uploaded Source

Built Distribution

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

docxaudit-0.1.3-py3-none-any.whl (20.1 kB view details)

Uploaded Python 3

File details

Details for the file docxaudit-0.1.3.tar.gz.

File metadata

  • Download URL: docxaudit-0.1.3.tar.gz
  • Upload date:
  • Size: 22.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.9

File hashes

Hashes for docxaudit-0.1.3.tar.gz
Algorithm Hash digest
SHA256 1f9d47a82581b9b743831e0ffd54973fbf84f543207e46a7e6b3abdd41bfdff8
MD5 e0a5920e6e6eee0cc1b3aafeed324aed
BLAKE2b-256 01ffd41918ab0f7250039f8aca03cc796e6a11290822648f5d45274aedd6678a

See more details on using hashes here.

File details

Details for the file docxaudit-0.1.3-py3-none-any.whl.

File metadata

  • Download URL: docxaudit-0.1.3-py3-none-any.whl
  • Upload date:
  • Size: 20.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.9

File hashes

Hashes for docxaudit-0.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 9f301fc793be01615b8d6f9db4e66d67cbbfe681372f2d2ec05996c9eabbf232
MD5 2671f2bb4ebd2f4c1cc070e03d3b01b3
BLAKE2b-256 35b2b8d5fd8f1bb40e28801406001a45a8a26b3bd62cd6b89b65bd41ed0c3464

See more details on using hashes here.

Release history Release notifications | RSS feed

0.1.5

2 files

0.1.4

2 files

This release

0.1.3 This release

2 files

0.1.2

2 files

0.1.1

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page