Comparing paths, printing friendly names and checking containment all need normalised paths.
Three ways to make a path absolute:
p.absolute()prefixes the cwd; it doesn't touch..or symlinks.p.resolve()makes it absolute and removes..and symlinks, giving the canonical location. Use it before comparing paths or checking containment. Withstrict=Trueit raises if the path doesn't exist.p.expanduser()replaces a leading~with the home directory. Paths never expand~automatically.
p.relative_to(base) returns the part of p below base: Path("/srv/app/static/a.css").relative_to("/srv/app") gives static/a.css. It raises ValueError if p isn't under base. Since 3.12, walk_up=True allows results with .. segments.
p.is_relative_to(base) returns a bool instead of raising, but it compares strings of parts, not real locations: Path("/srv/app/../etc") "is relative to" /srv/app. Resolve both sides first when the path comes from users.
p.samefile(other) checks whether two paths point to the same file on disk, accounting for links.
Pure string normalisation like os.path.normpath has no direct pathlib equivalent, because collapsing a/link/.. without asking the file system can be wrong when link is a symlink.
Example
from pathlib import Path
Path("site/static").mkdir(parents=True)
Path("site/static/a.css").touch()
Path("site/latest").symlink_to("static")
p = Path("site/static/../static/a.css")
print(p.absolute() == Path.cwd() / p) # True: no normalisation
print(p.resolve() == Path.cwd() / "site/static/a.css") # True
print(Path("site/latest/a.css").resolve().parent.name) # static
print(Path("/srv/app/static/a.css").relative_to("/srv/app")) # static/a.css
print(Path("/srv/app").relative_to("/srv/app/static", walk_up=True)) # ..
print(Path("/srv/app/../etc").is_relative_to("/srv/app")) # True (!)
print(Path("~/notes").expanduser().is_absolute()) # TrueRemember
resolve()canonicalises: absolute, no.., symlinks followedrelative_tostrips a base prefix and raises if the path isn't under itis_relative_tois lexical; resolve user-supplied paths first
Watch out for
- Treating
Path('~/x')as the home folder without callingexpanduser().