Skip to content

Optional: a python -m docx CLI for inspection and cleanup #118

Closed

Description

@toxicphreAK

The inspection and cleanup work in #114, #115 and #116 is all useful from a shell, and most of the questions people have about a .docx are one-off: what styles does this thing define, which are actually used, why is my file 900 KB. Writing a five-line script for that each time is friction.

$ python -m docx styles report house-template.dotx
164 styles defined  (36 paragraph, 27 character, 100 table, 1 numbering)
  3 in use, 161 unused
137 latent style exceptions

$ python -m docx styles list --unused report.docx
$ python -m docx cleanup report.docx -o report-clean.docx
$ python -m docx styles extract house.dotx --names "Quote,Caption" -o styles.docx
$ python -m docx info report.docx          # parts, sizes, content types, rels

Shape

  • A __main__.py and a docx.cli module, argparse only — no new runtime dependency
  • Subcommands mapping one-to-one onto the library operations, so the CLI stays a thin shell over the public API and never grows logic of its own
  • info reporting the part inventory with sizes, which is what you actually want when a document is unexpectedly large — this is how the 438 KB stylesWithEffects.xml in Default template ships 447 KB of parts no generated document needs #113 turned up
  • Optionally a [project.scripts] entry point; python -m docx alone is enough to start and commits to nothing

This one is genuinely optional

It is worth saying plainly that a CLI is a real commitment for a library: an argument surface that has to stay backward compatible, its own help text and docs, and a class of bug report ("the CLI prints this wrong") that is not about the library. python-docx has never shipped one, and there is a reasonable position that it should not.

Two things push the other way. The first is that the operations in the three issues above are diagnostic — you run them to find out something about a file, not as part of an application — and a diagnostic API with no command-line front end mostly does not get used. The second is that python -m docx info is the fastest way to answer the most common "why is this file like this" question, and there is currently no way to answer it without opening the zip by hand.

If the answer is no, the three library issues stand on their own and lose nothing. Close this one and the rest still make sense.

If it goes ahead

  • Every subcommand takes the document path first and writes to -o rather than in place. Never modify the input by default — cleanup is destructive and someone will point it at their only copy.
  • Exit codes matter for scripting: non-zero on a document that cannot be opened, and a --check mode for cleanup that reports what it would remove and exits non-zero if anything would be, so it can be a CI gate.
  • Keep the output greppable. A --json flag on the reporting commands costs nothing and makes the whole thing composable.

Activity

  1. toxicphreAK commented on Aug 5, 2026

    @toxicphreAK
    OwnerAuthor

    Landed in #139. On the genuinely-optional question: yes, on the terms the issue set. python -m docx with info, styles report/list/extract and cleanup; argparse only, no new dependency, and every subcommand is a thin shell over one public library operation so the CLI cannot grow logic of its own.

    The three conditions are met: cleanup refuses to write to its input and requires -o; exit codes are non-zero for a document that cannot be opened and for --check when something would be removed, so it can gate CI; and --json is on every reporting command. No [project.scripts] entry point — as the issue said, python -m docx commits to nothing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestquestionFurther information is requested

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions