]> granicus.if.org Git - python/commitdiff
Add an os.get_exec_path() function to return the list of directories
authorGregory P. Smith <greg@mad-scientist.com>
Sat, 27 Feb 2010 07:22:22 +0000 (07:22 +0000)
committerGregory P. Smith <greg@mad-scientist.com>
Sat, 27 Feb 2010 07:22:22 +0000 (07:22 +0000)
that launching a subprocess will search for the executable.
Refactors some code in os._execvpe().

Doc/library/os.rst
Lib/os.py
Lib/test/test_os.py
Misc/NEWS

index d01c8dafeb3e43f4e183c40af7dc01b192f404b0..05471549bb4c5f0ac97e544f9e0dc04e45a55111 100644 (file)
@@ -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.
index 1c5b5ce2eaaf2cb43e01099bc41f8a5253e3db9c..580b9833cf20f238416711fe8374ca7d9945845a 100644 (file)
--- a/Lib/os.py
+++ b/Lib/os.py
@@ -342,28 +342,23 @@ __all__.extend(["execl","execle","execlp","execlpe","execvp","execvpe"])
 
 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)
 
index 1ff356c099043f36b2a8d8cbc0b94245ee465a22..9846d923f592e99ffea3274cbac75ca60b42614f 100644 (file)
@@ -407,6 +407,27 @@ class EnvironTests(mapping_tests.BasicTestMappingProtocol):
         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()."""
index 81dfbc0073be60c43276d2fbd63b1916dcaad47f..8ce22add1a543716b3228e1fdc9f9ef075be8e6c 100644 (file)
--- 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
 -----------------