diff -r e5427b0b2bf7 Doc/library/shutil.rst --- a/Doc/library/shutil.rst Sun Jun 23 01:49:42 2013 +0200 +++ b/Doc/library/shutil.rst Sun Jun 23 02:21:19 2013 +0200 @@ -352,6 +352,10 @@ Directory and files operations .. versionadded:: 3.3 + .. versionchanged:: 3.4 + The :class:`bytes` type is now accepted. If *cmd* type is :class:`bytes`, + the result type is also :class:`bytes`. + .. exception:: Error diff -r e5427b0b2bf7 Lib/shutil.py --- a/Lib/shutil.py Sun Jun 23 01:49:42 2013 +0200 +++ b/Lib/shutil.py Sun Jun 23 02:21:19 2013 +0200 @@ -1065,6 +1065,13 @@ def get_terminal_size(fallback=(80, 24)) return os.terminal_size((columns, lines)) +# Check that a given file can be accessed with the correct mode. +# Additionally check that `file` is not a directory, as on Windows +# directories pass the os.access check. +def _access_check(fn, mode): + return (os.path.exists(fn) and os.access(fn, mode) + and not os.path.isdir(fn)) + def which(cmd, mode=os.F_OK | os.X_OK, path=None): """Given a command, mode, and a PATH string, return the path which conforms to the given mode on the PATH, or None if there is no such @@ -1075,13 +1082,6 @@ def which(cmd, mode=os.F_OK | os.X_OK, p path. """ - # Check that a given file can be accessed with the correct mode. - # Additionally check that `file` is not a directory, as on Windows - # directories pass the os.access check. - def _access_check(fn, mode): - return (os.path.exists(fn) and os.access(fn, mode) - and not os.path.isdir(fn)) - # If we're given a path with a directory part, look it up directly rather # than referring to PATH directories. This includes checking relative to the # current directory, e.g. ./script @@ -1094,7 +1094,12 @@ def which(cmd, mode=os.F_OK | os.X_OK, p path = os.environ.get("PATH", os.defpath) if not path: return None - path = path.split(os.pathsep) + if isinstance(cmd, bytes): + path = os.fsencode(path) + path = path.split(os.fsencode(os.pathsep)) + else: + path = os.fsdecode(path) + path = path.split(os.pathsep) if sys.platform == "win32": # The current directory takes precedence on Windows. @@ -1103,6 +1108,8 @@ def which(cmd, mode=os.F_OK | os.X_OK, p # PATHEXT is necessary to check on Windows. pathext = os.environ.get("PATHEXT", "").split(os.pathsep) + if isinstance(cmd, bytes): + pathext = map(os.fsencode, pathext) # See if the given file matches any of the expected path extensions. # This will allow us to short circuit when given "python.exe". # If it does match, only test that one, otherwise we have to try diff -r e5427b0b2bf7 Lib/test/test_shutil.py --- a/Lib/test/test_shutil.py Sun Jun 23 01:49:42 2013 +0200 +++ b/Lib/test/test_shutil.py Sun Jun 23 02:21:19 2013 +0200 @@ -1301,6 +1301,7 @@ class TestWhich(unittest.TestCase): 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) + self.env_path = self.dir def test_basic(self): # Given an EXE in a directory, it should be returned. @@ -1369,7 +1370,7 @@ class TestWhich(unittest.TestCase): def test_environ_path(self): with support.EnvironmentVarGuard() as env: - env['PATH'] = self.dir + env['PATH'] = self.env_path rv = shutil.which(self.file) self.assertEqual(rv, self.temp_file.name) @@ -1377,7 +1378,7 @@ class TestWhich(unittest.TestCase): base_dir = os.path.dirname(self.dir) with support.temp_cwd(path=self.dir), \ support.EnvironmentVarGuard() as env: - env['PATH'] = self.dir + env['PATH'] = self.env_path rv = shutil.which(self.file, path='') self.assertIsNone(rv) @@ -1388,6 +1389,14 @@ class TestWhich(unittest.TestCase): self.assertIsNone(rv) +class TestWhichBytes(TestWhich): + def setUp(self): + TestWhich.setUp(self) + self.dir = os.fsencode(self.dir) + self.file = os.fsencode(self.file) + self.temp_file.name = os.fsencode(self.temp_file.name) + + class TestMove(unittest.TestCase): def setUp(self):