GH-125413: Add private metadata methods to pathlib.Path.info (#129897)

Add the following private methods to `pathlib.Path.info`:

- `_posix_permissions()`: the POSIX file permissions (`S_IMODE(st_mode)`)
- `_file_id()`: the file ID (`(st_dev, st_ino)`)
- `_access_time_ns()`: the access time in nanoseconds (`st_atime_ns`)
- `_mod_time_ns()`: the modify time in nanoseconds (`st_mtime_ns`)
- `_bsd_flags()`: the BSD file flags (`st_flags`)
- `_xattrs()`: the file extended attributes as a list of key, value pairs,
  or an empty list if `listxattr()` or `getxattr()` fail in an ignorable 
  way.

These methods replace `LocalCopyReader.read_metadata()`, and so we can
delete the `CopyReader` and `LocalCopyReader` classes. Rather than reading
metadata via `source._copy_reader.read_metadata()`, we instead call
`source.info._posix_permissions()`, `_access_time_ns()`, etc.

Preserving metadata is only supported for local-to-local copies at the
moment. To support copying metadata between arbitrary `ReadablePath` and
`WritablePath` objects, we'd need to make the new methods public and
documented.

Co-authored-by: Petr Viktorin <encukou@gmail.com>
This commit is contained in:
Barney Gale 2025-02-17 19:15:25 +00:00 committed by GitHub
parent bd1642c6e5
commit 7fcace99bb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 205 additions and 207 deletions

View file

@ -1440,11 +1440,13 @@ class PathTest(test_pathlib_abc.RWPathTest, PurePathTest):
if hasattr(os, 'chflags') and hasattr(stat, 'UF_NODUMP'):
os.chflags(source / 'fileC', stat.UF_NODUMP)
target = base / 'copyA'
source.copy(target, preserve_metadata=True)
for subpath in ['.', 'fileC', 'dirD', 'dirD/fileD']:
source_st = source.joinpath(subpath).stat()
target_st = target.joinpath(subpath).stat()
subpaths = ['.', 'fileC', 'dirD', 'dirD/fileD']
source_sts = [source.joinpath(subpath).stat() for subpath in subpaths]
source.copy(target, preserve_metadata=True)
target_sts = [target.joinpath(subpath).stat() for subpath in subpaths]
for source_st, target_st in zip(source_sts, target_sts):
self.assertLessEqual(source_st.st_atime, target_st.st_atime)
self.assertLessEqual(source_st.st_mtime, target_st.st_mtime)
self.assertEqual(source_st.st_mode, target_st.st_mode)