bpo-30177: pathlib: include the full path in resolve(strict=False) (#1893)

This commit is contained in:
Antoine Pietri 2017-06-07 17:29:17 +02:00 committed by Steve Dower
parent ff48739ed0
commit add98eb4fe
3 changed files with 21 additions and 20 deletions

View File

@ -183,19 +183,18 @@ class _WindowsFlavour(_Flavour):
if strict: if strict:
return self._ext_to_normal(_getfinalpathname(s)) return self._ext_to_normal(_getfinalpathname(s))
else: else:
tail_parts = [] # End of the path after the first one not found
while True: while True:
try: try:
s = self._ext_to_normal(_getfinalpathname(s)) s = self._ext_to_normal(_getfinalpathname(s))
except FileNotFoundError: except FileNotFoundError:
previous_s = s previous_s = s
s = os.path.dirname(s) s, tail = os.path.split(s)
tail_parts.append(tail)
if previous_s == s: if previous_s == s:
return path return path
else: else:
if previous_s is None: return os.path.join(s, *reversed(tail_parts))
return s
else:
return s + os.path.sep + os.path.basename(previous_s)
# Means fallback on absolute # Means fallback on absolute
return None return None
@ -326,12 +325,10 @@ class _PosixFlavour(_Flavour):
try: try:
target = accessor.readlink(newpath) target = accessor.readlink(newpath)
except OSError as e: except OSError as e:
if e.errno != EINVAL: if e.errno != EINVAL and strict:
if strict: raise
raise # Not a symlink, or non-strict mode. We just leave the path
else: # untouched.
return newpath
# Not a symlink
path = newpath path = newpath
else: else:
seen[newpath] = None # not resolved symlink seen[newpath] = None # not resolved symlink

View File

@ -1492,10 +1492,10 @@ class _BasePathTest(object):
os.path.join(BASE, 'foo')) os.path.join(BASE, 'foo'))
p = P(BASE, 'foo', 'in', 'spam') p = P(BASE, 'foo', 'in', 'spam')
self.assertEqual(str(p.resolve(strict=False)), 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') p = P(BASE, '..', 'foo', 'in', 'spam')
self.assertEqual(str(p.resolve(strict=False)), 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 # These are all relative symlinks
p = P(BASE, 'dirB', 'fileB') p = P(BASE, 'dirB', 'fileB')
self._check_resolve_relative(p, p) self._check_resolve_relative(p, p)
@ -1507,16 +1507,18 @@ class _BasePathTest(object):
self._check_resolve_relative(p, P(BASE, 'dirB', 'fileB')) self._check_resolve_relative(p, P(BASE, 'dirB', 'fileB'))
# Non-strict # Non-strict
p = P(BASE, 'dirA', 'linkC', 'fileB', 'foo', 'in', 'spam') 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') p = P(BASE, 'dirA', 'linkC', '..', 'foo', 'in', 'spam')
if os.name == 'nt': if os.name == 'nt':
# In Windows, if linkY points to dirB, 'dirA\linkY\..' # In Windows, if linkY points to dirB, 'dirA\linkY\..'
# resolves to 'dirA' without resolving linkY first. # 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: else:
# In Posix, if linkY points to dirB, 'dirA/linkY/..' # In Posix, if linkY points to dirB, 'dirA/linkY/..'
# resolves to 'dirB/..' first before resolving to parent of dirB. # 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 # Now create absolute symlinks
d = tempfile.mkdtemp(suffix='-dirD') d = tempfile.mkdtemp(suffix='-dirD')
self.addCleanup(support.rmtree, d) self.addCleanup(support.rmtree, d)
@ -1526,16 +1528,17 @@ class _BasePathTest(object):
self._check_resolve_absolute(p, P(BASE, 'dirB', 'fileB')) self._check_resolve_absolute(p, P(BASE, 'dirB', 'fileB'))
# Non-strict # Non-strict
p = P(BASE, 'dirA', 'linkX', 'linkY', 'foo', 'in', 'spam') 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') p = P(BASE, 'dirA', 'linkX', 'linkY', '..', 'foo', 'in', 'spam')
if os.name == 'nt': if os.name == 'nt':
# In Windows, if linkY points to dirB, 'dirA\linkY\..' # In Windows, if linkY points to dirB, 'dirA\linkY\..'
# resolves to 'dirA' without resolving linkY first. # 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: else:
# In Posix, if linkY points to dirB, 'dirA/linkY/..' # In Posix, if linkY points to dirB, 'dirA/linkY/..'
# resolves to 'dirB/..' first before resolving to parent of dirB. # 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)
@support.skip_unless_symlink @support.skip_unless_symlink
def test_resolve_dot(self): def test_resolve_dot(self):
@ -1549,7 +1552,7 @@ class _BasePathTest(object):
r = q / '3' / '4' r = q / '3' / '4'
self.assertRaises(FileNotFoundError, r.resolve, strict=True) self.assertRaises(FileNotFoundError, r.resolve, strict=True)
# Non-strict # Non-strict
self.assertEqual(r.resolve(strict=False), p / '3') self.assertEqual(r.resolve(strict=False), p / '3' / '4')
def test_with(self): def test_with(self):
p = self.cls(BASE) p = self.cls(BASE)

View File

@ -1201,6 +1201,7 @@ Steve Piercy
Jim St. Pierre Jim St. Pierre
Dan Pierson Dan Pierson
Martijn Pieters Martijn Pieters
Antoine Pietri
Anand B. Pillai Anand B. Pillai
François Pinard François Pinard
Tom Pinckney Tom Pinckney