mirror of
https://github.com/python/cpython.git
synced 2025-08-03 16:39:00 +00:00
[3.13] gh-127001: Fix PATHEXT issues in shutil.which() on Windows (GH-127035) (GH-127156)
* Name without a PATHEXT extension is only searched if the mode does not
include X_OK.
* Support multi-component PATHEXT extensions (e.g. ".foo.bar").
* Support files without extensions in PATHEXT contains dot-only extension
(".", "..", etc).
* Support PATHEXT extensions that end with a dot (e.g. ".foo.").
(cherry picked from commit 8899e85de1
)
Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
This commit is contained in:
parent
5468d219df
commit
7f22b87d35
4 changed files with 302 additions and 247 deletions
|
@ -1551,21 +1551,21 @@ def which(cmd, mode=os.F_OK | os.X_OK, path=None):
|
|||
if sys.platform == "win32":
|
||||
# PATHEXT is necessary to check on Windows.
|
||||
pathext_source = os.getenv("PATHEXT") or _WIN_DEFAULT_PATHEXT
|
||||
pathext = [ext for ext in pathext_source.split(os.pathsep) if ext]
|
||||
pathext = pathext_source.split(os.pathsep)
|
||||
pathext = [ext.rstrip('.') for ext in pathext if ext]
|
||||
|
||||
if use_bytes:
|
||||
pathext = [os.fsencode(ext) for ext in pathext]
|
||||
|
||||
files = ([cmd] + [cmd + ext for ext in pathext])
|
||||
files = [cmd + ext for ext in pathext]
|
||||
|
||||
# gh-109590. If we are looking for an executable, we need to look
|
||||
# for a PATHEXT match. The first cmd is the direct match
|
||||
# (e.g. python.exe instead of python)
|
||||
# Check that direct match first if and only if the extension is in PATHEXT
|
||||
# Otherwise check it last
|
||||
suffix = os.path.splitext(files[0])[1].upper()
|
||||
if mode & os.X_OK and not any(suffix == ext.upper() for ext in pathext):
|
||||
files.append(files.pop(0))
|
||||
# If X_OK in mode, simulate the cmd.exe behavior: look at direct
|
||||
# match if and only if the extension is in PATHEXT.
|
||||
# If X_OK not in mode, simulate the first result of where.exe:
|
||||
# always look at direct match before a PATHEXT match.
|
||||
normcmd = cmd.upper()
|
||||
if not (mode & os.X_OK) or any(normcmd.endswith(ext.upper()) for ext in pathext):
|
||||
files.insert(0, cmd)
|
||||
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.
|
||||
|
@ -1574,7 +1574,7 @@ def which(cmd, mode=os.F_OK | os.X_OK, path=None):
|
|||
seen = set()
|
||||
for dir in path:
|
||||
normdir = os.path.normcase(dir)
|
||||
if not normdir in seen:
|
||||
if normdir not in seen:
|
||||
seen.add(normdir)
|
||||
for thefile in files:
|
||||
name = os.path.join(dir, thefile)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue