mirror of
https://github.com/python/cpython.git
synced 2025-09-01 14:38:00 +00:00
Add an os.get_exec_path() function to return the list of directories
that launching a subprocess will search for the executable. Refactors some code in os._execvpe().
This commit is contained in:
parent
9a81697494
commit
b6e8c7e8fb
4 changed files with 52 additions and 10 deletions
|
@ -136,6 +136,17 @@ process and user.
|
||||||
These functions are described in :ref:`os-file-dir`.
|
These functions are described in :ref:`os-file-dir`.
|
||||||
|
|
||||||
|
|
||||||
|
.. function:: get_exec_path(env=None)
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
.. versionadded:: 3.2
|
||||||
|
|
||||||
|
|
||||||
.. function:: ctermid()
|
.. function:: ctermid()
|
||||||
|
|
||||||
Return the filename corresponding to the controlling terminal of the process.
|
Return the filename corresponding to the controlling terminal of the process.
|
||||||
|
|
27
Lib/os.py
27
Lib/os.py
|
@ -342,28 +342,23 @@ __all__.extend(["execl","execle","execlp","execlpe","execvp","execvpe"])
|
||||||
|
|
||||||
def _execvpe(file, args, env=None):
|
def _execvpe(file, args, env=None):
|
||||||
if env is not None:
|
if env is not None:
|
||||||
func = execve
|
exec_func = execve
|
||||||
argrest = (args, env)
|
argrest = (args, env)
|
||||||
else:
|
else:
|
||||||
func = execv
|
exec_func = execv
|
||||||
argrest = (args,)
|
argrest = (args,)
|
||||||
env = environ
|
env = environ
|
||||||
|
|
||||||
head, tail = path.split(file)
|
head, tail = path.split(file)
|
||||||
if head:
|
if head:
|
||||||
func(file, *argrest)
|
exec_func(file, *argrest)
|
||||||
return
|
return
|
||||||
if 'PATH' in env:
|
|
||||||
envpath = env['PATH']
|
|
||||||
else:
|
|
||||||
envpath = defpath
|
|
||||||
PATH = envpath.split(pathsep)
|
|
||||||
last_exc = saved_exc = None
|
last_exc = saved_exc = None
|
||||||
saved_tb = None
|
saved_tb = None
|
||||||
for dir in PATH:
|
for dir in get_exec_path(env):
|
||||||
fullname = path.join(dir, file)
|
fullname = path.join(dir, file)
|
||||||
try:
|
try:
|
||||||
func(fullname, *argrest)
|
exec_func(fullname, *argrest)
|
||||||
except error as e:
|
except error as e:
|
||||||
last_exc = e
|
last_exc = e
|
||||||
tb = sys.exc_info()[2]
|
tb = sys.exc_info()[2]
|
||||||
|
@ -376,6 +371,18 @@ def _execvpe(file, args, env=None):
|
||||||
raise last_exc.with_traceback(tb)
|
raise last_exc.with_traceback(tb)
|
||||||
|
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
*env* must be an environment variable dict or None. If *env* is None,
|
||||||
|
os.environ will be used.
|
||||||
|
"""
|
||||||
|
if env is None:
|
||||||
|
env = environ
|
||||||
|
return env.get('PATH', defpath).split(pathsep)
|
||||||
|
|
||||||
|
|
||||||
# Change environ to automatically call putenv(), unsetenv if they exist.
|
# Change environ to automatically call putenv(), unsetenv if they exist.
|
||||||
from _abcoll import MutableMapping # Can't use collections (bootstrap)
|
from _abcoll import MutableMapping # Can't use collections (bootstrap)
|
||||||
|
|
||||||
|
|
|
@ -407,6 +407,27 @@ class EnvironTests(mapping_tests.BasicTestMappingProtocol):
|
||||||
self.assertTrue(isinstance(env.data, dict))
|
self.assertTrue(isinstance(env.data, dict))
|
||||||
self.assertEqual(repr(env), 'environ({!r})'.format(env.data))
|
self.assertEqual(repr(env), 'environ({!r})'.format(env.data))
|
||||||
|
|
||||||
|
def test_get_exec_path(self):
|
||||||
|
defpath_list = os.defpath.split(os.pathsep)
|
||||||
|
test_path = ['/monty', '/python', '', '/flying/circus']
|
||||||
|
test_env = {'PATH': os.pathsep.join(test_path)}
|
||||||
|
|
||||||
|
saved_environ = os.environ
|
||||||
|
try:
|
||||||
|
os.environ = dict(test_env)
|
||||||
|
# Test that defaulting to os.environ works.
|
||||||
|
self.assertSequenceEqual(test_path, os.get_exec_path())
|
||||||
|
self.assertSequenceEqual(test_path, os.get_exec_path(env=None))
|
||||||
|
finally:
|
||||||
|
os.environ = saved_environ
|
||||||
|
|
||||||
|
# No PATH environment variable
|
||||||
|
self.assertSequenceEqual(defpath_list, os.get_exec_path({}))
|
||||||
|
# Empty PATH environment variable
|
||||||
|
self.assertSequenceEqual(('',), os.get_exec_path({'PATH':''}))
|
||||||
|
# Supplied PATH environment variable
|
||||||
|
self.assertSequenceEqual(test_path, os.get_exec_path(test_env))
|
||||||
|
|
||||||
|
|
||||||
class WalkTests(unittest.TestCase):
|
class WalkTests(unittest.TestCase):
|
||||||
"""Tests for os.walk()."""
|
"""Tests for os.walk()."""
|
||||||
|
|
|
@ -701,6 +701,9 @@ Library
|
||||||
|
|
||||||
- Issue #6218: io.StringIO and io.BytesIO instances are now picklable.
|
- Issue #6218: io.StringIO and io.BytesIO instances are now picklable.
|
||||||
|
|
||||||
|
- The os.get_exec_path() function to return the list of directories that will
|
||||||
|
be searched for an executable when launching a subprocess was added.
|
||||||
|
|
||||||
Extension Modules
|
Extension Modules
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue