mirror of
				https://github.com/python/cpython.git
				synced 2025-11-01 06:01:29 +00:00 
			
		
		
		
	[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:
		
							parent
							
								
									302df02789
								
							
						
					
					
						commit
						c89f0b2587
					
				
					 3 changed files with 41 additions and 20 deletions
				
			
		|  | @ -261,28 +261,36 @@ 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: | ||||||
|         with open(src, 'rb') as fsrc, open(dst, 'wb') as fdst: |         try: | ||||||
|             # macOS |             with open(src, 'rb') as fsrc, open(dst, 'wb') as fdst: | ||||||
|             if _HAS_FCOPYFILE: |                 # macOS | ||||||
|                 try: |                 if _HAS_FCOPYFILE: | ||||||
|                     _fastcopy_fcopyfile(fsrc, fdst, posix._COPYFILE_DATA) |                     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 |                     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 |     return dst | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -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): | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -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…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Miss Islington (bot)
						Miss Islington (bot)