mirror of https://github.com/python/cpython
bpo-43219: shutil.copyfile, raise a less confusing exception instead of IsADirectoryError (GH-27049)
Fixes the misleading IsADirectoryError to be FileNotFoundError.
This commit is contained in:
parent
f24777c2b3
commit
248173cc04
|
@ -253,28 +253,36 @@ def copyfile(src, dst, *, follow_symlinks=True):
|
|||
if not follow_symlinks and _islink(src):
|
||||
os.symlink(os.readlink(src), dst)
|
||||
else:
|
||||
with open(src, 'rb') as fsrc, open(dst, 'wb') as fdst:
|
||||
# macOS
|
||||
if _HAS_FCOPYFILE:
|
||||
try:
|
||||
_fastcopy_fcopyfile(fsrc, fdst, posix._COPYFILE_DATA)
|
||||
try:
|
||||
with open(src, 'rb') as fsrc, open(dst, 'wb') as fdst:
|
||||
# macOS
|
||||
if _HAS_FCOPYFILE:
|
||||
try:
|
||||
_fastcopy_fcopyfile(fsrc, fdst, posix._COPYFILE_DATA)
|
||||
return dst
|
||||
except _GiveupOnFastCopy:
|
||||
pass
|
||||
# Linux
|
||||
elif _USE_CP_SENDFILE:
|
||||
try:
|
||||
_fastcopy_sendfile(fsrc, fdst)
|
||||
return dst
|
||||
except _GiveupOnFastCopy:
|
||||
pass
|
||||
# Windows, see:
|
||||
# https://github.com/python/cpython/pull/7160#discussion_r195405230
|
||||
elif _WINDOWS and file_size > 0:
|
||||
_copyfileobj_readinto(fsrc, fdst, min(file_size, COPY_BUFSIZE))
|
||||
return dst
|
||||
except _GiveupOnFastCopy:
|
||||
pass
|
||||
# Linux
|
||||
elif _USE_CP_SENDFILE:
|
||||
try:
|
||||
_fastcopy_sendfile(fsrc, fdst)
|
||||
return dst
|
||||
except _GiveupOnFastCopy:
|
||||
pass
|
||||
# Windows, see:
|
||||
# https://github.com/python/cpython/pull/7160#discussion_r195405230
|
||||
elif _WINDOWS and file_size > 0:
|
||||
_copyfileobj_readinto(fsrc, fdst, min(file_size, COPY_BUFSIZE))
|
||||
return dst
|
||||
|
||||
copyfileobj(fsrc, fdst)
|
||||
copyfileobj(fsrc, fdst)
|
||||
|
||||
# Issue 43219, raise a less confusing exception
|
||||
except IsADirectoryError as e:
|
||||
if os.path.exists(dst):
|
||||
raise
|
||||
else:
|
||||
raise FileNotFoundError(f'Directory does not exist: {dst}') from e
|
||||
|
||||
return dst
|
||||
|
||||
|
|
|
@ -1249,6 +1249,15 @@ class TestCopy(BaseTest, unittest.TestCase):
|
|||
# Make sure file is not corrupted.
|
||||
self.assertEqual(read_file(src_file), 'foo')
|
||||
|
||||
@unittest.skipIf(MACOS or _winapi, 'On MACOS and Windows the errors are not confusing (though different)')
|
||||
def test_copyfile_nonexistent_dir(self):
|
||||
# Issue 43219
|
||||
src_dir = self.mkdtemp()
|
||||
src_file = os.path.join(src_dir, 'foo')
|
||||
dst = os.path.join(src_dir, 'does_not_exist/')
|
||||
write_file(src_file, 'foo')
|
||||
self.assertRaises(FileNotFoundError, shutil.copyfile, src_file, dst)
|
||||
|
||||
|
||||
class TestArchives(BaseTest, unittest.TestCase):
|
||||
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
Update :func:`shutil.copyfile` to raise :exc:`FileNotFoundError` instead of
|
||||
confusing :exc:`IsADirectoryError` when a path ending with a
|
||||
:const:`os.path.sep` does not exist; :func:`shutil.copy` and
|
||||
:func:`shutil.copy2` are also affected.
|
Loading…
Reference in New Issue