dilbert
dilbert

Reputation: 3098

Start new subprocess with 'default' environment variables

I'm writing a build script to resolve dependent shared libraries (and their shared libraries, etc.). These shared libraries do not exist in the normal PATH environment variable.

For the build process to work (for the compiler to find these libraries), the PATH has been changed to include the directories of these libraries.

The build process is thus:

Loader script (changes PATH) -> Python-based build script -> Configure -> Build -> Resolve Dependencies -> Install.

The Python instance inherits a changed PATH variable from its parent shell.

From within Python, I'm trying to get the default PATH (not the one inherited from its parent shell).

The idea:

The idea to resolve the 'default' PATH variable is to somehow 'signal' the OS to start a new process (running a script that prints PATH) but this process is NOT a child of the current Python process (and presumably won't inherit its modified environment variables).

The attempted implementation:

import os
import sys

print os.environ["PATH"]
print "---"
os.spawnl(os.P_WAIT, sys.executable, "python", "-c \"import os;print(os.environ['PATH']);\"")

os.spawn appears to use the same environment variables as the Python process which calls it. I've also tried this approach with subprocess.POpen, with no success.

Can this approach be implemented ? If not, what is an alternative approach (given that the loader script and the overall process can't change)?

I'm currently using Windows but the build script is to be cross-platform.

EDIT:

The cross-platform constraint appears to be too restrictive. Different implementations of the same concept can now be considered.

As an example, using code from this answer, the Windows registry can be used to get the 'default' system PATH variable.

try:
    import _winreg as winreg
except ImportError:
    try:
        import winreg
    except ImportError:
        winreg = None

def env_keys(user=True):
    if user:
        root = winreg.HKEY_CURRENT_USER
        subkey = "Environment"
    else:
        root = winreg.HKEY_LOCAL_MACHINE
        subkey = r"SYSTEM\CurrentControlSet\Control\Session Manager\Environment"
    return root, subkey

def get_env(name, user=True):
    root, subkey = env_keys(user)
    key = winreg.OpenKey(root, subkey, 0, winreg.KEY_READ)
    try:
        value, _ = winreg.QueryValueEx(key, name)
    except WindowsError:
        return ""
    value = winreg.ExpandEnvironmentStrings(value)
    return value

print get_env("PATH", False)

A consistent approach for *nix is needed.

Upvotes: 5

Views: 7045

Answers (2)

dano
dano

Reputation: 94871

Using subprocess.Popen, you can provide an environment for the child process to use:

default_path = os.environ['PATH'] # save the default path before changing it
os.environ['PATH'] = # whatever you want
child_env = os.environ.copy()
child_env['PATH'] = default_path
# change env
subprocess.Popen(..., env=child_env)

The documentation states that the provided environment will be used instead of inheriting it from the parent:

If env is not None, it must be a mapping that defines the environment variables for the new process; these are used instead of inheriting the current process’ environment, which is the default behavior.

Upvotes: 6

BobHy
BobHy

Reputation: 1734

What do you really mean by 'default' value of PATH? The value it had when you logged in? Some system-wide default? The value the loader script started with before it made changes?

The easiest thing would be to wrap the loader script (if you really cannot change it) with one of your own that saves the current value of PATH in some other environment variable like OLD_PATH. Then you can use something like:

os.spawnle( ... , {'PATH' : os.environ['OLD_PATH']})

Or you could spawn a shell as a login or at least interactive shell and let it source the user's .bashrc (or other startup) before invoking python.

** update ** for windows, and assuming you just want to get the PATH:

Spawn CMD.EXE, have it execute command 'echo %PATH%'

Upvotes: 0

Related Questions