Skip to content

Commit

Permalink
pythonGH-125413: pathlib.Path.copy(): get common metadata keys only…
Browse files Browse the repository at this point in the history
… once

Improve `pathlib._abc.PathBase.copy()` (which provides `Path.copy()`) by
fetching operands' supported metadata keys up-front, rather than once for
each path in the tree.

This prepares the way for using `os.DirEntry` objects in `copy()`.
  • Loading branch information
barneygale committed Oct 25, 2024
1 parent 7f6e884 commit f8ffd49
Showing 1 changed file with 14 additions and 16 deletions.
30 changes: 14 additions & 16 deletions Lib/pathlib/_abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -837,16 +837,6 @@ def _write_metadata(self, metadata, *, follow_symlinks=True):
"""
raise UnsupportedOperation(self._unsupported_msg('_write_metadata()'))

def _copy_metadata(self, target, *, follow_symlinks=True):
"""
Copies metadata (permissions, timestamps, etc) from this path to target.
"""
# Metadata types supported by both source and target.
keys = self._readable_metadata & target._writable_metadata
if keys:
metadata = self._read_metadata(keys, follow_symlinks=follow_symlinks)
target._write_metadata(metadata, follow_symlinks=follow_symlinks)

def _copy_file(self, target):
"""
Copy the contents of this file to the given target.
Expand All @@ -872,24 +862,32 @@ def copy(self, target, *, follow_symlinks=True, dirs_exist_ok=False,
if not isinstance(target, PathBase):
target = self.with_segments(target)
self._ensure_distinct_path(target)
if preserve_metadata:
# Metadata types supported by both source and target.
metadata_keys = self._readable_metadata & target._writable_metadata
else:
metadata_keys = None
stack = [(self, target)]
while stack:
src, dst = stack.pop()
if not follow_symlinks and src.is_symlink():
dst._symlink_to_target_of(src)
if preserve_metadata:
src._copy_metadata(dst, follow_symlinks=False)
if metadata_keys:
metadata = src._read_metadata(metadata_keys, follow_symlinks=False)
dst._write_metadata(metadata, follow_symlinks=False)
elif src.is_dir():
children = src.iterdir()
dst.mkdir(exist_ok=dirs_exist_ok)
stack.extend((child, dst.joinpath(child.name))
for child in children)
if preserve_metadata:
src._copy_metadata(dst)
if metadata_keys:
metadata = src._read_metadata(metadata_keys)
dst._write_metadata(metadata)
else:
src._copy_file(dst)
if preserve_metadata:
src._copy_metadata(dst)
if metadata_keys:
metadata = src._read_metadata(metadata_keys)
dst._write_metadata(metadata)
return target

def copy_into(self, target_dir, *, follow_symlinks=True,
Expand Down

0 comments on commit f8ffd49

Please sign in to comment.