diff options
author | Barney Gale <barney.gale@gmail.com> | 2024-12-22 02:22:08 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-12-22 02:22:08 (GMT) |
commit | 8d9f52a7be5c09c0fd4423943edadaacf6d7f917 (patch) | |
tree | 6027636f753421b139f0ce77dabea3eab1d82052 /Lib/pathlib/_os.py | |
parent | f5ba74b81979b621e38be70ec3ddad1e7f1365ce (diff) | |
download | cpython-8d9f52a7be5c09c0fd4423943edadaacf6d7f917.zip cpython-8d9f52a7be5c09c0fd4423943edadaacf6d7f917.tar.gz cpython-8d9f52a7be5c09c0fd4423943edadaacf6d7f917.tar.bz2 |
GH-127807: pathlib ABCs: move private copying methods to dedicated class (#127810)
Move 9 private `PathBase` attributes and methods into a new `CopyWorker`
class. Change `PathBase.copy` from a method to a `CopyWorker` instance.
The methods remain private in the `CopyWorker` class. In future we might
make some/all of them public so that user subclasses of `PathBase` can
customize the copying process (in particular reading/writing of metadata,)
but we'd need to make `PathBase` public first.
Diffstat (limited to 'Lib/pathlib/_os.py')
-rw-r--r-- | Lib/pathlib/_os.py | 98 |
1 files changed, 0 insertions, 98 deletions
diff --git a/Lib/pathlib/_os.py b/Lib/pathlib/_os.py index 642b3a5..57bcaf3 100644 --- a/Lib/pathlib/_os.py +++ b/Lib/pathlib/_os.py @@ -4,7 +4,6 @@ Low-level OS functionality wrappers used by pathlib. from errno import * import os -import stat import sys try: import fcntl @@ -163,100 +162,3 @@ def copyfileobj(source_f, target_f): write_target = target_f.write while buf := read_source(1024 * 1024): write_target(buf) - - -# Kinds of metadata supported by the operating system. -file_metadata_keys = {'mode', 'times_ns'} -if hasattr(os.stat_result, 'st_flags'): - file_metadata_keys.add('flags') -if hasattr(os, 'listxattr'): - file_metadata_keys.add('xattrs') -file_metadata_keys = frozenset(file_metadata_keys) - - -def read_file_metadata(path, keys=None, *, follow_symlinks=True): - """ - Returns local path metadata as a dict with string keys. - """ - if keys is None: - keys = file_metadata_keys - assert keys.issubset(file_metadata_keys) - result = {} - for key in keys: - if key == 'xattrs': - try: - result['xattrs'] = [ - (attr, os.getxattr(path, attr, follow_symlinks=follow_symlinks)) - for attr in os.listxattr(path, follow_symlinks=follow_symlinks)] - except OSError as err: - if err.errno not in (EPERM, ENOTSUP, ENODATA, EINVAL, EACCES): - raise - continue - st = os.stat(path, follow_symlinks=follow_symlinks) - if key == 'mode': - result['mode'] = stat.S_IMODE(st.st_mode) - elif key == 'times_ns': - result['times_ns'] = st.st_atime_ns, st.st_mtime_ns - elif key == 'flags': - result['flags'] = st.st_flags - return result - - -def write_file_metadata(path, metadata, *, follow_symlinks=True): - """ - Sets local path metadata from the given dict with string keys. - """ - assert frozenset(metadata.keys()).issubset(file_metadata_keys) - - def _nop(*args, ns=None, follow_symlinks=None): - pass - - if follow_symlinks: - # use the real function if it exists - def lookup(name): - return getattr(os, name, _nop) - else: - # use the real function only if it exists - # *and* it supports follow_symlinks - def lookup(name): - fn = getattr(os, name, _nop) - if fn in os.supports_follow_symlinks: - return fn - return _nop - - times_ns = metadata.get('times_ns') - if times_ns is not None: - lookup("utime")(path, ns=times_ns, follow_symlinks=follow_symlinks) - # We must copy extended attributes before the file is (potentially) - # chmod()'ed read-only, otherwise setxattr() will error with -EACCES. - xattrs = metadata.get('xattrs') - if xattrs is not None: - for attr, value in xattrs: - try: - os.setxattr(path, attr, value, follow_symlinks=follow_symlinks) - except OSError as e: - if e.errno not in (EPERM, ENOTSUP, ENODATA, EINVAL, EACCES): - raise - mode = metadata.get('mode') - if mode is not None: - try: - lookup("chmod")(path, mode, follow_symlinks=follow_symlinks) - except NotImplementedError: - # if we got a NotImplementedError, it's because - # * follow_symlinks=False, - # * lchown() is unavailable, and - # * either - # * fchownat() is unavailable or - # * fchownat() doesn't implement AT_SYMLINK_NOFOLLOW. - # (it returned ENOSUP.) - # therefore we're out of options--we simply cannot chown the - # symlink. give up, suppress the error. - # (which is what shutil always did in this circumstance.) - pass - flags = metadata.get('flags') - if flags is not None: - try: - lookup("chflags")(path, flags, follow_symlinks=follow_symlinks) - except OSError as why: - if why.errno not in (EOPNOTSUPP, ENOTSUP): - raise |