summaryrefslogtreecommitdiffstats
path: root/Lib/pathlib/_os.py
diff options
context:
space:
mode:
authorBarney Gale <barney.gale@gmail.com>2024-12-22 02:22:08 (GMT)
committerGitHub <noreply@github.com>2024-12-22 02:22:08 (GMT)
commit8d9f52a7be5c09c0fd4423943edadaacf6d7f917 (patch)
tree6027636f753421b139f0ce77dabea3eab1d82052 /Lib/pathlib/_os.py
parentf5ba74b81979b621e38be70ec3ddad1e7f1365ce (diff)
downloadcpython-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.py98
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