From 014791f8484036b1c0040ea0de7a6a4c05f0aeed Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 21 Jan 2013 15:00:27 +0200 Subject: [PATCH] Issue #16993: shutil.which() now preserves the case of the path and extension on Windows. --- Doc/library/shutil.rst | 2 +- Lib/shutil.py | 12 +++++++----- Lib/test/test_shutil.py | 7 ++++--- Misc/NEWS | 3 +++ 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/Doc/library/shutil.rst b/Doc/library/shutil.rst index e9621120a9f..b5f39fe1e42 100644 --- a/Doc/library/shutil.rst +++ b/Doc/library/shutil.rst @@ -335,7 +335,7 @@ Directory and files operations directories. For example, on Windows:: >>> shutil.which("python") - 'c:\\python33\\python.exe' + 'C:\\Python33\\python.exe' .. versionadded:: 3.3 diff --git a/Lib/shutil.py b/Lib/shutil.py index 9c66008ed2f..86c32fa20ad 100644 --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -1093,10 +1093,12 @@ def which(cmd, mode=os.F_OK | os.X_OK, path=None): pathext = os.environ.get("PATHEXT", "").split(os.pathsep) # See if the given file matches any of the expected path extensions. # 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 # 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: # 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. @@ -1104,9 +1106,9 @@ def which(cmd, mode=os.F_OK | os.X_OK, path=None): seen = set() for dir in path: - dir = os.path.normcase(dir) - if not dir in seen: - seen.add(dir) + normdir = os.path.normcase(dir) + if not normdir in seen: + seen.add(normdir) for thefile in files: name = os.path.join(dir, thefile) if _access_check(name, mode): diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py index 01b93fc4411..6ae051b0aec 100644 --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -1269,12 +1269,13 @@ class TestShutil(unittest.TestCase): class TestWhich(unittest.TestCase): def setUp(self): - self.temp_dir = tempfile.mkdtemp() + self.temp_dir = tempfile.mkdtemp(prefix="Tmp") self.addCleanup(shutil.rmtree, self.temp_dir, True) # Give the temp_file an ".exe" suffix for all. # It's needed on Windows and not harmful on other platforms. self.temp_file = tempfile.NamedTemporaryFile(dir=self.temp_dir, - suffix=".exe") + prefix="Tmp", + suffix=".Exe") os.chmod(self.temp_file.name, stat.S_IXUSR) self.addCleanup(self.temp_file.close) self.dir, self.file = os.path.split(self.temp_file.name) @@ -1317,7 +1318,7 @@ class TestWhich(unittest.TestCase): # Ask for the file without the ".exe" extension, then ensure that # it gets found properly with the extension. 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): diff --git a/Misc/NEWS b/Misc/NEWS index 7a720c195a8..df97d42d3ab 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -150,6 +150,9 @@ Core and Builtins 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 descriptor argument.