Welcome, guest | Sign In | My Account | Store | Cart

This recipe facilitates getting and setting of both "user" and "system" environment variables on Windows. It uses PyWin32 (included in ActivePython) ... and works on both Python 2 and Python 3.

Python, 38 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import sys
from subprocess import check_call
if sys.hexversion > 0x03000000:
    import winreg
else:
    import _winreg as winreg

class Win32Environment:
    """Utility class to get/set windows environment variable"""
    
    def __init__(self, scope):
        assert scope in ('user', 'system')
        self.scope = scope
        if scope == 'user':
            self.root = winreg.HKEY_CURRENT_USER
            self.subkey = 'Environment'
        else:
            self.root = winreg.HKEY_LOCAL_MACHINE
            self.subkey = r'SYSTEM\CurrentControlSet\Control\Session Manager\Environment'
            
    def getenv(self, name):
        key = winreg.OpenKey(self.root, self.subkey, 0, winreg.KEY_READ)
        try:
            value, _ = winreg.QueryValueEx(key, name)
        except WindowsError:
            value = ''
        return value
    
    def setenv(self, name, value):
        # Note: for 'system' scope, you must run this as Administrator
        key = winreg.OpenKey(self.root, self.subkey, 0, winreg.KEY_ALL_ACCESS)
        winreg.SetValueEx(key, name, 0, winreg.REG_EXPAND_SZ, value)
        winreg.CloseKey(key)
        # For some strange reason, calling SendMessage from the current process
        # doesn't propagate environment changes at all.
        # TODO: handle CalledProcessError (for assert)
        check_call('''\
"%s" -c "import win32api, win32con; assert win32api.SendMessage(win32con.HWND_BROADCAST, win32con.WM_SETTINGCHANGE, 0, 'Environment')"''' % sys.executable)
    

Here's how you use it:

>>> e1 = Win32Environment(scope="system")
>>> print(e.getenv('PATH'))
>>> e2 = Win32Environment(scope="user")
>>> e2.setenv('PYTHONPATH', os.path.expanduser(r'~\mymodules'))

As you can see, the former prints the value of the system PATH environment, while the later sets a user environment variable.

This recipe is inspired by this StackOverflow answer.

5 comments

Denis Barmenkov 10 years, 8 months ago  # | flag
Sunjay Varma 10 years, 8 months ago  # | flag

Quick thing: You forgot to import sys on top!

Thanks for the recipe!

Sunjay Varma 10 years, 8 months ago  # | flag

Also, in the example, it should be this:

>>> print(e1.getenv("PATH"))
Sunjay Varma 10 years, 8 months ago  # | flag

Another thing (sorry for posting so many comments), is that in the getenv function, the key is never closed. I'm not sure if this would have any effect, I just noticed that you closed it in setenv, but not getenv.

Sridhar Ratnakumar (author) 10 years, 8 months ago  # | flag

[...] in the getenv function, the key is never closed. I'm not sure if this would have any effect, I just noticed that you closed it in setenv, but not getenv.

Good catch, I'm not sure either. In my actual code, I use regobj which (I believe) automatically closes open keys.