Skip to main content

Add a dry-run mode to a Python cleanup command

2026-11-11 15:57:28.071410+00:00
Add a dry-run mode to a Python cleanup command

A cleanup command should make its candidate set visible before it removes anything. Default to a preview, restrict work to a directory chosen by the operator and require a separate flag for execution.

The same candidate policy feeds preview or explicit execution; this example never recurses.

Keep the first version deliberately narrow

The following command checks immediate files in a supplied fixture directory. It removes only regular files ending in ".tmp"; it does not recurse or follow symbolic links.

import argparse
from pathlib import Path

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("directory", type=Path)
    parser.add_argument("--execute", action="store_true")
    args = parser.parse_args()

    root = args.directory.resolve(strict=True)
    if not root.is_dir():
        parser.error("directory must be a directory")

    candidates = sorted(
        path for path in root.iterdir()
        if path.suffix == ".tmp"
        and not path.is_symlink()
        and path.is_file()
    )
    for path in candidates:
        print(("REMOVE" if args.execute else "PREVIEW"), path)
        if args.execute:
            path.unlink()

if __name__ == "__main__":
    main()

Run it against a temporary directory containing "keep.txt" and "discard.tmp". The first invocation should print the temporary file and leave both files present. Add "--execute" for the second invocation and confirm only the candidate disappears. A third run should find nothing to remove.

The resolved absolute directory makes the operator's target visible. In a service, enforce a configured allowed root as well; a command accepting arbitrary operator-selected paths is a different authorization model. Reject a root that falls outside the application's intended working area before enumerating candidates.

Decide what a preview promises

Two invocations do not form one transaction. A file may change after the preview. If the execution command rescans the directory, it may select a file created after the operator reviewed the first list.

For a stronger review workflow, save a manifest containing each candidate's resolved path, size and modification metadata, then revalidate it during execution. Metadata comparisons still have race conditions. A hostile shared directory requires stronger operating-system-level file handling than this small example provides.

Handle permission errors as failures, with a nonzero exit status and a useful path message. Do not catch every exception and print "done": that makes a partially completed cleanup indistinguishable from success.

The operational automation in Postzyo offers related context. The relevant interfaces are documented in argparse and pathlib.