self.curdir = os.curdir
self.ext = ".EXE"
+ def to_text_type(self, s):
+ '''
+ In this class we're testing with str, so convert s to a str
+ '''
+ if isinstance(s, bytes):
+ return s.decode()
+ return s
+
def test_basic(self):
# Given an EXE in a directory, it should be returned.
rv = shutil.which(self.file, path=self.dir)
@unittest.skipUnless(sys.platform == "win32", 'test specific to Windows')
def test_pathext(self):
- ext = ".xyz"
+ ext = self.to_text_type(".xyz")
temp_filexyz = tempfile.NamedTemporaryFile(dir=self.temp_dir,
- prefix="Tmp2", suffix=ext)
+ prefix=self.to_text_type("Tmp2"), suffix=ext)
os.chmod(temp_filexyz.name, stat.S_IXUSR)
self.addCleanup(temp_filexyz.close)
program = os.path.splitext(program)[0]
with os_helper.EnvironmentVarGuard() as env:
- env['PATHEXT'] = ext
+ env['PATHEXT'] = ext if isinstance(ext, str) else ext.decode()
rv = shutil.which(program, path=self.temp_dir)
self.assertEqual(rv, temp_filexyz.name)
# Issue 40592: See https://bugs.python.org/issue40592
@unittest.skipUnless(sys.platform == "win32", 'test specific to Windows')
def test_pathext_with_empty_str(self):
- ext = ".xyz"
+ ext = self.to_text_type(".xyz")
temp_filexyz = tempfile.NamedTemporaryFile(dir=self.temp_dir,
- prefix="Tmp2", suffix=ext)
+ prefix=self.to_text_type("Tmp2"), suffix=ext)
self.addCleanup(temp_filexyz.close)
# strip path and extension
program = os.path.splitext(program)[0]
with os_helper.EnvironmentVarGuard() as env:
- env['PATHEXT'] = f"{ext};" # note the ;
+ env['PATHEXT'] = f"{ext if isinstance(ext, str) else ext.decode()};" # note the ;
rv = shutil.which(program, path=self.temp_dir)
self.assertEqual(rv, temp_filexyz.name)
@unittest.skipUnless(sys.platform == "win32", 'test specific to Windows')
def test_pathext_applied_on_files_in_path(self):
with os_helper.EnvironmentVarGuard() as env:
- env["PATH"] = self.temp_dir
+ env["PATH"] = self.temp_dir if isinstance(self.temp_dir, str) else self.temp_dir.decode()
env["PATHEXT"] = ".test"
- test_path = pathlib.Path(self.temp_dir) / "test_program.test"
- test_path.touch(mode=0o755)
+ test_path = os.path.join(self.temp_dir, self.to_text_type("test_program.test"))
+ open(test_path, 'w').close()
+ os.chmod(test_path, 0o755)
- self.assertEqual(shutil.which("test_program"), str(test_path))
+ self.assertEqual(shutil.which(self.to_text_type("test_program")), test_path)
# See GH-75586
@unittest.skipUnless(sys.platform == "win32", 'test specific to Windows')
self.assertFalse(shutil._win_path_needs_curdir('dontcare', os.X_OK))
need_curdir_mock.assert_called_once_with('dontcare')
+ # See GH-109590
+ @unittest.skipUnless(sys.platform == "win32", 'test specific to Windows')
+ def test_pathext_preferred_for_execute(self):
+ with os_helper.EnvironmentVarGuard() as env:
+ env["PATH"] = self.temp_dir if isinstance(self.temp_dir, str) else self.temp_dir.decode()
+ env["PATHEXT"] = ".test"
+
+ exe = os.path.join(self.temp_dir, self.to_text_type("test.exe"))
+ open(exe, 'w').close()
+ os.chmod(exe, 0o755)
+
+ # default behavior allows a direct match if nothing in PATHEXT matches
+ self.assertEqual(shutil.which(self.to_text_type("test.exe")), exe)
+
+ dot_test = os.path.join(self.temp_dir, self.to_text_type("test.exe.test"))
+ open(dot_test, 'w').close()
+ os.chmod(dot_test, 0o755)
+
+ # now we have a PATHEXT match, so it take precedence
+ self.assertEqual(shutil.which(self.to_text_type("test.exe")), dot_test)
+
+ # but if we don't use os.X_OK we don't change the order based off PATHEXT
+ # and therefore get the direct match.
+ self.assertEqual(shutil.which(self.to_text_type("test.exe"), mode=os.F_OK), exe)
+
+ # See GH-109590
+ @unittest.skipUnless(sys.platform == "win32", 'test specific to Windows')
+ def test_pathext_given_extension_preferred(self):
+ with os_helper.EnvironmentVarGuard() as env:
+ env["PATH"] = self.temp_dir if isinstance(self.temp_dir, str) else self.temp_dir.decode()
+ env["PATHEXT"] = ".exe2;.exe"
+
+ exe = os.path.join(self.temp_dir, self.to_text_type("test.exe"))
+ open(exe, 'w').close()
+ os.chmod(exe, 0o755)
+
+ exe2 = os.path.join(self.temp_dir, self.to_text_type("test.exe2"))
+ open(exe2, 'w').close()
+ os.chmod(exe2, 0o755)
+
+ # even though .exe2 is preferred in PATHEXT, we matched directly to test.exe
+ self.assertEqual(shutil.which(self.to_text_type("test.exe")), exe)
+ self.assertEqual(shutil.which(self.to_text_type("test")), exe2)
+
class TestWhichBytes(TestWhich):
def setUp(self):
self.dir = os.fsencode(self.dir)
self.file = os.fsencode(self.file)
self.temp_file.name = os.fsencode(self.temp_file.name)
+ self.temp_dir = os.fsencode(self.temp_dir)
self.curdir = os.fsencode(self.curdir)
self.ext = os.fsencode(self.ext)
+ def to_text_type(self, s):
+ '''
+ In this class we're testing with bytes, so convert s to a bytes
+ '''
+ if isinstance(s, str):
+ return s.encode()
+ return s
+
class TestMove(BaseTest, unittest.TestCase):