简体   繁体   中英

How to modify windows 10 path variable directly from a python script

I am looking to permanently modify the path variable inside windows from a python script. The script is a wrapper to help automate the installation of applications and I want to enable the API to add applications to the path.

So for example I want to install a program called micro which has an install path of C:\\Users\\USERNAME\\Path\\to\\micro and then add that install path to my path variable so that I can just run micro in my terminal.

I've been made aware of 2 possible solutions, which both do not work:

1. Using os.environ

In python the os module let's you read environment variables, but not actually modify them. so for example:

program_path = "C:\\Users\\USERNAME\\Path\\to\\micro"
new_path = f"{os.environ['PATH']};{program_path}"
os.environ["PATH"] = new_path

This would update the path variable in the python script, but it does not actually modify it on the system which is what I want.

2. setx

I was made aware that it is possible to update your path using the setx command in windows, but for some reason on windows 10 this destroys your path variable.

The idea is that you can call the setx command from python and use it to update the path variable. You should be able to type setx path "%path%;C:\\Users\\USERNAME\\Path\\to\\micro" and have it update correctly.

So for example, in python code that would be:

program_path = "C:\\Users\\USERNAME\\Path\\to\\micro"
subprocess.Popen(f'setx path "%path%;{program_path}"')

This should take the current path variable and append the program path to it, but instead it just wipes your entire path and replaces it with a literal %path% and then the program path.

So now my path looks like this:

%path%
C:\Users\USERNAME\Path\to\micro

Any ideas on how to get this to work would be appreciated.

Okay, so after a long (and disgusting) amount of research I found a solution. Here is the method I came up with for a cross-platform system of adding to PATH variable:

def add_to_path(program_path:str):
    """Takes in a path to a program and adds it to the system path"""
    if os.name == "nt": # Windows systems
        import winreg # Allows access to the windows registry
        import ctypes # Allows interface with low-level C API's

        with winreg.ConnectRegistry(None, winreg.HKEY_CURRENT_USER) as root: # Get the current user registry
            with winreg.OpenKey(root, "Environment", 0, winreg.KEY_ALL_ACCESS) as key: # Go to the environment key
                existing_path_value = winreg.EnumValue(key, 3)[1] # Grab the current path value
                new_path_value = existing_path_value + program_path + ";" # Takes the current path value and appends the new program path
                winreg.SetValueEx(key, "PATH", 0, winreg.REG_EXPAND_SZ, new_path_value) # Updated the path with the updated path

            # Tell other processes to update their environment
            HWND_BROADCAST = 0xFFFF
            WM_SETTINGCHANGE = 0x1A
            SMTO_ABORTIFHUNG = 0x0002
            result = ctypes.c_long()
            SendMessageTimeoutW = ctypes.windll.user32.SendMessageTimeoutW
            SendMessageTimeoutW(HWND_BROADCAST, WM_SETTINGCHANGE, 0, u"Environment", SMTO_ABORTIFHUNG, 5000, ctypes.byref(result),) 
    else: # If system is *nix
        with open(f"{os.getenv('HOME')}/.bashrc", "a") as bash_file:  # Open bashrc file
            bash_file.write(f'\nexport PATH="{program_path}:$PATH"\n')  # Add program path to Path variable
        os.system(f". {os.getenv('HOME')}/.bashrc")  # Update bash source
    print(f"Added {program_path} to path, please restart shell for changes to take effect")

Neither are pretty, but it does actually work. You do need to restart running shells for it to take effect, but other than that it's perfect.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM