Skip to content

cli

cli

A command-line front end for the inspection and cleanup operations.

python -m docx answers the questions people ask about a .docx one at a time: what styles it defines, which are actually used, and why the file is 900 KB. Those are diagnostic operations — 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.

Deliberately thin: every subcommand maps onto one public library operation and holds no logic of its own, so the CLI cannot drift from the API or grow behaviour that is only reachable through it. argparse only; no new runtime dependency.

Two rules the commands keep:

  • Never modify the input. cleanup writes to -o and refuses without it. Someone will point it at their only copy.
  • Exit codes matter, because this ends up in scripts: non-zero for a document that cannot be opened, and --check reports what would be removed and exits non-zero if anything would be, so it can be a CI gate.

main

main(
    argv: Sequence[str] | None = None,
    stdout: IO[str] | None = None,
) -> int

Run the CLI; return the process exit code.

argv and stdout are injectable so the tests do not have to drive a subprocess.

Source code in src/docx/cli.py
def main(argv: Sequence[str] | None = None, stdout: IO[str] | None = None) -> int:
    """Run the CLI; return the process exit code.

    `argv` and `stdout` are injectable so the tests do not have to drive a subprocess.
    """
    out = sys.stdout if stdout is None else stdout
    parser = _build_parser()
    args = parser.parse_args(argv)

    if getattr(args, "func", None) is None:
        parser.print_help(out)
        return 0

    try:
        return args.func(args, out)
    except FileNotFoundError as e:
        print("error: no such file: %s" % e.filename, file=sys.stderr)
        return EXIT_CANNOT_OPEN
    except EncryptedPackageError:
        print("error: document is password-protected", file=sys.stderr)
        return EXIT_CANNOT_OPEN
    except (PackageNotFoundError, zipfile.BadZipFile) as e:
        print("error: cannot open document: %s" % e, file=sys.stderr)
        return EXIT_CANNOT_OPEN
    except KeyError as e:
        # -- `styles extract --names` and `cleanup --keep` name styles, and a name the
        # -- document does not define surfaces here rather than as a traceback --
        message = e.args[0] if e.args else str(e)
        print("error: %s" % message, file=sys.stderr)
        return EXIT_CANNOT_OPEN