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

This modules provides a few handy functions to retrieve the path names of some windows system directories from the registry [1] and the environment. These path names can be different depending on OS version, installation language, current user and personal setup. Because of this, they should not be included statically in your program.

Python, 150 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
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# winpaths.py

"""Functions for getting system/language/user dependent paths on windows.

All path names returned by the functions of this module are unicode strings.
"""

__all__ = [
  'HKCU', 'HKLM',
  'SHELL_FOLDERS',
  'USER_SHELL_FOLDERS',
  'expandvars',
  'get_appdata',
  'get_common_shellfolders',
  'get_homedir',
  'get_sharedconf',
  'get_shellfolders',
  'get_userconf',
  'get_windir'
]

__module__    = "winpaths"
__author__    = "Christopher Arndt"
__version__   = "0.1"
__revision__  = "$Rev$"
__date__      = "$Date$"
__copyright__ = "Python license"

# standard library modules
import _winreg, os

SHELL_FOLDERS = \
  r'Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders'
USER_SHELL_FOLDERS = \
  r'Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders'
HKCU = _winreg.HKEY_CURRENT_USER
HKLM = _winreg.HKEY_LOCAL_MACHINE

# helper functions
def _substenv(m):
    return os.environ.get(m.group(1), m.group(0))

_env_rx = None
def expandvars(s):
    """Expand environment variables of form %var%.

    Unknown variables are left unchanged.
    """

    global _env_rx

    if '%' not in s:
        return s
    if _env_rx is None:
        import re
        _env_rx = re.compile(r'%([^|<>=^%]+)%')
    return _env_rx.sub(_substenv, s)

def _get_reg_value(key, subkey, name):
    """Return registry value specified by key, subkey, and name.

    Environment variables in values of type REG_EXPAND_SZ are expanded
    if possible.
    """

    key = _winreg.OpenKey(key, subkey)
    try:
        ret = _winreg.QueryValueEx(key, name)
    except WindowsError:
        return None
    else:
        key.Close()
        if ret[1] == _winreg.REG_EXPAND_SZ:
            return expandvars(ret[0])
        else:
            return ret[0]

def _get_reg_user_value(key, name):
    """Return a windows registry value from the CURRENT_USER branch."""

    return _get_reg_value(HKCU, key, name)

def _get_reg_machine_value(key, name):
    """Return a windows registry value from the LOCAL_MACHINE branch."""

    return _get_reg_value(HKLM, key, name)

# public functions
def get_appdata():
    """Return path of directory where apps should store user specific data."""

    return _get_reg_user_value(SHELL_FOLDERS, 'AppData')

def get_common_shellfolders():
    """Return mapping of shell folder names (all users) to paths."""

    return get_shellfolders(branch=HKLM)

def get_homedir():
    """Return path to user home directory, i.e. 'My Files'."""

    return _get_reg_user_value(SHELL_FOLDERS, 'Personal')

def get_sharedconf(prog, *args):
    """Return path to shared configuration data for 'prog' from 'vendor'.

    Additional arguments are appended via os.path.join().

    See also: get_user_conf()
    """

    return os.path.join(
      _get_reg_machine_value(SHELL_FOLDERS, 'Common AppData'),
      vendor, prog, *args
    )

def get_shellfolders(branch=HKCU, key=SHELL_FOLDERS):
    """Return mapping of shell folder names (current user) to paths."""

    key = _winreg.OpenKey(branch, key)
    folders = {}
    i = 0
    while True:
        try:
            ret = _winreg.EnumValue(key, i)
            if ret[2] == _winreg.REG_EXPAND_SZ:
                folders[ret[0]] = expandvars(ret[1])
            else:
                folders[ret[0]] = ret[1]
        except WindowsError:
            break
        i +=1
    key.Close()
    return folders

def get_userconf(vendor, prog, *args):
    """Return path to user configuration data for 'prog' from 'vendor'.

    Additional arguments are appended via os.path.join(), e.g.
    use like this:

    optionsfn = get_userconf("ACME Soft", "Exploder", "Options.xml")
    """

    return os.path.join(get_appdata(), vendor, prog, *args)

def get_windir():
    """Convenience function to get path to windows installation directory."""

    return unicode(os.environ["WINDIR"])

This module is especially useful, if your program wants to read/write configuration data from/to files (see recipe 146305 [2] for storing configuration data in the registry).

Example:

>>> from ConfigParser import RawConfigParser
>>> parser = RawConfigParser()
>>> parser.read(get_userconf("ACME Soft", "Exploder", "config.ini"))

Related recipes:

[1] http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66011 [2] http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/146305

2 comments

Denis Barmenkov 18 years, 1 month ago  # | flag

win32api.ExpandEnvironmentStrings is our choice! 8-). Function expandvars are easily replaced by win32api.ExpandEnvironmentStrings

Chris Arndt (author) 18 years, 1 month ago  # | flag

expandvars. Good to know! I am not very familiar with the win32 extensions.

But my module would work with just the Python standard library without win32api installed.