Skip to content

Commit 30f81ab

Browse files
committed
bpo-30177: pathlib: include the full path in resolve(strict=False)
1 parent a5aa72a commit 30f81ab

File tree

3 files changed

+21
-20
lines changed

3 files changed

+21
-20
lines changed

Lib/pathlib.py

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -183,19 +183,18 @@ def resolve(self, path, strict=False):
183183
if strict:
184184
return self._ext_to_normal(_getfinalpathname(s))
185185
else:
186+
tail_parts = [] # End of the path after the first one not found
186187
while True:
187188
try:
188189
s = self._ext_to_normal(_getfinalpathname(s))
189190
except FileNotFoundError:
190191
previous_s = s
191-
s = os.path.dirname(s)
192+
s, tail = os.path.split(s)
193+
tail_parts.append(tail)
192194
if previous_s == s:
193195
return path
194196
else:
195-
if previous_s is None:
196-
return s
197-
else:
198-
return s + os.path.sep + os.path.basename(previous_s)
197+
return os.path.join(s, *reversed(tail_parts))
199198
# Means fallback on absolute
200199
return None
201200

@@ -326,12 +325,10 @@ def _resolve(path, rest):
326325
try:
327326
target = accessor.readlink(newpath)
328327
except OSError as e:
329-
if e.errno != EINVAL:
330-
if strict:
331-
raise
332-
else:
333-
return newpath
334-
# Not a symlink
328+
if e.errno != EINVAL and strict:
329+
raise
330+
# Not a symlink, or non-strict mode. We just leave the path
331+
# untouched.
335332
path = newpath
336333
else:
337334
seen[newpath] = None # not resolved symlink

Lib/test/test_pathlib.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1492,10 +1492,10 @@ def test_resolve_common(self):
14921492
os.path.join(BASE, 'foo'))
14931493
p = P(BASE, 'foo', 'in', 'spam')
14941494
self.assertEqual(str(p.resolve(strict=False)),
1495-
os.path.join(BASE, 'foo'))
1495+
os.path.join(BASE, 'foo', 'in', 'spam'))
14961496
p = P(BASE, '..', 'foo', 'in', 'spam')
14971497
self.assertEqual(str(p.resolve(strict=False)),
1498-
os.path.abspath(os.path.join('foo')))
1498+
os.path.abspath(os.path.join('foo', 'in', 'spam')))
14991499
# These are all relative symlinks
15001500
p = P(BASE, 'dirB', 'fileB')
15011501
self._check_resolve_relative(p, p)
@@ -1507,16 +1507,18 @@ def test_resolve_common(self):
15071507
self._check_resolve_relative(p, P(BASE, 'dirB', 'fileB'))
15081508
# Non-strict
15091509
p = P(BASE, 'dirA', 'linkC', 'fileB', 'foo', 'in', 'spam')
1510-
self._check_resolve_relative(p, P(BASE, 'dirB', 'fileB', 'foo'), False)
1510+
self._check_resolve_relative(p, P(BASE, 'dirB', 'fileB', 'foo', 'in',
1511+
'spam'), False)
15111512
p = P(BASE, 'dirA', 'linkC', '..', 'foo', 'in', 'spam')
15121513
if os.name == 'nt':
15131514
# In Windows, if linkY points to dirB, 'dirA\linkY\..'
15141515
# resolves to 'dirA' without resolving linkY first.
1515-
self._check_resolve_relative(p, P(BASE, 'dirA', 'foo'), False)
1516+
self._check_resolve_relative(p, P(BASE, 'dirA', 'foo', 'in',
1517+
'spam'), False)
15161518
else:
15171519
# In Posix, if linkY points to dirB, 'dirA/linkY/..'
15181520
# resolves to 'dirB/..' first before resolving to parent of dirB.
1519-
self._check_resolve_relative(p, P(BASE, 'foo'), False)
1521+
self._check_resolve_relative(p, P(BASE, 'foo', 'in', 'spam'), False)
15201522
# Now create absolute symlinks
15211523
d = tempfile.mkdtemp(suffix='-dirD')
15221524
self.addCleanup(support.rmtree, d)
@@ -1526,16 +1528,17 @@ def test_resolve_common(self):
15261528
self._check_resolve_absolute(p, P(BASE, 'dirB', 'fileB'))
15271529
# Non-strict
15281530
p = P(BASE, 'dirA', 'linkX', 'linkY', 'foo', 'in', 'spam')
1529-
self._check_resolve_relative(p, P(BASE, 'dirB', 'foo'), False)
1531+
self._check_resolve_relative(p, P(BASE, 'dirB', 'foo', 'in', 'spam'),
1532+
False)
15301533
p = P(BASE, 'dirA', 'linkX', 'linkY', '..', 'foo', 'in', 'spam')
15311534
if os.name == 'nt':
15321535
# In Windows, if linkY points to dirB, 'dirA\linkY\..'
15331536
# resolves to 'dirA' without resolving linkY first.
1534-
self._check_resolve_relative(p, P(d, 'foo'), False)
1537+
self._check_resolve_relative(p, P(d, 'foo', 'in', 'spam'), False)
15351538
else:
15361539
# In Posix, if linkY points to dirB, 'dirA/linkY/..'
15371540
# resolves to 'dirB/..' first before resolving to parent of dirB.
1538-
self._check_resolve_relative(p, P(BASE, 'foo'), False)
1541+
self._check_resolve_relative(p, P(BASE, 'foo', 'in', 'spam'), False)
15391542

15401543
@support.skip_unless_symlink
15411544
def test_resolve_dot(self):
@@ -1549,7 +1552,7 @@ def test_resolve_dot(self):
15491552
r = q / '3' / '4'
15501553
self.assertRaises(FileNotFoundError, r.resolve, strict=True)
15511554
# Non-strict
1552-
self.assertEqual(r.resolve(strict=False), p / '3')
1555+
self.assertEqual(r.resolve(strict=False), p / '3' / '4')
15531556

15541557
def test_with(self):
15551558
p = self.cls(BASE)

Misc/ACKS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1197,6 +1197,7 @@ Steve Piercy
11971197
Jim St. Pierre
11981198
Dan Pierson
11991199
Martijn Pieters
1200+
Antoine Pietri
12001201
Anand B. Pillai
12011202
François Pinard
12021203
Tom Pinckney

0 commit comments

Comments
 (0)