Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 8 additions & 11 deletions Lib/pathlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,19 +187,18 @@ def resolve(self, path, strict=False):
if strict:
return self._ext_to_normal(_getfinalpathname(s))
else:
tail_parts = [] # End of the path after the first one not found
while True:
try:
s = self._ext_to_normal(_getfinalpathname(s))
except FileNotFoundError:
previous_s = s
s = os.path.dirname(s)
s, tail = os.path.split(s)
tail_parts.append(tail)
if previous_s == s:
return path
else:
if previous_s is None:
return s
else:
return s + os.path.sep + os.path.basename(previous_s)
return os.path.join(s, *reversed(tail_parts))
# Means fallback on absolute
return None

Expand Down Expand Up @@ -330,12 +329,10 @@ def _resolve(path, rest):
try:
target = accessor.readlink(newpath)
except OSError as e:
if e.errno != EINVAL:
if strict:
raise
else:
return newpath
# Not a symlink
if e.errno != EINVAL and strict:
raise
# Not a symlink, or non-strict mode. We just leave the path
# untouched.
path = newpath
else:
seen[newpath] = None # not resolved symlink
Expand Down
21 changes: 12 additions & 9 deletions Lib/test/test_pathlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -1507,10 +1507,10 @@ def test_resolve_common(self):
os.path.join(BASE, 'foo'))
p = P(BASE, 'foo', 'in', 'spam')
self.assertEqual(str(p.resolve(strict=False)),
os.path.join(BASE, 'foo'))
os.path.join(BASE, 'foo', 'in', 'spam'))
p = P(BASE, '..', 'foo', 'in', 'spam')
self.assertEqual(str(p.resolve(strict=False)),
os.path.abspath(os.path.join('foo')))
os.path.abspath(os.path.join('foo', 'in', 'spam')))
# These are all relative symlinks
p = P(BASE, 'dirB', 'fileB')
self._check_resolve_relative(p, p)
Expand All @@ -1522,16 +1522,18 @@ def test_resolve_common(self):
self._check_resolve_relative(p, P(BASE, 'dirB', 'fileB'))
# Non-strict
p = P(BASE, 'dirA', 'linkC', 'fileB', 'foo', 'in', 'spam')
self._check_resolve_relative(p, P(BASE, 'dirB', 'fileB', 'foo'), False)
self._check_resolve_relative(p, P(BASE, 'dirB', 'fileB', 'foo', 'in',
'spam'), False)
p = P(BASE, 'dirA', 'linkC', '..', 'foo', 'in', 'spam')
if os.name == 'nt':
# In Windows, if linkY points to dirB, 'dirA\linkY\..'
# resolves to 'dirA' without resolving linkY first.
self._check_resolve_relative(p, P(BASE, 'dirA', 'foo'), False)
self._check_resolve_relative(p, P(BASE, 'dirA', 'foo', 'in',
'spam'), False)
else:
# In Posix, if linkY points to dirB, 'dirA/linkY/..'
# resolves to 'dirB/..' first before resolving to parent of dirB.
self._check_resolve_relative(p, P(BASE, 'foo'), False)
self._check_resolve_relative(p, P(BASE, 'foo', 'in', 'spam'), False)
# Now create absolute symlinks
d = tempfile.mkdtemp(suffix='-dirD')
self.addCleanup(support.rmtree, d)
Expand All @@ -1541,16 +1543,17 @@ def test_resolve_common(self):
self._check_resolve_absolute(p, P(BASE, 'dirB', 'fileB'))
# Non-strict
p = P(BASE, 'dirA', 'linkX', 'linkY', 'foo', 'in', 'spam')
self._check_resolve_relative(p, P(BASE, 'dirB', 'foo'), False)
self._check_resolve_relative(p, P(BASE, 'dirB', 'foo', 'in', 'spam'),
False)
p = P(BASE, 'dirA', 'linkX', 'linkY', '..', 'foo', 'in', 'spam')
if os.name == 'nt':
# In Windows, if linkY points to dirB, 'dirA\linkY\..'
# resolves to 'dirA' without resolving linkY first.
self._check_resolve_relative(p, P(d, 'foo'), False)
self._check_resolve_relative(p, P(d, 'foo', 'in', 'spam'), False)
else:
# In Posix, if linkY points to dirB, 'dirA/linkY/..'
# resolves to 'dirB/..' first before resolving to parent of dirB.
self._check_resolve_relative(p, P(BASE, 'foo'), False)
self._check_resolve_relative(p, P(BASE, 'foo', 'in', 'spam'), False)

@with_symlinks
def test_resolve_dot(self):
Expand All @@ -1564,7 +1567,7 @@ def test_resolve_dot(self):
r = q / '3' / '4'
self.assertRaises(FileNotFoundError, r.resolve, strict=True)
# Non-strict
self.assertEqual(r.resolve(strict=False), p / '3')
self.assertEqual(r.resolve(strict=False), p / '3' / '4')

def test_with(self):
p = self.cls(BASE)
Expand Down
1 change: 1 addition & 0 deletions Misc/ACKS
Original file line number Diff line number Diff line change
Expand Up @@ -1190,6 +1190,7 @@ Steve Piercy
Jim St. Pierre
Dan Pierson
Martijn Pieters
Antoine Pietri
Anand B. Pillai
François Pinard
Tom Pinckney
Expand Down