Output folders, temp files and archiving steps are part of nearly every script.
Path wraps the common file operations:
p.mkdir(parents=True, exist_ok=True)creates the directory and missing parents, and doesn't complain if it exists.p.touch()creates an empty file or updates its modification time;touch(exist_ok=False)fails if it exists.p.rename(target)moves or renames and returns the new Path. On Windows it fails iftargetexists.p.replace(target)does the same but overwritestargeton every platform (atomic on POSIX).p.unlink(missing_ok=True)deletes a file, ignoring it if absent.p.rmdir()deletes an empty directory.
Relative targets in rename and replace are interpreted relative to the current working directory, not to p's folder. Write p.rename(p.with_name("new.txt")) or p.parent / "new.txt" to stay in the same directory.
Pathlib in 3.13 has no recursive delete or copy; use shutil.rmtree(p), shutil.copy2(src, dst) and shutil.move(src, dst), which all accept Path objects. (Python 3.14 adds Path.copy and Path.move.)
All these methods raise the usual OSError subclasses: FileExistsError, FileNotFoundError, IsADirectoryError, PermissionError.
Example
import shutil
from pathlib import Path
out = Path("out/2025/03")
out.mkdir(parents=True, exist_ok=True)
draft = out / "draft.txt"
draft.write_text("v1", encoding="utf-8")
final = draft.rename(draft.with_name("final.txt")) # same folder
print(final) # out/2025/03/final.txt
print(draft.exists()) # False
(out / "tmp.lock").touch()
(out / "tmp.lock").unlink()
(out / "tmp.lock").unlink(missing_ok=True) # no error when absent
try:
Path("out").rmdir()
except OSError as e:
print(type(e).__name__) # OSError
shutil.rmtree("out")
print(Path("out").exists()) # FalseRemember
mkdir(parents=True, exist_ok=True)ensures a folder existsrenametargets are relative to the cwd; build them fromp.parentorwith_name- Use shutil for recursive delete, copy and cross-device moves
Watch out for
- Writing
p.rename('new.txt')and finding the file moved into the current working directory.