GH-130614: pathlib ABCs: improve support for receiving path metadata … · python/cpython@563ab5c

GitHub

@@ -29,7 +29,7 @@

2929frompathlib._osimport (

3030PathInfo, DirEntryInfo,

3131ensure_different_files, ensure_distinct_paths,

32-copy_file, copy_info,

32+copyfile2, copyfileobj, magic_open, copy_info,

3333)

34343535@@ -810,12 +810,6 @@ def write_text(self, data, encoding=None, errors=None, newline=None):

810810withself.open(mode='w', encoding=encoding, errors=errors, newline=newline) asf:

811811returnf.write(data)

812812813-def_write_info(self, info, follow_symlinks=True):

814-"""

815- Write the given PathInfo to this path.

816- """

817-copy_info(info, self, follow_symlinks=follow_symlinks)

818-819813_remove_leading_dot=operator.itemgetter(slice(2, None))

820814_remove_trailing_slash=operator.itemgetter(slice(-1))

821815@@ -1100,18 +1094,21 @@ def replace(self, target):

11001094target=self.with_segments(target)

11011095returntarget

110210961103-defcopy(self, target, follow_symlinks=True, preserve_metadata=False):

1097+defcopy(self, target, **kwargs):

11041098"""

11051099 Recursively copy this file or directory tree to the given destination.

11061100 """

11071101ifnothasattr(target, 'with_segments'):

11081102target=self.with_segments(target)

11091103ensure_distinct_paths(self, target)

1110-copy_file(self, target, follow_symlinks, preserve_metadata)

1104+try:

1105+copy_to_target=target._copy_from

1106+exceptAttributeError:

1107+raiseTypeError(f"Target path is not writable: {target!r}") fromNone

1108+copy_to_target(self, **kwargs)

11111109returntarget.joinpath() # Empty join to ensure fresh metadata.

111211101113-defcopy_into(self, target_dir, *, follow_symlinks=True,

1114-preserve_metadata=False):

1111+defcopy_into(self, target_dir, **kwargs):

11151112"""

11161113 Copy this file or directory tree into the given existing directory.

11171114 """

@@ -1122,8 +1119,59 @@ def copy_into(self, target_dir, *, follow_symlinks=True,

11221119target=target_dir/name

11231120else:

11241121target=self.with_segments(target_dir, name)

1125-returnself.copy(target, follow_symlinks=follow_symlinks,

1126-preserve_metadata=preserve_metadata)

1122+returnself.copy(target, **kwargs)

1123+1124+def_copy_from(self, source, follow_symlinks=True, preserve_metadata=False):

1125+"""

1126+ Recursively copy the given path to this path.

1127+ """

1128+ifnotfollow_symlinksandsource.info.is_symlink():

1129+self._copy_from_symlink(source, preserve_metadata)

1130+elifsource.info.is_dir():

1131+children=source.iterdir()

1132+os.mkdir(self)

1133+forchildinchildren:

1134+self.joinpath(child.name)._copy_from(

1135+child, follow_symlinks, preserve_metadata)

1136+ifpreserve_metadata:

1137+copy_info(source.info, self)

1138+else:

1139+self._copy_from_file(source, preserve_metadata)

1140+1141+def_copy_from_file(self, source, preserve_metadata=False):

1142+ensure_different_files(source, self)

1143+withmagic_open(source, 'rb') assource_f:

1144+withopen(self, 'wb') astarget_f:

1145+copyfileobj(source_f, target_f)

1146+ifpreserve_metadata:

1147+copy_info(source.info, self)

1148+1149+ifcopyfile2:

1150+# Use fast OS routine for local file copying where available.

1151+_copy_from_file_fallback=_copy_from_file

1152+def_copy_from_file(self, source, preserve_metadata=False):

1153+try:

1154+source=os.fspath(source)

1155+exceptTypeError:

1156+pass

1157+else:

1158+copyfile2(source, str(self))

1159+return

1160+self._copy_from_file_fallback(source, preserve_metadata)

1161+1162+ifos.name=='nt':

1163+# If a directory-symlink is copied *before* its target, then

1164+# os.symlink() incorrectly creates a file-symlink on Windows. Avoid

1165+# this by passing *target_is_dir* to os.symlink() on Windows.

1166+def_copy_from_symlink(self, source, preserve_metadata=False):

1167+os.symlink(str(source.readlink()), self, source.info.is_dir())

1168+ifpreserve_metadata:

1169+copy_info(source.info, self, follow_symlinks=False)

1170+else:

1171+def_copy_from_symlink(self, source, preserve_metadata=False):

1172+os.symlink(str(source.readlink()), self)

1173+ifpreserve_metadata:

1174+copy_info(source.info, self, follow_symlinks=False)

1127117511281176defmove(self, target):

11291177"""