Automation must be safer than manual movement
A Downloads folder may contain images, documents, spreadsheets, archives, code and unknown files. The organizer groups top-level files into named subfolders based on lowercase extensions. Because movement changes real filesystem state, correctness includes avoiding overwrites, showing a preview and allowing cancellation with zero changes.
Discover
Inspect only direct child files of the selected folder.
Plan
Resolve category and a non-conflicting destination.
Apply
Create required folders and move after confirmation.
Define exclusions before scanning
- The selected path must exist and be a directory.
- Only top-level regular files are candidates; subdirectories are not traversed.
- The running organizer script excludes itself.
- Extension comparison is case-insensitive.
- Unknown or extensionless files go to
Other. - An existing destination is never overwritten.
- No movement begins unless the user types exactly
MOVE.
The narrow, non-recursive scope prevents accidentally reorganizing an entire nested project. Recursion can be an extension only after symlink handling, protected folders and rollback are designed.
A mapping keeps policy separate from movement
CATEGORIES = {
"Images": {".jpg", ".png", ...},
"Documents": {".pdf", ".docx", ...},
"Code": {".py", ".c", ".html", ...}
}category_for lowercases Path.suffix and searches the mapping. The classification rule is data, so adding an extension does not change the planning algorithm.
Important ambiguity
archive.tar.gz has .gz as its final suffix and is classified as an archive. A richer policy might inspect suffixes. A file extension is only a naming convention; it does not verify actual content. Security-sensitive systems need content inspection.
Separate decision from mutation
A dry preview lets the user detect a wrong directory or classification before anything changes. The plan is also testable without modifying files: provide a temporary directory, call build_plan and inspect its tuples.
The program sorts source names case-insensitively so preview order is deterministic. Determinism makes screenshots, tests and troubleshooting easier.
Never trade organization for data loss
If Images/photo.jpg already exists, moving another photo.jpg to that exact path could overwrite or fail depending on platform. The organizer tests the candidate and generates photo_1.jpg, photo_2.jpg, and so on until an unused name is found.
candidate = category / original_name
while candidate exists:
candidate = category / f"{stem}_{counter}{suffix}"This preserves both files, though it does not determine whether they contain duplicate bytes. Hash-based duplicate detection is a separate policy that should offer review rather than silently delete.
Runnable Python program using real files
Loading source…Trace a five-file test folder
- Start with copied test files.
- Validate target.
- Apply exclusions.
- Classify case-insensitively.
- Finish classification.
- Resolve collision before moving.
- Display preview.
- Confirm mutation.
- Apply and report.
Press Next to begin.
Verify without risking personal data
Cancellation
Case-insensitive extension
Unknown and extensionless
Name collision
Subdirectory exclusion
Partial OS failure
Directory scanning is linear; I/O dominates
| Phase | Time | Memory |
|---|---|---|
| List/sort n entries | O(n log n) | O(n) |
| Classification | O(nc) | O(n) |
| Apply moves | O(n) operations | O(1) extra |
c is the small number of categories. A sequence of filesystem moves is not atomic: power loss may leave a partially organized folder. A stronger version records a journal before each move and supports rollback. It must also define behavior for symbolic links and cross-filesystem copies.
Check safe automation principles
Why build a complete plan before moving?
What should happen when a destination name exists?
Extensions
- Create a move journal and Undo Last Run.
- Add modification-year subfolders after category.
- Detect byte-identical files using hashes but require review before deletion.
- Add configurable rules from JSON.
- Design safe recursion with symlink-cycle protection.
Explain filesystem safety
Why pathlib?
It provides readable, cross-platform path objects and avoids fragile manual path-string concatenation.
Why not overwrite?
Matching filenames do not prove matching content. Overwrite could irreversibly destroy the earlier file.
Is preview enough for atomicity?
No. It prevents unintended starts, but failures during application can still leave partial results. A journal/rollback or transactional storage is needed.
Why skip directories?
Recursive reorganization expands risk dramatically and requires explicit rules for nested structure, symlinks and protected folders.
Good automation makes consequences visible first
The Python APIs are straightforward; the engineering value lies in constrained scope, deterministic planning, explicit confirmation, collision protection, precise error reporting and temporary-directory tests.
