pathlib ABCs: tighten up resolve() and absolute() (#126611)

In `PathBase.resolve()`, raise `UnsupportedOperation` if a non-POSIX path
parser is used (our implementation uses `posixpath._realpath()`, which
produces incorrect results for non-POSIX path flavours.) Also tweak code to
call `self.absolute()` upfront rather than supplying an emulated `getcwd()`
function.

Adjust `PathBase.absolute()` to work somewhat like `resolve()`. If a POSIX
path parser is used, we treat the root directory as the current directory.
This is the simplest useful behaviour for concrete path types without a
current directory cursor.
This commit is contained in:
Barney Gale 2024-11-09 18:47:49 +00:00 committed by GitHub
parent 0f47a3199c
commit 266328552e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 53 additions and 32 deletions

View file

@ -735,7 +735,13 @@ class PathBase(PurePathBase):
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):
@ -772,10 +778,13 @@ class PathBase(PurePathBase):
"""
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)
@ -790,14 +799,10 @@ class PathBase(PurePathBase):
# 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))