diff -r 29d67ac7a9d5 Lib/pathlib.py --- a/Lib/pathlib.py Tue Dec 03 02:05:42 2013 +0100 +++ b/Lib/pathlib.py Tue Dec 03 15:51:50 2013 +0800 @@ -178,7 +178,7 @@ def casefold_parts(self, parts): return [p.lower() for p in parts] - def resolve(self, path): + def resolve(self, path, *, strict=True): s = str(path) if not s: return os.getcwd() @@ -255,7 +255,7 @@ def casefold_parts(self, parts): return parts - def resolve(self, path): + def resolve(self, path, *, strict=True): sep = self.sep def split(p): return [x for x in p.split(sep) if x] @@ -282,7 +282,10 @@ target = accessor.readlink(cur) except OSError as e: if e.errno != EINVAL: - raise + if strict: + raise + else: + return cur # Not a symlink resolved = cur else: @@ -1013,7 +1016,7 @@ obj._init(template=self) return obj - def resolve(self): + def resolve(self, *, strict=True): """ Make the path absolute, resolving all symlinks on the way and also normalizing it (for example turning slashes into backslashes under @@ -1021,7 +1024,7 @@ """ if self._closed: self._raise_closed() - s = self._flavour.resolve(self) + s = self._flavour.resolve(self, strict=strict) if s is None: # No symlink resolution => for consistency, raise an error if # the path doesn't exist or is forbidden diff -r 29d67ac7a9d5 Lib/test/test_pathlib.py --- a/Lib/test/test_pathlib.py Tue Dec 03 02:05:42 2013 +0100 +++ b/Lib/test/test_pathlib.py Tue Dec 03 15:51:50 2013 +0800 @@ -1252,6 +1252,12 @@ with self.assertRaises(OSError) as cm: p.resolve() self.assertEqual(cm.exception.errno, errno.ENOENT) + # Non-strict + self.assertEqual(str(p.resolve(strict=False)), + os.path.join(BASE, 'foo')) + p = P(BASE, 'foo', 'in', 'a', 'fairyland') + self.assertEqual(str(p.resolve(strict=False)), + os.path.join(BASE, 'foo')) # These are all relative symlinks p = P(BASE, 'dirB', 'fileB') self._check_resolve_relative(p, p) @@ -1261,6 +1267,10 @@ self._check_resolve_relative(p, P(BASE, 'dirB', 'fileB')) p = P(BASE, 'dirB', 'linkD', 'fileB') self._check_resolve_relative(p, P(BASE, 'dirB', 'fileB')) + # Non-strict + p = P(BASE, 'dirA', 'linkC', 'fileB', 'foo', 'in', 'a', 'fairyland') + self.assertEqual(p.resolve(strict=False), + P(BASE, 'dirB', 'fileB', 'foo')) # Now create absolute symlinks d = tempfile.mkdtemp(suffix='-dirD') self.addCleanup(shutil.rmtree, d) @@ -1268,6 +1278,9 @@ os.symlink(join('dirB'), os.path.join(d, 'linkY')) p = P(BASE, 'dirA', 'linkX', 'linkY', 'fileB') self._check_resolve_absolute(p, P(BASE, 'dirB', 'fileB')) + # Non-strict + p = P(BASE, 'dirA', 'linkX', 'linkY', 'foo', 'in', 'a', 'fairy', 'land') + self.assertEqual(p.resolve(strict=False), P(BASE, 'dirB', 'foo')) def test_with(self): p = self.cls(BASE) @@ -1632,6 +1645,10 @@ self._check_symlink_loop(BASE, 'linkY') os.symlink('linkZ/../linkZ', join('linkZ')) self._check_symlink_loop(BASE, 'linkZ') + # Non-strict + path = P(BASE, 'linkX', 'foo') + with self.assertRaises(RuntimeError): + path.resolve(strict=False) # Loops with absolute symlinks os.symlink(join('linkU/inside'), join('linkU')) self._check_symlink_loop(BASE, 'linkU') @@ -1639,6 +1656,10 @@ self._check_symlink_loop(BASE, 'linkV') os.symlink(join('linkW/../linkW'), join('linkW')) self._check_symlink_loop(BASE, 'linkW') + # Non-strict + path = P(BASE, 'linkU', 'foo') + with self.assertRaises(RuntimeError): + path.resolve(strict=False) def test_glob(self): P = self.cls