Index: Doc/library/os.rst =================================================================== --- Doc/library/os.rst (révision 81227) +++ Doc/library/os.rst (copie de travail) @@ -171,9 +171,11 @@ Returns the list of directories that will be searched for a named executable, similar to a shell, when launching a process. *env*, when specified, should be an environment variable dictionary - to lookup the PATH in. - By default, when *env* is None, :data:`environ` is used. + to lookup the PATH in. Result type is str on Windows, bytes on Unix. + By default, when *env* is None, :data:`environ` is used on Windows or + :data:`environb` on Unix. + .. versionadded:: 3.2 Index: Lib/os.py =================================================================== --- Lib/os.py (révision 81227) +++ Lib/os.py (copie de travail) @@ -355,6 +355,8 @@ return last_exc = saved_exc = None saved_tb = None + if not path.supports_unicode_filenames: + file = fsencode(file) for dir in get_exec_path(env): fullname = path.join(dir, file) try: @@ -374,13 +376,36 @@ def get_exec_path(env=None): """Returns the sequence of directories that will be searched for the named executable (similar to a shell) when launching a process. + Result type is str on Windows, bytes on Unix. - *env* must be an environment variable dict or None. If *env* is None, - os.environ will be used. + env must be an environment variable dict or None. If env is None, + os.environ will be used on Windows or os.environb on Unix. """ if env is None: - env = environ - return env.get('PATH', defpath).split(pathsep) + if supports_bytes_environ: + env = environb + else: + env = environ + try: + path_list = env.get('PATH') + except TypeError: + path_list = None + if supports_bytes_environ: + try: + path_listb = env[b'PATH'] + except (KeyError, TypeError): + pass + else: + if path_list is not None: + raise ValueError( + "env contains two PATH variables of different types") + path_list = path_listb + if path_list is None: + path_list = defpath + if path.supports_unicode_filenames: + return path_list.split(pathsep.encode('ascii')) + else: + return fsencode(path_list).split(pathsep.encode('ascii')) # Change environ to automatically call putenv(), unsetenv if they exist. @@ -482,9 +507,11 @@ The optional second argument can specify an alternate default. key, default and the result are str.""" return environ.get(key, default) -__all__.append("getenv") -if name not in ('os2', 'nt'): +supports_bytes_environ = name not in ('os2', 'nt') +__all__.extend(("getenv", "supports_bytes_environ")) + +if supports_bytes_environ: def _check_bytes(value): if not isinstance(value, bytes): raise TypeError("bytes expected, not %s" % type(value).__name__) @@ -504,7 +531,7 @@ return environb.get(key, default) __all__.append("getenvb") -if name != 'nt': +if not path.supports_unicode_filenames: def fsencode(value): """Encode value for use in the file system, environment variables or the command line.""" Index: Lib/test/test_subprocess.py =================================================================== --- Lib/test/test_subprocess.py (révision 81227) +++ Lib/test/test_subprocess.py (copie de travail) @@ -825,7 +825,23 @@ stdout = stdout.rstrip(b'\n\r') self.assertEquals(stdout.decode('ascii'), repr(value)) + def test_bytes_program(self): + path, program = os.path.split(sys.executable) + program = os.fsencode(program) + # bytes program, unicode PATH + env = os.environ.copy() + env["PATH"] = path + exitcode = subprocess.call([program, "-c", "pass"], env=env) + self.assertEquals(exitcode, 0) + + # bytes program, bytes PATH + envb = os.environb.copy() + envb[b"PATH"] = os.fsencode(path) + exitcode = subprocess.call([program, "-c", "pass"], env=envb) + self.assertEquals(exitcode, 0) + + @unittest.skipUnless(mswindows, "Windows specific tests") class Win32ProcessTestCase(BaseTestCase): Index: Lib/subprocess.py =================================================================== --- Lib/subprocess.py (révision 81227) +++ Lib/subprocess.py (copie de travail) @@ -1096,15 +1096,14 @@ for k, v in env.items()] else: env_list = None # Use execv instead of execve. + executable = os.fsencode(executable) if os.path.dirname(executable): - executable_list = (os.fsencode(executable),) + executable_list = (executable,) else: # This matches the behavior of os._execvpe(). - path_list = os.get_exec_path(env) - executable_list = (os.path.join(dir, executable) - for dir in path_list) - executable_list = tuple(os.fsencode(exe) - for exe in executable_list) + executable_list = tuple( + os.path.join(dir, executable) + for dir in os.get_exec_path(env)) self.pid = _posixsubprocess.fork_exec( args, executable_list, close_fds, cwd, env_list,