GH-73991: Rework pathlib.Path.copytree() into copy() (#122369)

Rename `pathlib.Path.copy()` to `_copy_file()` (i.e. make it private.)

Rename `pathlib.Path.copytree()` to `copy()`, and add support for copying
non-directories. This simplifies the interface for users, and nicely
complements the upcoming `move()` and `delete()` methods (which will also
accept any type of file.)

Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com>
This commit is contained in:
Barney Gale 2024-08-11 22:43:18 +01:00 committed by GitHub
parent ea70439bd2
commit a6644d4464
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 141 additions and 197 deletions

View file

@ -20,15 +20,6 @@ except ImportError:
_winapi = None
__all__ = ["UnsupportedOperation"]
class UnsupportedOperation(NotImplementedError):
"""An exception that is raised when an unsupported operation is attempted.
"""
pass
def get_copy_blocksize(infd):
"""Determine blocksize for fastcopying on Linux.
Hopefully the whole file will be copied in a single call.
@ -101,44 +92,12 @@ else:
copyfd = None
if _winapi and hasattr(_winapi, 'CopyFile2') and hasattr(os.stat_result, 'st_file_attributes'):
def _is_dirlink(path):
try:
st = os.lstat(path)
except (OSError, ValueError):
return False
return (st.st_file_attributes & stat.FILE_ATTRIBUTE_DIRECTORY and
st.st_reparse_tag == stat.IO_REPARSE_TAG_SYMLINK)
def copyfile(source, target, follow_symlinks):
if _winapi and hasattr(_winapi, 'CopyFile2'):
def copyfile(source, target):
"""
Copy from one file to another using CopyFile2 (Windows only).
"""
if follow_symlinks:
_winapi.CopyFile2(source, target, 0)
else:
# Use COPY_FILE_COPY_SYMLINK to copy a file symlink.
flags = _winapi.COPY_FILE_COPY_SYMLINK
try:
_winapi.CopyFile2(source, target, flags)
return
except OSError as err:
# Check for ERROR_ACCESS_DENIED
if err.winerror == 5 and _is_dirlink(source):
pass
else:
raise
# Add COPY_FILE_DIRECTORY to copy a directory symlink.
flags |= _winapi.COPY_FILE_DIRECTORY
try:
_winapi.CopyFile2(source, target, flags)
except OSError as err:
# Check for ERROR_INVALID_PARAMETER
if err.winerror == 87:
raise UnsupportedOperation(err) from None
else:
raise
_winapi.CopyFile2(source, target, 0)
else:
copyfile = None