[Python-checkins] [3.9] bpo-43219: shutil.copyfile, raise a less confusing exception instead of IsADirectoryError (GH-27049) (GH-27082)
miss-islington
webhook-mailer at python.org
Sat Jul 10 00:14:08 EDT 2021
https://github.com/python/cpython/commit/c89f0b2587eb0b16175a0bbb12d0b86314ff9320
commit: c89f0b2587eb0b16175a0bbb12d0b86314ff9320
branch: 3.9
author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com>
committer: miss-islington <31488909+miss-islington at users.noreply.github.com>
date: 2021-07-09T21:13:59-07:00
summary:
[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 248173cc0483a9ad9261353302f1234cf9eb2ebe)
Co-authored-by: andrei kulakov <andrei.avk at gmail.com>
Automerge-Triggered-By: GH:gpshead
files:
A Misc/NEWS.d/next/Library/2021-07-09-07-14-37.bpo-41928.Q1jMrr.rst
M Lib/shutil.py
M Lib/test/test_shutil.py
diff --git a/Lib/shutil.py b/Lib/shutil.py
index 5cb796e800f62..08384cf92bb5d 100644
--- a/Lib/shutil.py
+++ b/Lib/shutil.py
@@ -261,28 +261,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)
- return dst
- except _GiveupOnFastCopy:
- pass
- # Linux
- elif _USE_CP_SENDFILE:
- try:
- _fastcopy_sendfile(fsrc, fdst)
+ 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
- # 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
diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py
index e378033acd35a..7cf263972ba5f 100644
--- a/Lib/test/test_shutil.py
+++ b/Lib/test/test_shutil.py
@@ -1243,6 +1243,15 @@ def test_copyfile_same_file(self):
# 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):
diff --git a/Misc/NEWS.d/next/Library/2021-07-09-07-14-37.bpo-41928.Q1jMrr.rst b/Misc/NEWS.d/next/Library/2021-07-09-07-14-37.bpo-41928.Q1jMrr.rst
new file mode 100644
index 0000000000000..e6bd758980b00
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2021-07-09-07-14-37.bpo-41928.Q1jMrr.rst
@@ -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.
More information about the Python-checkins
mailing list