This class wraps most of the win32api functions for accessing a registry. It will read and write all win32 registry types, and will de/serialize python objects to registry keys when a string or integer representation is not possible.
This is an update of recipe 551761, which is in turn an update of 174627, folding in the enhancements listed in the discussion there to allow registry value types to be read and written within the dictionary metaphore if required. It doesnt change how it worked before, it adds a new capability, and shouldnt break existing code using the 551761 version.
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 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 | # From the recipe at http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/551761
# A backwards compatible enhancement has been made to allow full access to registry types still through the dictionary metaphor
"""Slightly magical Win32api Registry -> Dictionary-like-object wrapper"""
import win32api, win32con, cPickle
class RegistryDict(object):
def __init__(self, keyhandle = win32con.HKEY_LOCAL_MACHINE, keypath = [], flags = None):
"""If flags=None, then it will create the key.. otherwise pass a win32con.KEY_* sam"""
self.keyhandle = None
self.open(keyhandle, keypath, flags)
@staticmethod
def massageIncomingRegistryValue((obj, objtype), bReturnType=False):
r=None
if objtype == win32con.REG_BINARY and obj[:8]=='PyPickle':
obj = obj[8:]
r = (cPickle.loads(obj), objtype)
elif objtype == win32con.REG_NONE:
r = (None, objtype)
elif objtype in (win32con.REG_SZ, win32con.REG_EXPAND_SZ,
win32con.REG_RESOURCE_LIST, win32con.REG_LINK,
win32con.REG_BINARY, win32con.REG_DWORD,
win32con.REG_DWORD_LITTLE_ENDIAN, win32con.REG_DWORD_BIG_ENDIAN,
win32con.REG_MULTI_SZ):
r = (obj,objtype)
if r == None:
raise NotImplementedError, "Registry type 0x%08X not supported" % (objtype,)
if bReturnType:
return r
else:
return r[0]
def __getitem__(self, key):
bReturnType=False
if (type(key) is tuple) and (len(key)==1):
key = key[0]
bReturnType=True
# is it data?
try:
return self.massageIncomingRegistryValue(win32api.RegQueryValueEx(self.keyhandle, key),bReturnType)
except:
if key == '':
# Special case: this dictionary key means "default value"
raise KeyError, key
pass
# it's probably a registry key then
try:
return RegistryDict(self.keyhandle, key, win32con.KEY_ALL_ACCESS)
except:
pass
# must not be there
raise KeyError, key
def has_key(self, key):
return self.__contains__(key)
def __contains__(self, key):
try:
self.__getitem__(key)
return 1
except KeyError:
return 0
def copy(self):
return dict(self.iteritems())
def __repr__(self):
return repr(self.copy())
def __str__(self):
return self.__repr__()
def __cmp__(self, other):
# Do the objects have the same state?
return self.keyhandle == other.keyhandle
def __hash__(self):
raise TypeError, "RegistryDict objects are unhashable"
def clear(self):
keylist = list(self.iterkeys())
# Two-step to avoid changing the set while iterating over it
for k in keylist:
del self[k]
def iteritems_data(self):
i = 0
# yield data
try:
while 1:
s, obj, objtype = win32api.RegEnumValue(self.keyhandle, i)
yield s, self.massageIncomingRegistryValue((obj, objtype))
i += 1
except:
pass
def iteritems_children(self, access=win32con.KEY_ALL_ACCESS):
i = 0
try:
while 1:
s = win32api.RegEnumKey(self.keyhandle, i)
yield s, RegistryDict(self.keyhandle, [s], access)
i += 1
except:
pass
def iteritems(self, access=win32con.KEY_ALL_ACCESS):
# yield children
for item in self.iteritems_data():
yield item
for item in self.iteritems_children(access):
yield item
def iterkeys_data(self):
for key, value in self.iteritems_data():
yield key
def iterkeys_children(self, access=win32con.KEY_ALL_ACCESS):
for key, value in self.iteritems_children(access):
yield key
def iterkeys(self):
for key, value in self.iteritems():
yield key
def itervalues_data(self):
for key, value in self.iteritems_data():
yield value
def itervalues_children(self, access=win32con.KEY_ALL_ACCESS):
for key, value in self.iteritems_children(access):
yield value
def itervalues(self, access=win32con.KEY_ALL_ACCESS):
for key, value in self.iteritems(access):
yield value
def items(self, access=win32con.KEY_ALL_ACCESS):
return list(self.iteritems())
def keys(self):
return list(self.iterkeys())
def values(self, access=win32con.KEY_ALL_ACCESS):
return list(self.itervalues(access))
def __delitem__(self, key):
# Delete a string value or a subkey, depending on the type
try:
item = self[key]
except:
return # Silently ignore bad keys
itemtype = type(item)
if itemtype is str:
win32api.RegDeleteValue(self.keyhandle, key)
elif isinstance(item, RegistryDict):
# Delete everything in the subkey, then the subkey itself
item.clear()
win32api.RegDeleteKey(self.keyhandle, key)
else:
raise ValueError, "Unknown item type in RegistryDict"
def __len__(self):
return len(self.items())
def __iter__(self):
return self.iterkeys()
def popitem(self):
try:
k, v = self.iteritems().next()
del self[k]
return k, v
except StopIteration:
raise KeyError, "RegistryDict is empty"
def get(self,key,default=None):
try:
return self.__getitem__(key)
except:
return default
def setdefault(self,key,default=None):
try:
return self.__getitem__(key)
except:
self.__setitem__(key)
return default
def update(self,d):
for k,v in d.items():
self.__setitem__(k, v)
def __setitem__(self, item, value):
item = str(item)
pyvalue = type(value)
if pyvalue is tuple and len(value)==2:
valuetype = value[1]
value = value[0]
else:
if pyvalue is dict or isinstance(value, RegistryDict):
d = RegistryDict(self.keyhandle, item)
d.clear()
d.update(value)
return
if pyvalue is str:
valuetype = win32con.REG_SZ
elif pyvalue is int:
valuetype = win32con.REG_DWORD
else:
valuetype = win32con.REG_BINARY
value = 'PyPickle' + cPickle.dumps(value)
win32api.RegSetValueEx(self.keyhandle, item, 0, valuetype, value)
def open(self, keyhandle, keypath, flags = None):
if self.keyhandle:
self.close()
if type(keypath) is str:
keypath = keypath.split('\\')
if flags is None:
for subkey in keypath:
keyhandle = win32api.RegCreateKey(keyhandle, subkey)
else:
for subkey in keypath:
keyhandle = win32api.RegOpenKeyEx(keyhandle, subkey, 0, flags)
self.keyhandle = keyhandle
def close(self):
try:
win32api.RegCloseKey(self.keyhandle)
except:
pass
def __del__(self):
self.close()
|
Love this recipe! It makes using the registry very easy.
I made a few additions, because apparently string variables appear now as Unicode, and also int variables are allowed.
This means I propose to change line 156 into:
Moreover I added some test code at the bottom:
Note, that if you explicitly pass "flags=None" in the call to RegistryDict, new keys will be made automatically.