mirror of
https://github.com/python/cpython.git
synced 2025-10-19 07:53:46 +00:00
GH-139174: Prepare pathlib.Path.info
for new methods (part 2) (#140155)
Merge `_Info`, `_StatResultInfo` and `_DirEntryInfo` into a single `_Info` class. No other changes. This will allow us to use a cached `os.stat()` result from our upcoming `_Info.stat()` method even when we have a backing `os.DirEntry`.
This commit is contained in:
parent
f4e51f253a
commit
1bfe86caaa
1 changed files with 102 additions and 138 deletions
|
@ -611,11 +611,20 @@ class PureWindowsPath(PurePath):
|
|||
__slots__ = ()
|
||||
|
||||
|
||||
class _Info:
|
||||
__slots__ = ('_path',)
|
||||
_STAT_RESULT_ERROR = [] # falsy sentinel indicating stat() failed.
|
||||
|
||||
def __init__(self, path):
|
||||
|
||||
class _Info:
|
||||
"""Implementation of pathlib.types.PathInfo that provides status
|
||||
information by querying a wrapped os.stat_result object. Don't try to
|
||||
construct it yourself."""
|
||||
__slots__ = ('_path', '_entry', '_stat_result', '_lstat_result')
|
||||
|
||||
def __init__(self, path, entry=None):
|
||||
self._path = path
|
||||
self._entry = entry
|
||||
self._stat_result = None
|
||||
self._lstat_result = None
|
||||
|
||||
def __repr__(self):
|
||||
path_type = "WindowsPath" if os.name == "nt" else "PosixPath"
|
||||
|
@ -623,7 +632,94 @@ def __repr__(self):
|
|||
|
||||
def _stat(self, *, follow_symlinks=True):
|
||||
"""Return the status as an os.stat_result."""
|
||||
raise NotImplementedError
|
||||
if self._entry:
|
||||
return self._entry.stat(follow_symlinks=follow_symlinks)
|
||||
if follow_symlinks:
|
||||
if not self._stat_result:
|
||||
try:
|
||||
self._stat_result = os.stat(self._path)
|
||||
except (OSError, ValueError):
|
||||
self._stat_result = _STAT_RESULT_ERROR
|
||||
raise
|
||||
return self._stat_result
|
||||
else:
|
||||
if not self._lstat_result:
|
||||
try:
|
||||
self._lstat_result = os.lstat(self._path)
|
||||
except (OSError, ValueError):
|
||||
self._lstat_result = _STAT_RESULT_ERROR
|
||||
raise
|
||||
return self._lstat_result
|
||||
|
||||
def exists(self, *, follow_symlinks=True):
|
||||
"""Whether this path exists."""
|
||||
if self._entry:
|
||||
if not follow_symlinks:
|
||||
return True
|
||||
if follow_symlinks:
|
||||
if self._stat_result is _STAT_RESULT_ERROR:
|
||||
return False
|
||||
else:
|
||||
if self._lstat_result is _STAT_RESULT_ERROR:
|
||||
return False
|
||||
try:
|
||||
self._stat(follow_symlinks=follow_symlinks)
|
||||
except (OSError, ValueError):
|
||||
return False
|
||||
return True
|
||||
|
||||
def is_dir(self, *, follow_symlinks=True):
|
||||
"""Whether this path is a directory."""
|
||||
if self._entry:
|
||||
try:
|
||||
return self._entry.is_dir(follow_symlinks=follow_symlinks)
|
||||
except OSError:
|
||||
return False
|
||||
if follow_symlinks:
|
||||
if self._stat_result is _STAT_RESULT_ERROR:
|
||||
return False
|
||||
else:
|
||||
if self._lstat_result is _STAT_RESULT_ERROR:
|
||||
return False
|
||||
try:
|
||||
st = self._stat(follow_symlinks=follow_symlinks)
|
||||
except (OSError, ValueError):
|
||||
return False
|
||||
return S_ISDIR(st.st_mode)
|
||||
|
||||
def is_file(self, *, follow_symlinks=True):
|
||||
"""Whether this path is a regular file."""
|
||||
if self._entry:
|
||||
try:
|
||||
return self._entry.is_file(follow_symlinks=follow_symlinks)
|
||||
except OSError:
|
||||
return False
|
||||
if follow_symlinks:
|
||||
if self._stat_result is _STAT_RESULT_ERROR:
|
||||
return False
|
||||
else:
|
||||
if self._lstat_result is _STAT_RESULT_ERROR:
|
||||
return False
|
||||
try:
|
||||
st = self._stat(follow_symlinks=follow_symlinks)
|
||||
except (OSError, ValueError):
|
||||
return False
|
||||
return S_ISREG(st.st_mode)
|
||||
|
||||
def is_symlink(self):
|
||||
"""Whether this path is a symbolic link."""
|
||||
if self._entry:
|
||||
try:
|
||||
return self._entry.is_symlink()
|
||||
except OSError:
|
||||
return False
|
||||
if self._lstat_result is _STAT_RESULT_ERROR:
|
||||
return False
|
||||
try:
|
||||
st = self._stat(follow_symlinks=False)
|
||||
except (OSError, ValueError):
|
||||
return False
|
||||
return S_ISLNK(st.st_mode)
|
||||
|
||||
def _posix_permissions(self, *, follow_symlinks=True):
|
||||
"""Return the POSIX file permissions."""
|
||||
|
@ -661,138 +757,6 @@ def _xattrs(self, *, follow_symlinks=True):
|
|||
return []
|
||||
|
||||
|
||||
_STAT_RESULT_ERROR = [] # falsy sentinel indicating stat() failed.
|
||||
|
||||
|
||||
class _StatResultInfo(_Info):
|
||||
"""Implementation of pathlib.types.PathInfo that provides status
|
||||
information by querying a wrapped os.stat_result object. Don't try to
|
||||
construct it yourself."""
|
||||
__slots__ = ('_stat_result', '_lstat_result')
|
||||
|
||||
def __init__(self, path):
|
||||
super().__init__(path)
|
||||
self._stat_result = None
|
||||
self._lstat_result = None
|
||||
|
||||
def _stat(self, *, follow_symlinks=True):
|
||||
"""Return the status as an os.stat_result."""
|
||||
if follow_symlinks:
|
||||
if not self._stat_result:
|
||||
try:
|
||||
self._stat_result = os.stat(self._path)
|
||||
except (OSError, ValueError):
|
||||
self._stat_result = _STAT_RESULT_ERROR
|
||||
raise
|
||||
return self._stat_result
|
||||
else:
|
||||
if not self._lstat_result:
|
||||
try:
|
||||
self._lstat_result = os.lstat(self._path)
|
||||
except (OSError, ValueError):
|
||||
self._lstat_result = _STAT_RESULT_ERROR
|
||||
raise
|
||||
return self._lstat_result
|
||||
|
||||
def exists(self, *, follow_symlinks=True):
|
||||
"""Whether this path exists."""
|
||||
if follow_symlinks:
|
||||
if self._stat_result is _STAT_RESULT_ERROR:
|
||||
return False
|
||||
else:
|
||||
if self._lstat_result is _STAT_RESULT_ERROR:
|
||||
return False
|
||||
try:
|
||||
self._stat(follow_symlinks=follow_symlinks)
|
||||
except (OSError, ValueError):
|
||||
return False
|
||||
return True
|
||||
|
||||
def is_dir(self, *, follow_symlinks=True):
|
||||
"""Whether this path is a directory."""
|
||||
if follow_symlinks:
|
||||
if self._stat_result is _STAT_RESULT_ERROR:
|
||||
return False
|
||||
else:
|
||||
if self._lstat_result is _STAT_RESULT_ERROR:
|
||||
return False
|
||||
try:
|
||||
st = self._stat(follow_symlinks=follow_symlinks)
|
||||
except (OSError, ValueError):
|
||||
return False
|
||||
return S_ISDIR(st.st_mode)
|
||||
|
||||
def is_file(self, *, follow_symlinks=True):
|
||||
"""Whether this path is a regular file."""
|
||||
if follow_symlinks:
|
||||
if self._stat_result is _STAT_RESULT_ERROR:
|
||||
return False
|
||||
else:
|
||||
if self._lstat_result is _STAT_RESULT_ERROR:
|
||||
return False
|
||||
try:
|
||||
st = self._stat(follow_symlinks=follow_symlinks)
|
||||
except (OSError, ValueError):
|
||||
return False
|
||||
return S_ISREG(st.st_mode)
|
||||
|
||||
def is_symlink(self):
|
||||
"""Whether this path is a symbolic link."""
|
||||
if self._lstat_result is _STAT_RESULT_ERROR:
|
||||
return False
|
||||
try:
|
||||
st = self._stat(follow_symlinks=False)
|
||||
except (OSError, ValueError):
|
||||
return False
|
||||
return S_ISLNK(st.st_mode)
|
||||
|
||||
|
||||
class _DirEntryInfo(_Info):
|
||||
"""Implementation of pathlib.types.PathInfo that provides status
|
||||
information by querying a wrapped os.DirEntry object. Don't try to
|
||||
construct it yourself."""
|
||||
__slots__ = ('_entry',)
|
||||
|
||||
def __init__(self, entry):
|
||||
super().__init__(entry.path)
|
||||
self._entry = entry
|
||||
|
||||
def _stat(self, *, follow_symlinks=True):
|
||||
"""Return the status as an os.stat_result."""
|
||||
return self._entry.stat(follow_symlinks=follow_symlinks)
|
||||
|
||||
def exists(self, *, follow_symlinks=True):
|
||||
"""Whether this path exists."""
|
||||
if not follow_symlinks:
|
||||
return True
|
||||
try:
|
||||
self._stat(follow_symlinks=follow_symlinks)
|
||||
except OSError:
|
||||
return False
|
||||
return True
|
||||
|
||||
def is_dir(self, *, follow_symlinks=True):
|
||||
"""Whether this path is a directory."""
|
||||
try:
|
||||
return self._entry.is_dir(follow_symlinks=follow_symlinks)
|
||||
except OSError:
|
||||
return False
|
||||
|
||||
def is_file(self, *, follow_symlinks=True):
|
||||
"""Whether this path is a regular file."""
|
||||
try:
|
||||
return self._entry.is_file(follow_symlinks=follow_symlinks)
|
||||
except OSError:
|
||||
return False
|
||||
|
||||
def is_symlink(self):
|
||||
"""Whether this path is a symbolic link."""
|
||||
try:
|
||||
return self._entry.is_symlink()
|
||||
except OSError:
|
||||
return False
|
||||
|
||||
|
||||
def _copy_info(info, target, follow_symlinks=True):
|
||||
"""Copy metadata from the given PathInfo to the given local path."""
|
||||
copy_times_ns = (
|
||||
|
@ -877,7 +841,7 @@ def info(self):
|
|||
try:
|
||||
return self._info
|
||||
except AttributeError:
|
||||
self._info = _StatResultInfo(str(self))
|
||||
self._info = _Info(str(self))
|
||||
return self._info
|
||||
|
||||
def stat(self, *, follow_symlinks=True):
|
||||
|
@ -1057,7 +1021,7 @@ def _filter_trailing_slash(self, paths):
|
|||
def _from_dir_entry(self, dir_entry, path_str):
|
||||
path = self.with_segments(path_str)
|
||||
path._str = path_str
|
||||
path._info = _DirEntryInfo(dir_entry)
|
||||
path._info = _Info(dir_entry.path, dir_entry)
|
||||
return path
|
||||
|
||||
def iterdir(self):
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue