From b6e8c7e8fb750e44b387557ad19afe2ccfe69f7c Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" Date: Sat, 27 Feb 2010 07:22:22 +0000 Subject: [PATCH] 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(). --- Doc/library/os.rst | 11 +++++++++++ Lib/os.py | 27 +++++++++++++++++---------- Lib/test/test_os.py | 21 +++++++++++++++++++++ Misc/NEWS | 3 +++ 4 files changed, 52 insertions(+), 10 deletions(-) diff --git a/Doc/library/os.rst b/Doc/library/os.rst index d01c8dafeb3..05471549bb4 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -136,6 +136,17 @@ process and user. 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() Return the filename corresponding to the controlling terminal of the process. diff --git a/Lib/os.py b/Lib/os.py index 1c5b5ce2eaa..580b9833cf2 100644 --- a/Lib/os.py +++ b/Lib/os.py @@ -342,28 +342,23 @@ def execvpe(file, args, env): def _execvpe(file, args, env=None): if env is not None: - func = execve + exec_func = execve argrest = (args, env) else: - func = execv + exec_func = execv argrest = (args,) env = environ head, tail = path.split(file) if head: - func(file, *argrest) + exec_func(file, *argrest) return - if 'PATH' in env: - envpath = env['PATH'] - else: - envpath = defpath - PATH = envpath.split(pathsep) last_exc = saved_exc = None saved_tb = None - for dir in PATH: + for dir in get_exec_path(env): fullname = path.join(dir, file) try: - func(fullname, *argrest) + exec_func(fullname, *argrest) except error as e: last_exc = e tb = sys.exc_info()[2] @@ -376,6 +371,18 @@ def _execvpe(file, args, env=None): 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. from _abcoll import MutableMapping # Can't use collections (bootstrap) diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py index 1ff356c0990..9846d923f59 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -407,6 +407,27 @@ def test___repr__(self): self.assertTrue(isinstance(env.data, dict)) 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): """Tests for os.walk().""" diff --git a/Misc/NEWS b/Misc/NEWS index 81dfbc0073b..8ce22add1a5 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -701,6 +701,9 @@ Library - 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 -----------------