absolute.py 849 B

1234567891011121314151617181920212223242526
  1. """Whether a path is absolute on any platform, and where an absolute path sits under a root."""
  2. from __future__ import annotations
  3. import ntpath
  4. import os
  5. from pathlib import PurePath
  6. def spelled(path: str) -> bool:
  7. """True for a rooted, drive-qualified or UNC path, whichever platform reads it."""
  8. return (
  9. os.path.isabs(path)
  10. or path.replace("\\", "/").startswith("/")
  11. or bool(ntpath.splitdrive(path)[0])
  12. )
  13. def relative(path: str, root: str) -> str | None:
  14. """Where a normalised absolute `path` sits below `root`, as "a/b" ("." for root); else None."""
  15. try:
  16. inside = PurePath(path).relative_to(root)
  17. except ValueError:
  18. return None
  19. # A ".." could name somewhere above root; a normalised path never carries one.
  20. return None if ".." in inside.parts else inside.as_posix()