_path.py 1.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041
  1. """Utilities for working with paths."""
  2. from collections.abc import Sequence
  3. from contextlib import suppress
  4. def normalize_path_segments(segments: Sequence[str]) -> list[str]:
  5. """Drop '.' and '..' from a sequence of str segments"""
  6. resolved_path: list[str] = []
  7. for seg in segments:
  8. if seg == "..":
  9. # ignore any .. segments that would otherwise cause an
  10. # IndexError when popped from resolved_path if
  11. # resolving for rfc3986
  12. with suppress(IndexError):
  13. resolved_path.pop()
  14. elif seg != ".":
  15. resolved_path.append(seg)
  16. if segments and segments[-1] in (".", ".."):
  17. # do some post-processing here.
  18. # if the last segment was a relative dir,
  19. # then we need to append the trailing '/'
  20. resolved_path.append("")
  21. return resolved_path
  22. def normalize_path(path: str) -> str:
  23. # Drop '.' and '..' from str path
  24. prefix = ""
  25. if path and path[0] == "/":
  26. # preserve the "/" root element of absolute paths, copying it to the
  27. # normalised output as per sections 5.2.4 and 6.2.2.3 of rfc3986.
  28. prefix = "/"
  29. path = path[1:]
  30. segments = path.split("/")
  31. return prefix + "/".join(normalize_path_segments(segments))