diff --git a/Lib/shutil.py b/Lib/shutil.py index b82e3e3e1a5d07..171489ca41f2a7 100644 --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -1551,7 +1551,7 @@ def which(cmd, mode=os.F_OK | os.X_OK, path=None): # PATHEXT is necessary to check on Windows. pathext_source = os.getenv("PATHEXT") or _WIN_DEFAULT_PATHEXT pathext = pathext_source.split(os.pathsep) - pathext = [ext.rstrip('.') and ext for ext in pathext if ext] + pathext = [ext.rstrip('.') for ext in pathext if ext] if use_bytes: pathext = [os.fsencode(ext) for ext in pathext] diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py index 573b2e0da509ea..1f18b1f09b5858 100644 --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -2546,6 +2546,21 @@ def test_pathext_with_null_extension(self): self.assertEqual(shutil.which(cmddot, path=self.dir), filepath + self.to_text_type('.')) + @unittest.skipUnless(sys.platform == "win32", 'test specific to Windows') + def test_pathext_extension_ends_with_dot(self): + ext = '.xyz' + cmd = self.to_text_type(TESTFN2) + cmdext = cmd + self.to_text_type(ext) + dot = self.to_text_type('.') + filepath = os.path.join(self.dir, cmdext) + self.create_file(filepath) + with os_helper.EnvironmentVarGuard() as env: + env['PATHEXT'] = ext + '.' + self.assertEqual(shutil.which(cmd, path=self.dir), filepath) # cmd.exe hangs here + self.assertEqual(shutil.which(cmdext, path=self.dir), filepath) + self.assertIsNone(shutil.which(cmd + dot, path=self.dir)) + self.assertIsNone(shutil.which(cmdext + dot, path=self.dir)) + # See GH-75586 @unittest.skipUnless(sys.platform == "win32", 'test specific to Windows') def test_pathext_applied_on_files_in_path(self): diff --git a/Misc/NEWS.d/next/Library/2024-11-22-10-42-34.gh-issue-127035.UnbDlr.rst b/Misc/NEWS.d/next/Library/2024-11-22-10-42-34.gh-issue-127035.UnbDlr.rst index 5484758721b7e3..6bb7abfdd50040 100644 --- a/Misc/NEWS.d/next/Library/2024-11-22-10-42-34.gh-issue-127035.UnbDlr.rst +++ b/Misc/NEWS.d/next/Library/2024-11-22-10-42-34.gh-issue-127035.UnbDlr.rst @@ -1,3 +1,4 @@ Fix :mod:`shutil.which` on Windows. Now it looks at direct match if and only if the command ends with a PATHEXT extension or X_OK is not in mode. Support -extensionless files if "." is in PATHEXT. +extensionless files if "." is in PATHEXT. Support PATHEXT extensions that end +with a dot.