[3.9] bpo-43219: shutil.copyfile, raise a less confusing exception instead of IsADirectoryError (GH-27049) (GH-27082)

Fixes the misleading IsADirectoryError to be FileNotFoundError.
(cherry picked from commit 248173cc04)


Co-authored-by: andrei kulakov <andrei.avk@gmail.com>

Automerge-Triggered-By: GH:gpshead
This commit is contained in:
Miss Islington (bot) 2021-07-09 21:13:59 -07:00 committed by GitHub
parent 302df02789
commit c89f0b2587
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 41 additions and 20 deletions

View file

@ -261,6 +261,7 @@ def copyfile(src, dst, *, follow_symlinks=True):
if not follow_symlinks and _islink(src): if not follow_symlinks and _islink(src):
os.symlink(os.readlink(src), dst) os.symlink(os.readlink(src), dst)
else: else:
try:
with open(src, 'rb') as fsrc, open(dst, 'wb') as fdst: with open(src, 'rb') as fsrc, open(dst, 'wb') as fdst:
# macOS # macOS
if _HAS_FCOPYFILE: if _HAS_FCOPYFILE:
@ -284,6 +285,13 @@ def copyfile(src, dst, *, follow_symlinks=True):
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 return dst
def copymode(src, dst, *, follow_symlinks=True): def copymode(src, dst, *, follow_symlinks=True):

View file

@ -1243,6 +1243,15 @@ def test_copyfile_same_file(self):
# Make sure file is not corrupted. # Make sure file is not corrupted.
self.assertEqual(read_file(src_file), 'foo') 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): class TestArchives(BaseTest, unittest.TestCase):

View file

@ -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.