[I'm having mail troubles so my response time may be slow...] I've just had a chance to look at the winreg module. I think that it is too low-level. I wrote a wrapper class that I feel is more Pythonic. I'll outline the basic ideas and then if there is interest I'll develop a test suite and send it out for eyeballing by Mark and others. Yes, I am proposing this for 1.6. If we're going to put in a registry module, it should be as Pythonic as possible. First, about Winreg 1: It was perfect when it was part of the win32 package and was supposed to mirror the win32 APIs exactly (for reasons of documentation and familiarity) but as the "standard" Python registry manipulation module it seems too low-level to me. I'm sure Mark would be the first to admit that it isn't very Pythonic. It's more Microsoft-ic. In one part of the docs he says: "this API is lame, lame, lame. Don't use it." :) There are also bogus parameters that Microsoft hasn't got around to assigning values to, undocumented constants and so forth. My favorite is "WHOLE_HIVE_VOLATILE". Winreg 2: The basic idea in the pythonic wrapper is that there are key "objects" rather than just handles. winreg already has a primtive "handle object" but for some reason most of the stuff that would logically be methods are actually functions that take the handle as the first param. Keys can have subkeys. So in winreg 1 you would say: winreg.CreateKey( winreg.CreateKey( winreg.HKEY_LOCAL_MACHINE, "HARDWARE"), "DESCRIPTION" ) now you say: winreg.HKEY_LOCAL_MACHINE.createKey( "HARDWARE").createKey( "DESCRIPTION" ) (you could also use a path syntax in either case) You can get a complete list of existant subkeys with a getSubkeys() method call. This list behaves like a Python mapping and also like a sequence. You can use either string key names or integer ordinal indexes. You can fetch and delete keys based on those indexes: for key in winreg.HKEY_LOCAL_MACHINE.getSubkeys(): dosomething( key ) Before it was something like this: for index in xrange( 0, sys.maxint ): try: dosomething( winreg.EnumKey( index ) ) except WindowsError: break "Values" (in the Microsoft sense) are handled the same basic way. Looping, deleting, etc. is the same. When you fetch a value, you get a (type,value) tuple. Types are objects with properties: typeobj.intval -> 0..10 typeobj.msname -> REG_SZ, REG_SZ_MULTI, ... typeobj.friendlyname -> "String", "Sting List", ... Type coercions are all done by the underlying module (the old winreg) except that I've decided that binary data should be returned as an array.array('c') rather than an 8-bit string. -- Paul Prescod Out of timber so crooked as that which man is made nothing entirely straight can be built. - Immanuel Kant
I've just had a chance to look at the winreg module. I think that it is too low-level.
I agree. There was a proposal (from Thomas Heller, IIRC) to do just this. I successfully argued there should be _2_ modules for Python - the raw low-level API, which guarantees you can do (almost) anything. A higher-level API could cover the 80% of cases. It is probably worth getting in touch with Thomas - he may be able to dig up his proposed high-level API. Ive CCd him on this message [I hope is _was_ you Thomas - otherwise you will be wondering WTF I am on about :] I was very keen to ensure the win32api code was used as the low-level API, simply because it has been well tested and used. We _know_ it has no significant limitations. Im happy to support a high-level API, but didnt have the inclination to provide one. Every one I have seen and every one I have tried to design has started to fall-apart under real-world use - Ive needed to revert back to the low-level.
There are also bogus parameters that Microsoft hasn't got around to assigning values to, undocumented constants and so forth. My favorite is "WHOLE_HIVE_VOLATILE".
This is exactly my concern with a high-level API - you cant hope to capture all this - especially the undocumented ones - so having a low-level API means you can do anything, even stuff never dreamt of by the high-level designer. I have no real problem with your proposed design, as long as it it written in Python, _using_ the low-level API. It could be called "registry" or I would even be happy for "winreg.pyd" -> "_winreg.pyd" and your new module to be called "winreg.py" Mark.
Mark wrote: [Paul]
I've just had a chance to look at the winreg module. I think that it is too low-level.
I agree. There was a proposal (from Thomas Heller, IIRC) to do just this. I successfully argued there should be _2_ modules for Python - the raw low-level API, which guarantees you can do (almost) anything. A higher-level API could cover the 80% of cases. It is probably worth getting in touch with Thomas - he may be able to dig up his proposed high-level API.
Found it. ------- Forwarded message follows ------- From: "Thomas Heller" <thomas.heller@ion- tof.com> To: <python-dev@python.org>, <distutil- sig@python.org> Date sent: Thu, 3 Feb 2000 14:27:00 +0100 Subject: [Python-Dev] Revised proposal (and preliminary implementation): Registry access module for Python on Windows Ok, at least the first proposal did start the discussion. Here is a revised one: A preliminary implementation is available at http://starship.python.net/crew/theller/ ----------------------------------------------------------------- ----- winreg - windows registry access module Exception: error - raised when a function fails. Will contain a windows error code and a textual description. Objects: regnode object - represents a open key in the registry. Functions: OpenKey (name) -> regnode object Opens an existing key with the specified access rights and returns a regnode object. name is specified like "HKLM\Software\Python" or "HKEY_LOCAL_MACHINE\Software\Python" CreateKey (name) -> regnode object Creates a new key or opens an existing one and returns a regnode object. For the name format see OpenKey regnode object methods: Values () -> dict Returns a dictionary mapping names to values. The <default> or unnamed value has the key ''. The values are either strings or integers, depending on the REG_* type. GetValue ([name]) -> integer or string Returns a value specified by name or the default value. SetValue ([name,] value) Set a named or the <default> value. Named values must be integers or string (which are stored as REG_DWORD or REG_SZ). Should an optional third parameter be used, allowing to store in other REG_* typecodes? I dont think so. DeleteValue ([name]) Deletes a named or the <default> value. SubKeys () -> sequence Returns a sequence containing the names of all subkeys. DeleteKey (name [,recursive=0]) If recursive is 0, deletes the named key if no subkeys exist. If there are subkeys an error is raised. If recursive is not 0, the named key is deleted including subkeys. OpenKey (name) -> regnode object Openes an existing subkey and returns a regnode object pointing to it. CreateKey (name) -> regnode object Creates a new or openes an existing subkey and returns a regnode object pointing to it. regnode objects have the following properties: name - the name of the RegistryKey, something like "HKLM\Software\Python" hkey - the integer keyhandle ----------------------------------------------------------------- ----- Thomas Heller _______________________________________________ Python-Dev maillist - Python-Dev@python.org http://www.python.org/mailman/listinfo/python-dev ------- End of forwarded message ------- - Gordon
I've just had a chance to look at the winreg module. I think that it is too low-level.
I agree. There was a proposal (from Thomas Heller, IIRC) to do just this. I successfully argued there should be _2_ modules for Python - the raw low-level API, which guarantees you can do (almost) anything. A higher-level API could cover the 80% of cases. It is probably worth getting in touch with Thomas - he may be able to dig up his proposed high-level API. Ive CCd him on this message [I hope is _was_ you Thomas - otherwise you will be wondering WTF I am on about :] Yes, it was me :-)
Here is the 3. (final?) proposal, earlier ones are in the archives: http://www.python.org/pipermail/python-dev/2000-February/003417.html and http://www.python.org/pipermail/python-dev/2000-February/003472.html ---------------------------------------------------------------------- winreg - windows registry access module Exception: error - raised when a function fails. Will contain a windows error code and a textual description. Objects: regkey object - represents a open key in the registry. Functions: OpenKey (name) -> regkey object Opens an existing key with the specified access rights and returns a regkey object. name is specified like "HKLM\Software\Python" or "HKEY_LOCAL_MACHINE\Software\Python" CreateKey (name) -> regkey object Creates a new key or opens an existing one and returns a regkey object. For the name format see OpenKey regkey object methods: Standard Mapping protocol: len (r) r[k] r[k] = x del r[k] r.clear() r.has_key(k) r.items() r.keys() r.update(dict) r.values() r.get(k[, x]) todict() -> dictionary Returns a dictionary mapping value names to values. SubKeys () -> sequence Returns a sequence containing the names of all subkeys. DeleteKey (name [,recursive=0]) If recursive is 0, deletes the named key if no subkeys exist. If there are subkeys an error is raised. If recursive is not 0, the named key is deleted including subkeys. OpenKey (name) -> regkey object Openes an existing subkey and returns a regkey object pointing to it. CreateKey (name) -> regkey object Creates a new or openes an existing subkey and returns a regkey object pointing to it. regkey objects have the following properties: name - the name of the RegistryKey, something like "HKLM\Software\Python" hkey - the integer keyhandle ---------------------------------------------------------------------- It would not be too much work to implement it, but I will be away the next 20 days...
I have no real problem with your proposed design, as long as it it written in Python, _using_ the low-level API. It could be called "registry" or I would even be happy for "winreg.pyd" -> "_winreg.pyd" and your new module to be called "winreg.py"
If we change the name of the low level api module, we have to change Distutils, because it is used there. Maybe we would better use the high level api then, but there is still this 1.5 compatibility using the win32api module. Thomas
Mark, Thomas and whoever, thanks for your input and I hope you can spare some more... Thomas Heller wrote:
This is similar to what I have implemented...
---------------------------------------------------------------------- winreg - windows registry access module
Exception: error - raised when a function fails. Will contain a windows error code and a textual description.
As an aside, I notice that the winreg documentation says it will raise an EnvironmentError but it actually raises a WindowsError.
Objects: regkey object - represents a open key in the registry.
Right. Even the same name. My stance was that keys would always be created from keys, so you would start with HKEY_LOCAL_MACHINE.CreateKey("Software\Python") That mirrors the underlying API a little closer and reduces the number of functions to 0. The question is whether the CreateKey and OpenKey functions are important enough as "convenience functions".
regkey object methods: Standard Mapping protocol: len (r) r[k] r[k] = x del r[k] r.clear() r.has_key(k) r.items() r.keys() r.update(dict) r.values() r.get(k[, x])
I had a separate object for values. I couldn't really justify elevating either the Subkeys or the Values. I tried to treat them as alike as possible.
todict() -> dictionary Returns a dictionary mapping value names to values.
I called this getValues() and it returned an object that was both a mapping and a sequence and allowed read/write/delete of values.
SubKeys () -> sequence Returns a sequence containing the names of all subkeys.
DeleteKey (name [,recursive=0]) If recursive is 0, deletes the named key if no subkeys exist. If there are subkeys an error is raised. If recursive is not 0, the named key is deleted including subkeys.
I may or may not get around to implementing the recursive version. You have to be VERY CAREFUL when you test such a thing. :)
OpenKey (name) -> regkey object Openes an existing subkey and returns a regkey object pointing to it.
Okay.
CreateKey (name) -> regkey object Creates a new or openes an existing subkey and returns a regkey object pointing to it.
Okay.
regkey objects have the following properties: name - the name of the RegistryKey, something like "HKLM\Software\Python"
Okay.
hkey - the integer keyhandle
Is this really useful? Better to use the low-level API in that case...
If we change the name of the low level api module, we have to change Distutils, because it is used there. Maybe we would better use the high level api then, but there is still this 1.5 compatibility using the win32api module.
The high level could probably be made compatible with 1.5 like this: try: import _winreg except ImportError: import win32api winreg=win32api It would probably be good for DistUtils to use the high level API as soon as it is possible for testing purposes. I am considering doing away with the two enumeration interfaces. The cost/benefit of having two more objects is probably low. We can simplify the whole thing by just using methods on the regkey object: deleteValue(name) getValue(name)-> (type, value) setValue(name,(type,value)) getValueNames() -> List of strings getSubkey(name) -> regkey deleteSubkey(name) getSubkeyNames( ) -> List of strings Iterating will be slightly less efficient because it will loop twice, once to gather the names and once to do whatever you need to do but that's not the typical registry use case anyhow. Anyone who needs absolute performance can use the low-level API. Recursive iteration under the existing model: def doit( key ): for subkey in key.getSubkeyNames(): doit( subkey ) Recursive iteration under the proposed model: def doit( key ): for keyname in key.getSubkeyNames(): doit( key.getSubkey( name )) -- Paul Prescod - Not encumbered by corporate consensus When George Bush entered office, a Washington Post-ABC News poll found that 62 percent of Americans "would be willing to give up a few of the freedoms we have" for the war effort. They have gotten their wish. - "This is your bill of rights...on drugs", Harpers, Dec. 1999
(Hopefully it is ok to use the reply-all button)
... My stance was that keys would always be created from keys, so you would start with
HKEY_LOCAL_MACHINE.CreateKey("Software\Python")
That mirrors the underlying API a little closer and reduces the number of functions to 0. Good idea! Maybe HKLM and so on should be provided as aliases.
DeleteKey (name [,recursive=0]) If recursive is 0, deletes the named key if no subkeys exist. If there are subkeys an error is raised. If recursive is not 0, the named key is deleted including subkeys.
I may or may not get around to implementing the recursive version. You have to be VERY CAREFUL when you test such a thing. :) Someone (I don't remember who) mentioned in the discussion about my proposal that one should use SHDeleteKey for recursive deletion of keys. See the MSDN docs on RegDeleteKey for details. Don't know if this is exposed by the lowlevel module.
If we change the name of the low level api module, we have to change Distutils, because it is used there. Maybe we would better use the high level api
then,
but there is still this 1.5 compatibility using the win32api module.
The high level could probably be made compatible with 1.5 like this:
try: import _winreg except ImportError: import win32api winreg=win32api Currently it goes like this, because win32api and winreg (which will soon be _winreg) have slightly different apis, but it will doubtlessly be solved:
try: import winreg _can_read_reg = 1 hkey_mod = winreg RegOpenKeyEx = winreg.OpenKeyEx RegEnumKey = winreg.EnumKey RegEnumValue = winreg.EnumValue RegError = winreg.error except ImportError: try: import win32api import win32con _can_read_reg = 1 hkey_mod = win32con RegOpenKeyEx = win32api.RegOpenKeyEx RegEnumKey = win32api.RegEnumKey RegEnumValue = win32api.RegEnumValue RegError = win32api.error except ImportError: pass Thomas
Right now the Python list is a little slow (at least for me) so I appreciate cc:s directly to me. Thomas Heller wrote:
Good idea! Maybe HKLM and so on should be provided as aliases.
Sure.
Someone (I don't remember who) mentioned in the discussion about my proposal that one should use SHDeleteKey for recursive deletion of keys. See the MSDN docs on RegDeleteKey for details. Don't know if this is exposed by the lowlevel module.
Don't think so.
Currently it goes like this, because win32api and winreg (which will soon be _winreg) have slightly different apis, but it will doubtlessly be solved:
Ouch. I don't know if I have time to figure out all of the correspondances. Are the only differences those four method names or are those the only four differences that DistUtils happened to care about. I'm not interested in 1.5 compatibility if it will take a lot of work. -- Paul Prescod - Not encumbered by corporate consensus When George Bush entered office, a Washington Post-ABC News poll found that 62 percent of Americans "would be willing to give up a few of the freedoms we have" for the war effort. They have gotten their wish. - "This is your bill of rights...on drugs", Harpers, Dec. 1999
Right now the Python list is a little slow (at least for me) so I appreciate cc:s directly to me. Same for me: All python lists take hours to distribute the mails.
Someone (I don't remember who) mentioned in the discussion about my proposal that one should use SHDeleteKey for recursive deletion of keys. See the MSDN docs on RegDeleteKey for details. Don't know if this is exposed by the lowlevel module.
Don't think so. The tricky thing is: Deletion of keys behaves differently on Win95/98 and NT/2000. (Quoting MSDN:) The RegDeleteKey function deletes a subkey.
Windows 95/98: The function also deletes all subkeys and values. To delete a key only if the key has no subkeys or values, use the SHDeleteEmptyKey function. Windows NT/2000: The subkey to be deleted must not have subkeys. To delete a key and all its subkeys, you need to recursively enumerate the subkeys and delete them individually. To recursively delete keys, use the SHDeleteKey function. (end quote) The SHDelete* funtions require version 4.71 of shlwapi.dll, which is included in Win98 or 2000 (or in IE 4.0).
Currently it goes like this, because win32api and winreg (which will soon be _winreg) have slightly different apis, but it will doubtlessly be solved:
Ouch. I don't know if I have time to figure out all of the correspondances. Are the only differences those four method names or are those the only four differences that DistUtils happened to care about. I'm not interested in 1.5 compatibility if it will take a lot of work.
So you should simply ignore this. We will work it out on distutils. Thomas (I will disappear soon for holidays)
I'm trying to figure out all of the constants in _winreg. Some of them seem related to functions that _winreg doesn't support. I won't put those in new winreg because they can't be used. The only one I can't figure out through web searches is REG_OPTION_OPEN_LINK. RegNotifyChangeKeyValue (unsupported) REG_NOTIFY_CHANGE_NAME REG_NOTIFY_CHANGE_LAST_SET REG_NOTIFY_CHANGE_SECURITY REG_NOTIFY_CHANGE_ATTRIBUTES RegRestoreKey (unsupported) REG_FORCE_RESTORE REG_NO_LAZY_FLUSH REG_REFRESH_HIVE REG_WHOLE_HIVE_VOLATILE RegCreateKeyEx (unxupported) REG_OPTION_RESERVED REG_OPTION_VOLATILE REG_OPTION_NON_VOLATILE REG_OPTION_BACKUP_RESTORE REG_CREATED_NEW_KEY REG_OPENED_EXISTING_KEY REG_OPTION_CREATE_LINK I presume that nobody intends to add these three functions to _winreg in time for Python 1.6! -- Paul Prescod - Not encumbered by corporate consensus When George Bush entered office, a Washington Post-ABC News poll found that 62 percent of Americans "would be willing to give up a few of the freedoms we have" for the war effort. They have gotten their wish. - "This is your bill of rights...on drugs", Harpers, Dec. 1999
There are a few features missing from the proposed API. I don't think that this API should serve the 80%, but rather the 97%. The only things I plan to exclude from the low level API are things that are undocumented and a little bit of performance. I see no reason not to add support for close, flush, save, remote keys and REG_FOO types. If I ever figure out how to use HIVE_VOLATILE_IS_TRUE I would add support for that too. :) -- Paul Prescod - Not encumbered by corporate consensus When George Bush entered office, a Washington Post-ABC News poll found that 62 percent of Americans "would be willing to give up a few of the freedoms we have" for the war effort. They have gotten their wish. - "This is your bill of rights...on drugs", Harpers, Dec. 1999
There are a few features missing from the proposed API. I don't think that this API should serve the 80%, but rather the 97%. The only things I plan to exclude from the low level API are things that are undocumented and a little bit of performance. I want to simplify the API, not dumb it down. I see no reason not to add support for close, flush, save, remote keys and REG_FOO types. If I ever figure out how to use HIVE_VOLATILE_IS_TRUE I would add support for that too. :) -- Paul Prescod - Not encumbered by corporate consensus When George Bush entered office, a Washington Post-ABC News poll found that 62 percent of Americans "would be willing to give up a few of the freedoms we have" for the war effort. They have gotten their wish. - "This is your bill of rights...on drugs", Harpers, Dec. 1999
participants (4)
-
Gordon McMillan
-
Mark Hammond
-
Paul Prescod
-
Thomas Heller