Skip to content

Commit dfbd9e6

Browse files
committed
os-path: implement normpath and fix abspath
normpath was a no-op stub that returned the input unchanged. This caused abspath to produce un-normalized paths containing "." and ".." components (e.g. "/cwd/./foo" instead of "/cwd/foo"). Implement normpath following CPython posixpath semantics: - collapse "." components - resolve ".." by removing the preceding component - collapse multiple consecutive slashes - preserve POSIX double-slash "//" at path start - return "." for empty input Update abspath to call normpath on the result.
1 parent 8a184c4 commit dfbd9e6

1 file changed

Lines changed: 26 additions & 4 deletions

File tree

python-stdlib/os-path/os/path.py

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,35 @@ def normcase(s):
99

1010

1111
def normpath(s):
12-
return s
12+
if not s:
13+
return "."
14+
slash = "/"
15+
initial_slashes = s.startswith(slash)
16+
# POSIX: leading double slash is implementation-defined, keep exactly two.
17+
if initial_slashes and s.startswith("//") and not s.startswith("///"):
18+
initial_slashes = 2
19+
comps = s.split(slash)
20+
new_comps = []
21+
for comp in comps:
22+
if not comp or comp == ".":
23+
continue
24+
if comp == "..":
25+
if new_comps and new_comps[-1] != "..":
26+
new_comps.pop()
27+
elif not initial_slashes:
28+
new_comps.append(comp)
29+
else:
30+
new_comps.append(comp)
31+
s = slash.join(new_comps)
32+
if initial_slashes:
33+
s = slash * initial_slashes + s
34+
return s or "."
1335

1436

1537
def abspath(s):
16-
if s[0] != "/":
17-
return os.getcwd() + "/" + s
18-
return s
38+
if not s.startswith("/"):
39+
s = os.getcwd() + "/" + s
40+
return normpath(s)
1941

2042

2143
realpath = os.realpath

0 commit comments

Comments
 (0)