----- Original Message -----
> From: eryksun <eryk...@gmail.com>
> To: Albert-Jan Roskam <fo...@yahoo.com>
> Cc: Dave Angel <da...@davea.name>; "tutor@python.org" <tutor@python.org>
> Sent: Thursday, May 30, 2013 10:05 PM
> Subject: Re: [Tutor] walk registry using _winreg
> 
> On Thu, May 30, 2013 at 10:47 AM, Albert-Jan Roskam <fo...@yahoo.com> 
> wrote:
>> 
>> def walkRegistry(regkey, keyToSet="file_locations",
>>                   valueToSet="temp_dir",
>>                   HKEY=_winreg.HKEY_CURRENT_USER, verbose=False):
> 
> I suppose you don't need the "sam" option in your case, but in 
> general
> it's needed for 64-bit Windows in order to handle both native and
> WOW64 keys.
> 
> For a WOW64 process, the native 64-bit keys can be read with
> sam=KEY_READ | KEY_WOW64_64KEY. For a 64-bit process, the WOW64 keys
> can be read with sam=KEY_READ | KEY_WOW64_32KEY.
> 
> A WOW64 process will have "PROCESSOR_ARCHITEW6432" defined in 
> os.environ.
 

That's entirely new to me.So every 64-bit windows registry comes in a WOW64 and 
a native flavour? If one native registry is already a mess, does two registries 
mean double mess? I will have to read up on this, although I have to admit that 
the windows registry is not my favourite topic. The walk function might also 
come in really handy with searching in virtual registries that Symantec virtual 
software layer creates (talking about mess! Yikes!)

 
>>     aReg = _winreg.OpenKey(HKEY, regkey)
> 
> You should use a "with" statement here instead of depending on the
> garbage collection of the generator frame.


Thank you. Yes, I was staring at the code and this crossed my mind. I found my 
code too nested (which I considered to be a bad sign) and I didn't use a 'with' 
statement because it would add yet another nesting level. 

 
>>     try:
>>         while True:
>>             key = _winreg.EnumKey(aReg, i)
>>             i += 1
>>             if key:
>>                 new_regkey = os.path.join(regkey, key)
> 
> There's too much code here under the banner of one "try" suite.
> OpenKey and QueryValueEx in the subsequent statements may raise a
> WindowsError for various reasons.
> 
> Also, as you're currently doing things it leaves several open handles
> as you recursively create generators. It's likely not an issue (the
> registry isn't deeply nested), but in general I prefer to close a
> resource as immediately as is possible.
> 
> I'd enumerate the subkeys in a list and only yield a key/value match
> for the current regkey (that's basically how os.walk traverses the
> file system). This can match on the initial key. If you don't want
> that, it can be worked around (e.g. a flag, or a helper function), but
> I don't think the additional complexity is worth it.
> 
>     import os
>     import _winreg
> 
>     def walkRegistry(regkey,
>                     keyToSet="file_locations",
>                     valueToSet="temp_dir",
>                     HKEY=_winreg.HKEY_CURRENT_USER,
>                     sam=_winreg.KEY_READ,
>                     onerror=None,


The onerror parameter is nice (just like in os.walk). Cool way to handle errors.


>                     verbose=False):
> 
>         try:
>             aReg = _winreg.OpenKey(HKEY, regkey)
>         except WindowsError as e:
>             if onerror is not None:
>                 onerror(e)
>             return
> 
>         i = 0
>         subkeys = []
>         with aReg:


I always forget that "with" statements also work without using "as" (ie, with 
_winreg.OpenKey(HKEY, regkey) as aReg).

Another remark that happens to be also about "as": is "except WindowsError as 
e:" a more modern version of "except WindowsError, e:"? Comparable to the 
old-fashioned "raise SomeError, 'error'"  and the new "raise 
SomeError('error')".  
. 

>             while True:
>                 try:
>                     subkeys.append(_winreg.EnumKey(aReg, i))
>                 except WindowsError:
>                     break
>                 i += 1
>             # check the key name; not the key path
>             if os.path.basename(regkey) == keyToSet:
>                 if verbose:
>                     print "---> FOUND KEY:", regkey
>                 try:
>                     data = _winreg.QueryValueEx(aReg, valueToSet)[0]
>                 except WindowsError:  # value not found
>                     pass
>                 else:


Thanks for reminding me of the "else" clause in the try-except suite. I knew it 
existed, but I never use it. For others who are reading along, the links below 
are useful. Basically, it boils down to: (1) keep the "try" clause as empty as 
possible (2) the "else" clause is there to prevent you from catching the same 
type of exception, but with a different cause.
http://stackoverflow.com/questions/855759/python-try-else
http://docs.python.org/2/tutorial/errors.html: "The use of the else clause is 
better than adding additional code to the try clause because it avoids 
accidentally catching an exception that wasn’t raised by the code being 
protected by the try ... except statement"

 
>                     if verbose:
>                         print "---> FOUND KEY,VALUE PAIR"
>                     yield regkey, valueToSet, data
> 
>         for key in subkeys:
>             new_regkey = os.path.join(regkey, key)
>             for item in walkRegistry(
>                     new_regkey, keyToSet, valueToSet,
>                     HKEY, sam, onerror, verbose):
>                 yield item
> 
> 
> Minimally tested (sorry):


You all have been of enormous help, thank you!! Code reviews are a great way to 
find errors, make code more readable, make code more efficient (in that order) 
and learn new tricks
I wrote a simple doctest for the code. Perhaps I should post this somewhere.
    r"""
    >>> regkey = u"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer"
    >>> args = regkey, u"Shell Folders", u"Cookies"
    >>> regdata = [(key, val, data) for key, val, data in walkRegistry(*args)]
    >>> print regdata  # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE
    [(u'Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders',
    u'Cookies', u'...\\Microsoft\\Windows\\Cookies')]
    """
....
if __name__ == "__main__":
    import doctest
    doctest.testmod()
    regkey = u"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer"
    args = regkey, u"Shell Folders", u"Cookies"
    regdata = [(key, val, data) for key, val, data in walkRegistry(*args)]
    print regdata


> 
>     >>> HKEY = _winreg.HKEY_LOCAL_MACHINE
>     >>> regkey = r'Software\Python\PythonCore\2.7'
> 
>     >>> res = list(
>     ... walkRegistry(regkey, 'PythonPath', '', HKEY, 
> verbose=True))
> 
>     ---> FOUND KEY: Software\Python\PythonCore\2.7\PythonPath
>     ---> FOUND KEY,VALUE PAIR
> 
>     >>> res[0][2]
>     
> u'C:\\Python27\\Lib;C:\\Python27\\DLLs;C:\\Python27\\Lib\\lib-tk'
> 
_______________________________________________
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor

Reply via email to