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
23 changes: 14 additions & 9 deletions Lib/pathlib/_abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -735,7 +735,13 @@ def absolute(self):

Use resolve() to resolve symlinks and remove '..' segments.
"""
raise UnsupportedOperation(self._unsupported_msg('absolute()'))
if self.is_absolute():
return self
elif self.parser is not posixpath:
raise UnsupportedOperation(self._unsupported_msg('absolute()'))
else:
# Treat the root directory as the current working directory.
return self.with_segments('/', *self._raw_paths)

@classmethod
def cwd(cls):
Expand Down Expand Up @@ -772,10 +778,13 @@ def resolve(self, strict=False):
"""
if self._resolving:
return self
elif self.parser is not posixpath:
raise UnsupportedOperation(self._unsupported_msg('resolve()'))

def getcwd():
return str(self.with_segments().absolute())
def raise_error(*args):
raise OSError("Unsupported operation.")

getcwd = raise_error
if strict or getattr(self.readlink, '_supported', True):
def lstat(path_str):
path = self.with_segments(path_str)
Expand All @@ -790,14 +799,10 @@ def readlink(path_str):
# If the user has *not* overridden the `readlink()` method, then
# symlinks are unsupported and (in non-strict mode) we can improve
# performance by not calling `path.lstat()`.
def skip(path_str):
# This exception will be internally consumed by `_realpath()`.
raise OSError("Operation skipped.")

lstat = readlink = skip
lstat = readlink = raise_error

return self.with_segments(posixpath._realpath(
str(self), strict, self.parser.sep,
str(self.absolute()), strict, self.parser.sep,
getcwd=getcwd, lstat=lstat, readlink=readlink,
maxlinks=self._max_symlinks))

Expand Down
22 changes: 22 additions & 0 deletions Lib/test/test_pathlib/test_pathlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -861,6 +861,28 @@ def test_move_into_other_os(self):
def test_move_into_empty_name_other_os(self):
self.test_move_into_empty_name()

def _check_complex_symlinks(self, link0_target):
super()._check_complex_symlinks(link0_target)
P = self.cls(self.base)
# Resolve relative paths.
old_path = os.getcwd()
os.chdir(self.base)
try:
p = self.cls('link0').resolve()
self.assertEqual(p, P)
self.assertEqualNormCase(str(p), self.base)
p = self.cls('link1').resolve()
self.assertEqual(p, P)
self.assertEqualNormCase(str(p), self.base)
p = self.cls('link2').resolve()
self.assertEqual(p, P)
self.assertEqualNormCase(str(p), self.base)
p = self.cls('link3').resolve()
self.assertEqual(p, P)
self.assertEqualNormCase(str(p), self.base)
finally:
os.chdir(old_path)

def test_resolve_nonexist_relative_issue38671(self):
p = self.cls('non', 'exist')

Expand Down
40 changes: 17 additions & 23 deletions Lib/test/test_pathlib/test_pathlib_abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -2493,6 +2493,23 @@ def test_glob_long_symlink(self):
bad_link.symlink_to("bad" * 200)
self.assertEqual(sorted(base.glob('**/*')), [bad_link])

@needs_posix
def test_absolute_posix(self):
P = self.cls
# The default implementation uses '/' as the current directory
self.assertEqual(str(P('').absolute()), '/')
self.assertEqual(str(P('a').absolute()), '/a')
self.assertEqual(str(P('a/b').absolute()), '/a/b')

self.assertEqual(str(P('/').absolute()), '/')
self.assertEqual(str(P('/a').absolute()), '/a')
self.assertEqual(str(P('/a/b').absolute()), '/a/b')

# '//'-prefixed absolute path (supported by POSIX).
self.assertEqual(str(P('//').absolute()), '//')
self.assertEqual(str(P('//a').absolute()), '//a')
self.assertEqual(str(P('//a/b').absolute()), '//a/b')

@needs_symlinks
def test_readlink(self):
P = self.cls(self.base)
Expand Down Expand Up @@ -2810,29 +2827,6 @@ def _check_complex_symlinks(self, link0_target):
self.assertEqual(p, P)
self.assertEqualNormCase(str(p), self.base)

# Resolve relative paths.
try:
self.cls('').absolute()
except UnsupportedOperation:
return
old_path = os.getcwd()
os.chdir(self.base)
try:
p = self.cls('link0').resolve()
self.assertEqual(p, P)
self.assertEqualNormCase(str(p), self.base)
p = self.cls('link1').resolve()
self.assertEqual(p, P)
self.assertEqualNormCase(str(p), self.base)
p = self.cls('link2').resolve()
self.assertEqual(p, P)
self.assertEqualNormCase(str(p), self.base)
p = self.cls('link3').resolve()
self.assertEqual(p, P)
self.assertEqualNormCase(str(p), self.base)
finally:
os.chdir(old_path)

@needs_symlinks
def test_complex_symlinks_absolute(self):
self._check_complex_symlinks(self.base)
Expand Down
Loading