4

Reading out OS environment variables in Python is a piece of cake. Try out the following three code lines to read out the 'PATH' variable in Windows:

    #################
    #   PYTHON 3.5  #
    #################
    >> import os
    >> pathVar = os.getenv('Path')
    >> print(pathVar)

        C:\Anaconda3\Library\bin;C:\Anaconda3\Library\bin;
        C:\WINDOWS\system32;C:\Anaconda3\Scripts;C:\Apps\SysGCC\arm-eabi\bin;
        ...

Now make a small change in the 'PATH' variable. You can find them in:

Control Panel >> System and Security >> System >> Advanced system settings >> Environment variables

If you run the same code in Python, the change is not visible! You've got to close down the terminal in which you started the Python session. When you restart it, and run the code again, the change will be visible.

Is there a way to see the change immediately - without the need to close python? This is important for the application that I'm building.

Thank you so much :-)


EDIT :

Martijn Pieters showed me the following link: Is there a command to refresh environment variables from the command prompt in Windows?

There are many options mentioned in that link. I chose the following one (because it is just a batch file, no extra dependencies):

            REM   --------------------------------------------
            REM   |            refreshEnv.bat                |
            REM   --------------------------------------------
    @ECHO OFF
    REM Source found on https://github.com/DieterDePaepe/windows-scripts
    REM Please share any improvements made!

    REM Code inspired by https://stackoverflow.com/questions/171588/is-there-a-command-to-refresh-environment-variables-from-the-command-prompt-in-w

    IF [%1]==[/?] GOTO :help
    IF [%1]==[/help] GOTO :help
    IF [%1]==[--help] GOTO :help
    IF [%1]==[] GOTO :main

    ECHO Unknown command: %1
    EXIT /b 1 

    :help
    ECHO Refresh the environment variables in the console.
    ECHO.
    ECHO   refreshEnv       Refresh all environment variables.
    ECHO   refreshEnv /?        Display this help.
    GOTO :EOF

    :main
    REM Because the environment variables may refer to other variables, we need a 2-step approach.
    REM One option is to use delayed variable evaluation, but this forces use of SETLOCAL and
    REM may pose problems for files with an '!' in the name.
    REM The option used here is to create a temporary batch file that will define all the variables.

    REM Check to make sure we dont overwrite an actual file.
    IF EXIST %TEMP%\__refreshEnvironment.bat (
      ECHO Environment refresh failed!
      ECHO.
      ECHO This script uses a temporary file "%TEMP%\__refreshEnvironment.bat", which already exists. The script was aborted in order to prevent accidental data loss. Delete this file to enable this script.
      EXIT /b 1
    )

    REM Read the system environment variables from the registry.
    FOR /F "usebackq tokens=1,2,* skip=2" %%I IN (`REG QUERY "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment"`) DO (
      REM /I -> ignore casing, since PATH may also be called Path
      IF /I NOT [%%I]==[PATH] (
        ECHO SET %%I=%%K>>%TEMP%\__refreshEnvironment.bat
      )
    )

    REM Read the user environment variables from the registry.
    FOR /F "usebackq tokens=1,2,* skip=2" %%I IN (`REG QUERY HKCU\Environment`) DO (
      REM /I -> ignore casing, since PATH may also be called Path
      IF /I NOT [%%I]==[PATH] (
        ECHO SET %%I=%%K>>%TEMP%\__refreshEnvironment.bat
      )
    )

    REM PATH is a special variable: it is automatically merged based on the values in the
    REM system and user variables.
    REM Read the PATH variable from the system and user environment variables.
    FOR /F "usebackq tokens=1,2,* skip=2" %%I IN (`REG QUERY "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /v PATH`) DO (
      ECHO SET PATH=%%K>>%TEMP%\__refreshEnvironment.bat
    )
    FOR /F "usebackq tokens=1,2,* skip=2" %%I IN (`REG QUERY HKCU\Environment /v PATH`) DO (
      ECHO SET PATH=%%PATH%%;%%K>>%TEMP%\__refreshEnvironment.bat
    )

    REM Load the variable definitions from our temporary file.
    CALL %TEMP%\__refreshEnvironment.bat

    REM Clean up after ourselves.
    DEL /Q %TEMP%\__refreshEnvironment.bat

    ECHO Environment successfully refreshed.

This solution works on my computer (64-bit Windows 10). The environment variables get updated. However, I get the following error:

    ERROR: The system was unable to find the specified registry key or value.

Strange.. I get an error, but the variables do get updated.


EDIT :

The environment variables get updated when I call the batch file 'refreshEnv' directly in the terminal window. But it doesn't work when I call it from my Python program:

    #################################
    #          PYTHON 3.5           #
    #   -------------------------   #
    # Refresh Environment variables #
    #################################
    def refresh(self):
        p = Popen(self.homeCntr.myState.getProjectFolder() + "\\refreshEnv.bat", cwd=r"{0}".format(str(self.homeCntr.myState.getProjectFolder())))
    ###

Why? Is it because Popen runs the batch file in another cmd terminal, such that it doesn't affect the current Python process?

Community
  • 1
  • 1
K.Mulier
  • 6,430
  • 9
  • 58
  • 110
  • 5
    Shortly: you can't. Environment variables are set for a process when it starts, and are not updated. This is not limited to Python. – Martijn Pieters Jul 23 '16 at 18:42
  • This would be a dupe of [Is there a way to change another process's environment variables?](http://stackoverflow.com/q/205064) if this was Linux, but the same limitations apply to Windows. – Martijn Pieters Jul 23 '16 at 18:47
  • Closely related, if not a direct dupe, as it explains about environment variables and process memory: [Is there a command to refresh environment variables from the command prompt in Windows?](http://stackoverflow.com/q/171588) – Martijn Pieters Jul 23 '16 at 18:49
  • Waw, Thank you Martijn! These links are really helpful :-) – K.Mulier Jul 23 '16 at 19:07
  • Hi @MartijnPieters , I found kind of a solution thanks to your links. However, I still get an error message. Do you have an idea why? (I've updated my question with the details :-) – K.Mulier Jul 23 '16 at 21:01

1 Answers1

5

On Windows, the initial environment variables are stored in the registry: HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment for system variables and HKEY_CURRENT_USER\Environment for user variables.

Using the winreg module in Python, you can query these environment variables easily without resorting to external scripts:

import winreg
def get_sys_env(name):
    key = winreg.CreateKey(winreg.HKEY_LOCAL_MACHINE, r"System\CurrentControlSet\Control\Session Manager\Environment")
    return winreg.QueryValueEx(key, name)[0]

def get_user_env(name):
    key = winreg.CreateKey(winreg.HKEY_CURRENT_USER, r"Environment")
    return winreg.QueryValueEx(key, name)[0]

(On Python 2.x, use import _winreg as winreg on the first line instead).

With this, you can just use get_sys_env("PATH") instead of os.environ["PATH"] any time you want an up-to-date PATH variable. This is safer, faster and less complicated than shelling out to an external script.

nneonneo
  • 154,210
  • 32
  • 267
  • 343