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.
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 | """Slightly magical Win32api Registry -> Dictionary-like-object wrapper"""
from __future__ import generators
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"""
keyhandle = None
self.open(keyhandle, keypath, flags)
def massageIncomingRegistryValue((obj, objtype)):
if objtype == win32con.REG_BINARY and obj[:8]=='PyPickle':
obj = obj[8:]
return cPickle.loads(obj)
elif objtype == win32con.REG_NONE:
return None
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):
return obj
raise NotImplementedError, "Registry type 0x%08X not supported" % (objtype,)
massageIncomingRegistryValue = staticmethod(massageIncomingRegistryValue)
def __getitem__(self, item):
item = str(item)
# is it data?
try:
return self.massageIncomingRegistryValue(win32api.RegQueryValueEx(self.keyhandle, item))
except:
pass
# it's probably a key then
try:
return RegistryDict(self.keyhandle, item, win32con.KEY_ALL_ACCESS)
except:
pass
# must not be there
raise KeyError, item
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):
return cmp(self.copy(), other)
def __hash__(self):
raise TypeError, "RegistryDict objects are unhashable"
def clear(self):
for k in self.iterkeys():
del self[k]
def iteritems_data(self):
i = 0
# yield data
try:
while 1:
s, obj, objtype = win32api.RegEnumValue(self.keyhandle, i)
yield s, massageRegistryValue((obj, objtype))
i += 1
except:
pass
def iteritems_children(self, access=win32con.KEY_ALL_ACCESS):
i = 0
try:
while 1:
s, obj, objtype = 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, item):
win32api.RegDeleteValue(self.keyhandle, str(item))
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 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()
|
A developer would choose this recipe to make working with the win32 registry pythonic. It's also very useful when implementing a cross-platform solution to storing preferences. For example, you could have a proxy class use ~/.YourCompany.YourSoftware (and a pickled dict) for unix, HKLM\Software\YourCompany\YourSoftware registry keys (using this class) in windows, and ~/Library/Preferences/YourCompany.YourSoftware.plist (and a plist-ed/pickled dict) for OS X.
self. missing. 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 # THIS should be this way, should it not? self.open(keyhandle, keypath, flags)
otherwise self.open leads to "... has no attribut "keyhandle")
Updates and fixes. I've had occasion to use this class, and have found it quite nice. There are a few changes I've had to make, though:
The previous comment's correction, adding "self." to the first line of __init__ to make keyhandle an ivar, is correct.
Changed the definition of __cmp__ to the following:
Changed the definition of clear to the following:
In iteritems_data, the call to "massage..." should be:
In iteritems_children, changed the RegEnumKey line to read:
The __delitem__ method only deletes string values. I changed it to the following:
Note the use of .clear() to delete the whole tree under the subkey. A more cautious approach would be to require the client code to manage that.
In the "open" method, the "else" clause is one level too deep. The "else" should be paired with "if flags is None:"
If desired, I can put a patch or the whole file somewhere around here.
Oops! one more fix. I just ran across another subtle bug: the dictionary key '' (the empty string) must mean the "default value" of a registry key, but it was returning a copy of "self" if there was no default value. The following updated __getitem__ fixes this:
Requests. This looks like a very cool recipe. It would help though to have the updated/fixed version of this recipe posted in it's entirety. Cutting and pasting the fixes from the comments is somewhat error prone. It'd also be nice if some simple test cases were constructed to act as a demonstration of the usage of this module.
I second that. I agree with the previous post. Before or after applying the mentioned bug fixes, I've never gotten this to work. Without clear examples and tests in a main function like many other recipes, I wouldn't be sure if I were using it properly anyway. This looks like a very useful and promising recipe, but it definitely could be improved with unit tests and some refactoring.
Fixed script, downloadable. You can download the entire script with the fixes above from:
http://mikebabcock.ca/code/registrydict.py
You're welcome :)
PS, I'll update this with any other patches/fixes I notice from here. I made one change myself as well, by removing an unnecessary temporary variable in one of the other patches.
Still not quite right. This script at http://mikebabcock.ca/code/registrydict.py also needs a wee fix (I've emailed the author about it):
Line26: def __getitem__(self, item):
should be (I think):
def __getitem__(self, key)
Now, I wish someone could show me how it works!
-ross
Save unicode as REG_SZ. May be worth putting
</pre>
__delitem__ rewrite. I've rewritten __delitem__ as it just plain didn't work...
It's got slightly different behaviour: the old version looked like it was attempting to silently fail if you deleted a key that didn't exist.
This version will raise a keyerror, which is more consistent with the behaviour of standard dictionaries, i.e.
Will raise a keyerror, not fail silently.
Updated my hosted copy. http://mikebabcock.ca/code/registrydict.py has been updated appropriately as per the updates above.
doesnt work. I try to run this script with no success. Is this right?: Should be printed subkeys this way? Neither of these is working :-(
Moreover, here: http://mikebabcock.ca/code/registrydict.py is just part of updated script, so I am not sure, if I collect the right script of last version.
Thank you very much
Updated version available in a new recipe. I've just submitted a new recipe, number 551761, with all the corrections applied; it's awaiting approval.
what will this call return, if the keyPath in the below method call doesnt exist, then what would be return value of function call? rd = RegistryDict(win32con.HKEY_LOCAL_MACHINE, KeyPath)
so basically i first want to find if key path exists. if yes, then want to find the value of some key at this key path.
thanks, Rahul