Skip to content

Commit 60ec854

Browse files
authored
gh-126780: Fix ntpath.normpath() for drive-relative paths (GH-126801)
1 parent 0c5556f commit 60ec854

File tree

4 files changed

+34
-25
lines changed

4 files changed

+34
-25
lines changed

Lib/test/test_ntpath.py

+5
Original file line numberDiff line numberDiff line change
@@ -347,13 +347,18 @@ def test_normpath(self):
347347

348348
tester("ntpath.normpath('..')", r'..')
349349
tester("ntpath.normpath('.')", r'.')
350+
tester("ntpath.normpath('c:.')", 'c:')
350351
tester("ntpath.normpath('')", r'.')
351352
tester("ntpath.normpath('/')", '\\')
352353
tester("ntpath.normpath('c:/')", 'c:\\')
353354
tester("ntpath.normpath('/../.././..')", '\\')
354355
tester("ntpath.normpath('c:/../../..')", 'c:\\')
356+
tester("ntpath.normpath('/./a/b')", r'\a\b')
357+
tester("ntpath.normpath('c:/./a/b')", r'c:\a\b')
355358
tester("ntpath.normpath('../.././..')", r'..\..\..')
356359
tester("ntpath.normpath('K:../.././..')", r'K:..\..\..')
360+
tester("ntpath.normpath('./a/b')", r'a\b')
361+
tester("ntpath.normpath('c:./a/b')", r'c:a\b')
357362
tester("ntpath.normpath('C:////a/b')", r'C:\a\b')
358363
tester("ntpath.normpath('//machine/share//a/b')", r'\\machine\share\a\b')
359364

Lib/test/test_posixpath.py

+2
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,7 @@ def test_expanduser_pwd2(self):
379379
("/.", "/"),
380380
("/./", "/"),
381381
("/.//.", "/"),
382+
("/./foo/bar", "/foo/bar"),
382383
("/foo", "/foo"),
383384
("/foo/bar", "/foo/bar"),
384385
("//", "//"),
@@ -388,6 +389,7 @@ def test_expanduser_pwd2(self):
388389
("///..//./foo/.//bar", "/foo/bar"),
389390
(".", "."),
390391
(".//.", "."),
392+
("./foo/bar", "foo/bar"),
391393
("..", ".."),
392394
("../", ".."),
393395
("../foo", "../foo"),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix :func:`os.path.normpath` for drive-relative paths on Windows.

Python/fileutils.c

+26-25
Original file line numberDiff line numberDiff line change
@@ -2506,37 +2506,38 @@ _Py_normpath_and_size(wchar_t *path, Py_ssize_t size, Py_ssize_t *normsize)
25062506
#endif
25072507
#define SEP_OR_END(x) (IS_SEP(x) || IS_END(x))
25082508

2509-
if (p1[0] == L'.' && IS_SEP(&p1[1])) {
2510-
// Skip leading '.\'
2511-
path = &path[2];
2512-
while (IS_SEP(path)) {
2513-
path++;
2514-
}
2515-
p1 = p2 = minP2 = path;
2516-
lastC = SEP;
2517-
}
2518-
else {
2519-
Py_ssize_t drvsize, rootsize;
2520-
_Py_skiproot(path, size, &drvsize, &rootsize);
2521-
if (drvsize || rootsize) {
2522-
// Skip past root and update minP2
2523-
p1 = &path[drvsize + rootsize];
2509+
Py_ssize_t drvsize, rootsize;
2510+
_Py_skiproot(path, size, &drvsize, &rootsize);
2511+
if (drvsize || rootsize) {
2512+
// Skip past root and update minP2
2513+
p1 = &path[drvsize + rootsize];
25242514
#ifndef ALTSEP
2525-
p2 = p1;
2515+
p2 = p1;
25262516
#else
2527-
for (; p2 < p1; ++p2) {
2528-
if (*p2 == ALTSEP) {
2529-
*p2 = SEP;
2530-
}
2517+
for (; p2 < p1; ++p2) {
2518+
if (*p2 == ALTSEP) {
2519+
*p2 = SEP;
25312520
}
2521+
}
25322522
#endif
2533-
minP2 = p2 - 1;
2534-
lastC = *minP2;
2523+
minP2 = p2 - 1;
2524+
lastC = *minP2;
25352525
#ifdef MS_WINDOWS
2536-
if (lastC != SEP) {
2537-
minP2++;
2538-
}
2526+
if (lastC != SEP) {
2527+
minP2++;
2528+
}
2529+
#endif
2530+
}
2531+
if (p1[0] == L'.' && SEP_OR_END(&p1[1])) {
2532+
// Skip leading '.\'
2533+
lastC = *++p1;
2534+
#ifdef ALTSEP
2535+
if (lastC == ALTSEP) {
2536+
lastC = SEP;
2537+
}
25392538
#endif
2539+
while (IS_SEP(p1)) {
2540+
p1++;
25402541
}
25412542
}
25422543

0 commit comments

Comments
 (0)