12

Batch renaming is exactly the kind of task where a model gives you a confident three-liner that renames files in a loop and, halfway through, renames a.txt to b.txt on top of an existing b.txt, or renames files in an order that clobbers targets it hasn't processed yet. I've lost files this way.

So I made the prompt require a plan-then-apply design: compute all renames first, detect collisions and cycles, refuse to run unless --apply is passed, and rename via a safe two-phase (through temp names) to survive swaps like a<->b. The dry-run-by-default plus collision check is what makes it trustworthy.

Is two-phase temp renaming overkill, or do you all do the topological-sort approach for swap cycles instead?

THE PROMPT
Write a Python CLI `rerename` that renames files matching a regex. Safety first: it must be impossible to silently lose a file.

Design:
- Args: a `--pattern` (Python regex) and `--replace` (backreferences allowed) applied to filenames, a directory (default `.`), `--recursive`, `--include-dirs`, and `--apply`. WITHOUT `--apply` it is a dry-run and changes nothing (default = dry-run).
- Phase 1 PLAN: compute every (src -> dst) pair. Print them as a table. Do NOT touch the filesystem yet.
- Collision detection: refuse to proceed (exit 2) if two sources map to the same destination, or a destination already exists and isn't itself a source being moved, or the regex produces an empty/invalid name or one containing a path separator.
- Cycle/swap safety: handle cases like `a->b` and `b->a` by renaming through unique temp names (two-phase), or a dependency-ordered sequence. Never overwrite a file that still needs to be read as a source.
- Atomicity within a run: if any rename fails mid-way, roll back the ones already done (track completed moves) so you never end half-applied.
- `--apply` prints a confirmation summary and requires the plan to be collision-free.
- Never follow symlinks out of the target dir; skip and log them.

Output the code, then a WORKED EXAMPLE showing the swap case `a.txt<->b.txt` and proving no data is lost. List every way a rename could lose a file and how the design prevents each.
Dry-run as the DEFAULT, with --apply to actually do it, is the right polarity for anything destructive. Opt in to danger, don't opt out of it.terminal_theo 3 months ago
add a comment

1 Answer

11

Two-phase temp renaming isn't overkill, it's the only thing that survives swap cycles without a topological sort, and it's simpler to reason about. But add one guard: generate the temp names with os.path.exists checks (or tempfile in the same dir) so your intermediate names can't collide with an untouched file. I've seen a naive .tmp suffix clobber someone's real report.txt.tmp.

THE PROMPT
For phase-one temp names, allocate them in the SAME directory (for atomic os.rename on one filesystem) using a random suffix verified not to exist, e.g. `f"{name}.rerename-{uuid4().hex}.tmp"`. Assert none collide before moving.

Your Answer