mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 05:31:20 +00:00 
			
		
		
		
	Issue #16993: shutil.which() now preserves the case of the path and extension
on Windows.
This commit is contained in:
		
							parent
							
								
									85da624ebe
								
							
						
					
					
						commit
						014791f848
					
				
					 4 changed files with 15 additions and 9 deletions
				
			
		|  | @ -335,7 +335,7 @@ Directory and files operations | ||||||
|    directories.  For example, on Windows:: |    directories.  For example, on Windows:: | ||||||
| 
 | 
 | ||||||
|       >>> shutil.which("python") |       >>> shutil.which("python") | ||||||
|       'c:\\python33\\python.exe' |       'C:\\Python33\\python.exe' | ||||||
| 
 | 
 | ||||||
|    .. versionadded:: 3.3 |    .. versionadded:: 3.3 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1093,10 +1093,12 @@ def _access_check(fn, mode): | ||||||
|         pathext = os.environ.get("PATHEXT", "").split(os.pathsep) |         pathext = os.environ.get("PATHEXT", "").split(os.pathsep) | ||||||
|         # See if the given file matches any of the expected path extensions. |         # See if the given file matches any of the expected path extensions. | ||||||
|         # This will allow us to short circuit when given "python.exe". |         # This will allow us to short circuit when given "python.exe". | ||||||
|         matches = [cmd for ext in pathext if cmd.lower().endswith(ext.lower())] |  | ||||||
|         # If it does match, only test that one, otherwise we have to try |         # If it does match, only test that one, otherwise we have to try | ||||||
|         # others. |         # others. | ||||||
|         files = [cmd] if matches else [cmd + ext.lower() for ext in pathext] |         if any(cmd.lower().endswith(ext.lower()) for ext in pathext): | ||||||
|  |             files = [cmd] | ||||||
|  |         else: | ||||||
|  |             files = [cmd + ext for ext in pathext] | ||||||
|     else: |     else: | ||||||
|         # On other platforms you don't have things like PATHEXT to tell you |         # On other platforms you don't have things like PATHEXT to tell you | ||||||
|         # what file suffixes are executable, so just pass on cmd as-is. |         # what file suffixes are executable, so just pass on cmd as-is. | ||||||
|  | @ -1104,9 +1106,9 @@ def _access_check(fn, mode): | ||||||
| 
 | 
 | ||||||
|     seen = set() |     seen = set() | ||||||
|     for dir in path: |     for dir in path: | ||||||
|         dir = os.path.normcase(dir) |         normdir = os.path.normcase(dir) | ||||||
|         if not dir in seen: |         if not normdir in seen: | ||||||
|             seen.add(dir) |             seen.add(normdir) | ||||||
|             for thefile in files: |             for thefile in files: | ||||||
|                 name = os.path.join(dir, thefile) |                 name = os.path.join(dir, thefile) | ||||||
|                 if _access_check(name, mode): |                 if _access_check(name, mode): | ||||||
|  |  | ||||||
|  | @ -1269,12 +1269,13 @@ def test_copytree_return_value(self): | ||||||
| class TestWhich(unittest.TestCase): | class TestWhich(unittest.TestCase): | ||||||
| 
 | 
 | ||||||
|     def setUp(self): |     def setUp(self): | ||||||
|         self.temp_dir = tempfile.mkdtemp() |         self.temp_dir = tempfile.mkdtemp(prefix="Tmp") | ||||||
|         self.addCleanup(shutil.rmtree, self.temp_dir, True) |         self.addCleanup(shutil.rmtree, self.temp_dir, True) | ||||||
|         # Give the temp_file an ".exe" suffix for all. |         # Give the temp_file an ".exe" suffix for all. | ||||||
|         # It's needed on Windows and not harmful on other platforms. |         # It's needed on Windows and not harmful on other platforms. | ||||||
|         self.temp_file = tempfile.NamedTemporaryFile(dir=self.temp_dir, |         self.temp_file = tempfile.NamedTemporaryFile(dir=self.temp_dir, | ||||||
|                                                      suffix=".exe") |                                                      prefix="Tmp", | ||||||
|  |                                                      suffix=".Exe") | ||||||
|         os.chmod(self.temp_file.name, stat.S_IXUSR) |         os.chmod(self.temp_file.name, stat.S_IXUSR) | ||||||
|         self.addCleanup(self.temp_file.close) |         self.addCleanup(self.temp_file.close) | ||||||
|         self.dir, self.file = os.path.split(self.temp_file.name) |         self.dir, self.file = os.path.split(self.temp_file.name) | ||||||
|  | @ -1317,7 +1318,7 @@ def test_pathext_checking(self): | ||||||
|         # Ask for the file without the ".exe" extension, then ensure that |         # Ask for the file without the ".exe" extension, then ensure that | ||||||
|         # it gets found properly with the extension. |         # it gets found properly with the extension. | ||||||
|         rv = shutil.which(self.temp_file.name[:-4], path=self.dir) |         rv = shutil.which(self.temp_file.name[:-4], path=self.dir) | ||||||
|         self.assertEqual(self.temp_file.name, rv) |         self.assertEqual(rv, self.temp_file.name[:-4] + ".exe") | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class TestMove(unittest.TestCase): | class TestMove(unittest.TestCase): | ||||||
|  |  | ||||||
|  | @ -150,6 +150,9 @@ Core and Builtins | ||||||
| Library | Library | ||||||
| ------- | ------- | ||||||
| 
 | 
 | ||||||
|  | - Issue #16993: shutil.which() now preserves the case of the path and extension | ||||||
|  |   on Windows. | ||||||
|  | 
 | ||||||
| - Issue #16992: On Windows in signal.set_wakeup_fd, validate the file | - Issue #16992: On Windows in signal.set_wakeup_fd, validate the file | ||||||
|   descriptor argument. |   descriptor argument. | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Serhiy Storchaka
						Serhiy Storchaka