path-utils
Cross-platform path resolver: Windows, macOS, Linux, WSL.
Metadata
- Author: ropean, Claude Sonnet (Anthropic)
- Version: 1.0.0
- Dependencies: pathlib, platform
- See Also: md-files/help/script-template.md
Code
python
#!/usr/bin/env python3
"""
@title path-utils
@description Cross-platform path resolver: Windows, macOS, Linux, WSL.
@author ropean, Claude Sonnet (Anthropic)
@version 1.0.0
Parses and resolves file paths from any of the following formats:
- Windows absolute: C:\\Users\\foo\\file.env or C:/Users/foo/file.env
- UNC: \\\\server\\share\\file.env
- WSL mount: /mnt/c/Users/foo/file.env
- Unix absolute: /home/foo/file.env
- Tilde-expanded: ~/projects/file.env
- Relative: ../file.env or .dev.vars
Can be used as a module (import resolve_path) or run directly for testing.
@example
# As a module:
from path_utils import resolve_path
p = resolve_path("C:/Users/foo/.dev.vars")
# Self-test:
python path-utils.py --test
@requires pathlib, platform
@see md-files/help/script-template.md
"""
import os
import platform
import re
import sys
from pathlib import Path, PurePosixPath, PureWindowsPath
# ════════════════════════════════════════════════════════════
# PLATFORM DETECTION
# ════════════════════════════════════════════════════════════
def _running_platform() -> str:
"""Return 'windows', 'wsl', 'macos', or 'linux'."""
if sys.platform == "win32":
return "windows"
uname = platform.uname()
if "microsoft" in uname.release.lower() or "microsoft" in uname.version.lower():
return "wsl"
if sys.platform == "darwin":
return "macos"
return "linux"
CURRENT_PLATFORM = _running_platform()
# ════════════════════════════════════════════════════════════
# PATH CLASSIFIER
# ════════════════════════════════════════════════════════════
_WIN_ABS = re.compile(r'^[A-Za-z]:[/\\]') # C:\ or C:/
_UNC = re.compile(r'^[/\\]{2}[^/\\]') # \\server or //server
_WSL_MOUNT = re.compile(r'^/mnt/[a-z]/') # /mnt/c/...
def _classify(path_str: str) -> str:
s = path_str.strip()
if _WIN_ABS.match(s):
return "windows_abs"
if _UNC.match(s):
return "unc"
if _WSL_MOUNT.match(s):
return "wsl_mount"
if s.startswith("~"):
return "tilde"
if s.startswith("/") or s.startswith("./") or s.startswith("../"):
return "unix"
# bare relative (no leading slash or dot-slash)
return "relative"
# ════════════════════════════════════════════════════════════
# CONVERSION HELPERS
# ════════════════════════════════════════════════════════════
def _win_abs_to_path(s: str) -> Path:
"""C:/Users/foo or C:\\Users\\foo → Path on any OS."""
if CURRENT_PLATFORM in ("windows",):
return Path(s)
# On WSL/Linux/macOS, convert to /mnt/c/... style
drive = s[0].lower()
rest = s[2:].replace("\\", "/").lstrip("/")
return Path(f"/mnt/{drive}/{rest}")
def _unc_to_path(s: str) -> Path:
"""\\\\server\\share\\path → Path (Windows only; warn elsewhere)."""
if CURRENT_PLATFORM == "windows":
return Path(s)
# UNC not natively supported on Linux/macOS — return as-is and let the
# caller handle the resulting error
return Path(s.replace("\\", "/"))
def _wsl_mount_to_path(s: str) -> Path:
"""
/mnt/c/Users/foo → C:\\Users\\foo on Windows,
→ /mnt/c/Users/foo on WSL/Linux (already valid).
"""
if CURRENT_PLATFORM == "windows":
# /mnt/c/Users/foo → C:\Users\foo
parts = PurePosixPath(s).parts # ('/', 'mnt', 'c', 'Users', 'foo')
drive = parts[2].upper() + ":\\"
rest = "\\".join(parts[3:])
return Path(drive + rest)
return Path(s)
# ════════════════════════════════════════════════════════════
# PUBLIC API
# ════════════════════════════════════════════════════════════
def resolve_path(path_str: str) -> Path:
"""
Parse *path_str* into a fully-resolved, absolute :class:`pathlib.Path`
on the current OS.
Supports:
- Windows absolute (C:/… or C:\\…)
- UNC (\\\\server\\share\\…)
- WSL mount (/mnt/c/…)
- Tilde (~/…)
- Unix absolute (/home/…)
- Relative (./… ../… or bare name)
Returns the Path object; does **not** assert existence so you can use it
for output paths too.
"""
s = path_str.strip()
kind = _classify(s)
if kind == "windows_abs":
p = _win_abs_to_path(s)
elif kind == "unc":
p = _unc_to_path(s)
elif kind == "wsl_mount":
p = _wsl_mount_to_path(s)
elif kind == "tilde":
p = Path(s).expanduser()
else: # unix absolute or relative
p = Path(s)
return p.resolve()
# ════════════════════════════════════════════════════════════
# SELF-TEST
# ════════════════════════════════════════════════════════════
_TEST_CASES = [
# (label, path_str, expected_fragment_on_platform)
# expected_fragment is a substring we look for in the resolved string
("Windows abs (forward slash)", "C:/Users/test/.env", None),
("Windows abs (backslash)", r"C:\Users\test\.env", None),
("WSL mount path", "/mnt/c/Users/test/.env", None),
("Tilde expansion", "~/.env", None),
("Unix absolute", "/tmp/test/.env", None),
("Relative dot-slash", "./.env", None),
("Relative bare", ".env", None),
]
def _color(code: int, text: str) -> str:
if not sys.stdout.isatty():
return text
return f"\033[{code}m{text}\033[0m"
def run_tests() -> None:
print(f"\nPlatform detected: {_color(36, CURRENT_PLATFORM)}\n")
pad = max(len(lbl) for lbl, _, _ in _TEST_CASES) + 2
passes = 0
for label, raw, _ in _TEST_CASES:
try:
result = resolve_path(raw)
status = _color(32, "PASS")
detail = str(result)
passes += 1
except Exception as exc:
status = _color(31, "FAIL")
detail = f"ERROR: {exc}"
print(f" {status} {label:<{pad}} {_color(33, repr(raw))}")
print(f" -> {detail}\n")
total = len(_TEST_CASES)
summary = _color(32 if passes == total else 31, f"{passes}/{total} passed")
print(f"Results: {summary}\n")
# ════════════════════════════════════════════════════════════
# CLI ENTRY
# ════════════════════════════════════════════════════════════
def main() -> None:
import argparse
parser = argparse.ArgumentParser(
description="Cross-platform path resolver utility.",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="Run --test to execute the built-in test suite.",
)
parser.add_argument("path", nargs="?", help="Path string to resolve")
parser.add_argument("--test", action="store_true", help="Run self-test suite")
args = parser.parse_args()
if args.test:
run_tests()
return
if args.path:
result = resolve_path(args.path)
print(result)
return
parser.print_help()
if __name__ == "__main__":
main()File Information
- Filename:
path_utils.py - Category: python
- Language: PYTHON