Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit da6f098

Browse filesBrowse files
authored
bpo-40592: shutil.which will not return None anymore if ; is the last char in PATHEXT (GH-20088)
shutil.which will not return None anymore for empty str in PATHEXT Empty PATHEXT will now be defaulted to _WIN_DEFAULT_PATHEXT
1 parent 345cd37 commit da6f098
Copy full SHA for da6f098

File tree

3 files changed

+24
-1
lines changed
Filter options

3 files changed

+24
-1
lines changed

‎Lib/shutil.py

Copy file name to clipboardExpand all lines: Lib/shutil.py
+6-1Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@
5353
_USE_CP_SENDFILE = hasattr(os, "sendfile") and sys.platform.startswith("linux")
5454
_HAS_FCOPYFILE = posix and hasattr(posix, "_fcopyfile") # macOS
5555

56+
# CMD defaults in Windows 10
57+
_WIN_DEFAULT_PATHEXT = ".COM;.EXE;.BAT;.CMD;.VBS;.JS;.WS;.MSC"
58+
5659
__all__ = ["copyfileobj", "copyfile", "copymode", "copystat", "copy", "copy2",
5760
"copytree", "move", "rmtree", "Error", "SpecialFileError",
5861
"ExecError", "make_archive", "get_archive_formats",
@@ -1415,7 +1418,9 @@ def which(cmd, mode=os.F_OK | os.X_OK, path=None):
14151418
path.insert(0, curdir)
14161419

14171420
# PATHEXT is necessary to check on Windows.
1418-
pathext = os.environ.get("PATHEXT", "").split(os.pathsep)
1421+
pathext_source = os.getenv("PATHEXT") or _WIN_DEFAULT_PATHEXT
1422+
pathext = [ext for ext in pathext_source.split(os.pathsep) if ext]
1423+
14191424
if use_bytes:
14201425
pathext = [os.fsencode(ext) for ext in pathext]
14211426
# See if the given file matches any of the expected path extensions.

‎Lib/test/test_shutil.py

Copy file name to clipboardExpand all lines: Lib/test/test_shutil.py
+17Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1849,6 +1849,23 @@ def test_pathext(self):
18491849
rv = shutil.which(program, path=self.temp_dir)
18501850
self.assertEqual(rv, temp_filexyz.name)
18511851

1852+
# Issue 40592: See https://bugs.python.org/issue40592
1853+
@unittest.skipUnless(sys.platform == "win32", 'test specific to Windows')
1854+
def test_pathext_with_empty_str(self):
1855+
ext = ".xyz"
1856+
temp_filexyz = tempfile.NamedTemporaryFile(dir=self.temp_dir,
1857+
prefix="Tmp2", suffix=ext)
1858+
self.addCleanup(temp_filexyz.close)
1859+
1860+
# strip path and extension
1861+
program = os.path.basename(temp_filexyz.name)
1862+
program = os.path.splitext(program)[0]
1863+
1864+
with os_helper.EnvironmentVarGuard() as env:
1865+
env['PATHEXT'] = f"{ext};" # note the ;
1866+
rv = shutil.which(program, path=self.temp_dir)
1867+
self.assertEqual(rv, temp_filexyz.name)
1868+
18521869

18531870
class TestWhichBytes(TestWhich):
18541871
def setUp(self):
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
:func:`shutil.which` now ignores empty entries in :envvar:`PATHEXT` instead of treating them as a match.

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.