[Python-Dev] Winreg update

Paul Prescod paul@prescod.net
2000年8月11日 08:25:27 -0500


I am in transit so I don't have time for a lot of back and forth email
relating to winreg. It also seems that there are a lot of people (let's
call them "back seat coders") who have vague ideas of what they want but
don't want to spend a bunch of time in a long discussion about registry
arcana. Therefore I am endevouring to make it as easy and fast to
contribute to the discussion as possible. 
I'm doing this through a Python Module Proposal format. This can also
serve as the basis of documentation.
This is really easy so I want
some real feedback this time. Distutils people, this means you! Mark! I
would love to hear Bill Tutt, Greg Stein and anyone else who claims some
knowledge of Windows!
If you're one of the people who has asked for winreg in the core then
you should respond. It isn't (IMO) sufficient to put in a hacky API to
make your life easier. You need to give something to get something. You
want windows registry support in the core -- fine, let's do it properly.
Even people with a minimal understanding of the registry should be able
to contribute: the registry isn't rocket surgery. I'll include a short
primer in this email.
All you need to do is read this email and comment on whether you agree
with the overall principle and then give your opinion on fifteen
possibly controversial issues. The "overall principle" is to steal
shamelessly from Microsoft's new C#/VB/OLE/Active-X/CRL API instead of
innovating for Python. That allows us to avoid starting the debate from
scratch. It also eliminates the feature that Mark complained about
(which was a Python-specific innovation).
The fifteen issues are mostly extensions to the API to make it easier
(convenience extensions) or more powerful (completeness extensions).
Many of them are binary: "do this, don't do that." Others are choices:
e.g. "Use tuples", "Use lists", "Use an instance".
I will try to make sense of the various responses. Some issues will have
strong consensus and I'll close those quickly. Others will require more
(hopefully not much!) discussion.
Windows Registry Primer:
========================
There are things called "keys". They aren't like Python keys so don't
think of them that way. Keys have a list of subkeys indexed by name.
Keys also have a list of "values". Values have names. Every value has a
type. In some type-definition syntax:
key is (name: string, 
 subkeys: (string : key), 
 values: (string : value ))
value is ( name: string,
 type: enumeration,
 data: (depends on enumeration) )
That's the basic model. There are various helper facilities provided by
the APIs, but really, the model is as above.
=========================================================================
Python Module Proposal
Title: Windows registry
Version: $Revision: 1.0$
Owner: paul@prescod.net (Paul Prescod)
Python-Version: 2.0
Status: Incomplete
Overview
 It is convenient for Windows users to know that a Python module to
 access the registry is always available whenever Python is installed
 on Windows. This is especially useful for installation programs.
 There is a Windows registry module from the win32 extensions to
 Python. It is based directly on the original Microsoft APIs. This
 means that there are many backwards compatibility hacks, "reserved"
 parameters and other legacy features that are not interesting to
 most Python programmers. Microsoft is moving to a higher level API
 for languages other than C, as part of Microsoft's Common Runtime
 Library (CRL) initiative. This newer, higher level API serves as
 the basis for the module described herein.
 This higher level API would be implemented in Python and based upon 
 the low-level API. They would not be in competition: a user would 
 choose based on their preferences and needs.
Module Exports
 These are taken directly from the Common Runtime Library:
 ClassesRoot The Windows Registry base key HKEY_CLASSES_ROOT.
 CurrentConfig The Windows Registry base key HKEY_CURRENT_CONFIG.
 CurrentUser The Windows Registry base key HKEY_CURRENT_USER.
 LocalMachine The Windows Registry base key HKEY_LOCAL_MACHINE.
 CurrentUser The Windows Registry base key HKEY_CURRENT_USER.
 DynData The Windows Registry base key HKEY_DYN_DATA.
 PerformanceData The Windows Registry base key HKEY_PERFORMANCE_DATA.
 Users The Windows Registry base key HKEY_USERS.
 RegistryKey Registry key class (important class in module)
RegistryKey class Data Members
 These are taken directly from the Common Runtime Library:
 Name Retrieves the name of the key. 
 [Issue: full path or just name within parent?]
 SubKeyCount Retrieves the count of subkeys.
 ValueCount Retrieves the count of values in the key.
RegistryKey Methods
 These are taken directly from the Common Runtime Library:
 Close()
 Closes this key and flushes it to disk if the contents have 
 been modified.
 CreateSubKey( subkeyname )
 Creates a new subkey or opens an existing subkey.
 [Issue: SubKey_full_path]: Should it be possible to create a subkey 
 deeply:
 >>> LocalMachine.CreateSubKey( r"foo\bar\baz" )
 Presumably the result of this issue would also apply to every
 other method that takes a subkey parameter.
 It is not clear what the CRL API says yet (Mark?). If it says
 "yes" then we would follow it of course. If it says "no" then
 we could still consider the feature as an extension.
 [Yes] allow subkey parameters to be full paths
 [No] require them to be a single alphanumeric name, no slashes
 DeleteSubKey( subkeyname )
 Deletes the specified subkey. To delete subkeys and all their 
 children (recursively), use DeleteSubKeyTree.
 DeleteSubKeyTree( subkeyname )
 Recursively deletes a subkey and any child subkeys. 
 DeleteValue( valuename )
 Deletes the specified value from this key.
 __cmp__( other )
	Determines whether the specified key is the same key as the
	current key.
 GetSubKeyNames()
 Retrieves an array of strings containing all the subkey names.
 GetValue( valuename )
 Retrieves the specified value.
 Registry types are converted according to the following table:
 REG_NONE: None
 REG_SZ: UnicodeType
 REG_MULTI_SZ: [UnicodeType, UnicodeType, ...]
 REG_DWORD: IntegerType
 REG_DWORD_LITTLE_ENDIAN: IntegerType
 REG_DWORD_BIG_ENDIAN: IntegerType
 REG_EXPAND_SZ: Same as REG_SZ
 REG_RESOURCE_LIST: Same as REG_BINARY
 REG_FULL_RESOURCE_DESCRIPTOR: Same as REG_BINARY
 REG_RESOURCE_REQUIREMENTS_LIST: Same as REG_BINARY
 REG_LINK: Same as REG_BINARY??? [Issue: more info needed!]
 REG_BINARY: StringType or array.array( 'c' )
 [Issue: REG_BINARY Representation]:
 How should binary data be represented as Python data?
 [String] The win32 module uses "string".
 [Array] I propose that an array of bytes would be better.
 One benefit of "binary" is that allows SetValue to detect
 string data as REG_SZ and array.array('c') as REG_BINARY
 [Issue: Type getting method]
 Should there be a companion method called GetType that fetches 
 the type of a registry value? Otherwise client code would not
 be able to distinguish between (e.g.) REG_SZ and 
 REG_SZ_BINARY.
 [Yes] Add GetType( string )
 [No] Do not add GetType
 GetValueNames()
 Retrieves a list of strings containing all the value names.
 OpenRemoteBaseKey( machinename, name )
 Opens a new RegistryKey that represents the requested key on a 
 foreign machine.
 OpenSubKey( subkeyname )
 Retrieves a subkey.
 SetValue( keyname, value )
 Sets the specified value
	Types are automatically mapped according to the following
	algorithm:
 None: REG_NONE
 String: REG_SZ
 UnicodeType: REG_SZ
 [UnicodeType, UnicodeType, ...]: REG_MULTI_SZ
 [StringType, StringType, ...]: REG_MULTI_SZ
 IntegerType: REG_DWORD
 array.array('c'): REG_BINARY
 [Issue: OptionalTypeParameter]
 Should there be an optional parameter that allows you to
 specify the type explicitly? Presume that the types are 
 constants in the winreg modules (perhaps strings or 
 integers).
 [Yes] Allow other types to be specified
 [No] People who want more control should use the underlying 
 win32 module.
Proposed Extensions
 The API above is a direct transliteration of the .NET API. It is
 somewhat underpowered in some senses and also is not entirely
 Pythonic. It is a good start as a basis for consensus, however,
 and these proposed extensions can be voted up or down individually.
 Two extensions are just the convenience functions (OpenRemoteKey
 and the top-level functions). Other extensions attempt to extend
 the API to support ALL features of the underlying API so that users
 never have to switch from one API to another to get a particular
 feature.
 Convenience Extension: OpenRemoteKey
 It is not clear to me why Microsoft restricts remote key opening
 to base keys. Why does it not allow a full path like this:
 >>> winreg.OpenRemoteKey( "machinename", 
 r"HKEY_LOCAL_MACHINE\SOFTWARE\Python" )
 [Issue: Add_OpenRemoteKey]: 
 [Yes] add RemoteKey 
 [No] do not add?
 [Issue: Remove_OpenRemoteBaseKey]
 [Remove] It's redundant!
 [Retain] For backwards compatibility
 Convenience Extension: Top-level Functions
 A huge number of registry-manipulating programs treat the
 registry namespace as "flat" and go directly to the interesting
 registry key. These top-level functions allow the Python user
 to skip all of the OO key object and get directly to what
 they want:
 key=OpenKey( keypath, machinename=None )
 key=CreateKey( keypath, machinename=None )
 DeleteKey( keypath, machinename=None )
 val=GetValue( keypath, valname, machinename=None )
 SetValue( keypath, valname, valdata, machinename=None )
 [Yes] Add these functions
 [No] Do not add
 [Variant] I like the idea but would change the function
 signatures
 Completeness Extension: Type names
 If the type extensions are added to SetValue and GetValue then
 we need to decide how to represent types. It is fairly clear
 that they should be represented as constants in the module. The
 names of those constants could be the cryptic (but standard)
 Microsoft names or more descriptive, conventional names.
	Microsoft Names:
 REG_NONE
 REG_SZ
 REG_EXPAND_SZ
 REG_BINARY
 REG_DWORD
 REG_DWORD_LITTLE_ENDIAN
 REG_DWORD_BIG_ENDIAN
 REG_LINK
 REG_MULTI_SZ
 REG_RESOURCE_LIST
 REG_FULL_RESOURCE_DESCRIPTOR
 REG_RESOURCE_REQUIREMENTS_LIST
	Proposed Descriptive Names:
 NONE
 STRING
 EXPANDABLE_TEMPLATE_STRING
 BINARY_DATA
 INTEGER
 LITTLE_ENDIAN_INTEGER
 BIG_ENDIAN_INTEGER
 LINK
 STRING_LIST
 RESOURCE_LIST
 FULL_RESOURCE_DESCRIPTOR
 RESOURCE_REQUIREMENTS_LIST
 
 We could also allow both. One set would be aliases for the
 other.
 [Issue: TypeNames]:
 [MS Names]: Use the Microsoft names
 [Descriptive Names]: Use the more descriptive names
 [Both]: Use both
 Completeness Extension: Type representation
 No matter what the types are called, they must have values.
	The simplest thing would be to use the integers provided by the
	Microsoft header files. Unfortunately integers are not at all
	self-describing so getting from the integer value to something
	human readable requires some sort of switch statement or mapping.
 
 An alternative is to use strings and map them internally to the 
 Microsoft integer constants.
 A third option is to use object instances. These instances would
 be useful for introspection and would have the following 
 attributes:
 msname (e.g. REG_SZ)
 friendlyname (e.g. String)
 msinteger (e.g. 6 )
 They would have only the following method:
 def __repr__( self ):
 "Return a useful representation of the type object"
 return "<RegType %d: %s %s>" % \
 (self.msinteger, self.msname, self.friendlyname )
 A final option is a tuple with the three attributes described
 above.
 [Issue: Type_Representation]:
 [Integers]: Use Microsoft integers
 [Strings]: Use string names
 [Instances]: Use object instances with three introspective 
 attributes
 [Tuples]: Use 3-tuples
 Completeness Extension: Type Namespace
 Should the types be declared in the top level of the module 
 (and thus show up in a "dir" or "from winreg import *") or 
 should they live in their own dictionary, perhaps called 
 "types" or "regtypes". They could also be attributes of some 
 instance.
 [Issue: Type_Namespace]:
 [Module]: winreg.REG_SZ
 [Dictionary]: winreg.types["REG_SZ"]
 [Instance]: winreg.types["REG_SZ"]
 Completeness Extension: Saving/Loading Keys
 The underlying win32 registry API allows the loading and saving
 of keys to filenames. Therefore these could be implemented
 easily as methods:
 def save( self, filename ):
 "Save a key to a filename"
 _winreg.SaveKey( self.keyobj, filename )
 def load( self, subkey, filename ):
 "Load a key from a filename"
 return _winreg.RegLoadKey( self.handle, subkey, 
 filename )
 >>> key.OpenSubKey("Python").save( "Python.reg" )
 >>> key.load( "Python", "Python.reg" )
 [Issue: Save_Load_Keys]
 [Yes] Support the saving and loading of keys
 [No] Do not add these methods
 Completeness Extension: Security Access Flags
 The underlying win32 registry API allows security flags to be
 applied to the OpenKey method. The flags are:
 "KEY_ALL_ACCESS"
 "KEY_CREATE_LINK"
 "KEY_CREATE_SUB_KEY"
 "KEY_ENUMERATE_SUB_KEYS"
 "KEY_EXECUTE"
 "KEY_NOTIFY"
 "KEY_QUERY_VALUE"
 "KEY_READ"
 "KEY_SET_VALUE"
 These are not documented in the underlying API but should be for
 this API. This documentation would be derived from the Microsoft
 documentation. They would be represented as integer or string
 constants in the Python API and used something like this:
 key=key.OpenKey( subkeyname, winreg.KEY_READ )
 [Issue: Security_Access_Flags]
 [Yes] Allow the specification of security access flags.
 [No] Do not allow this specification.
 [Issue: Security_Access_Flags_Representation]
 [Integer] Use the Microsoft integers
 [String] Use string values
 [Tuples] Use (string, integer) tuples
 [Instances] Use instances with "name", "msinteger"
 attributes
 [Issue: Security_Access_Flags_Location]
 [Top-Level] winreg.KEY_READ
 [Dictionary] winreg.flags["KEY_READ"]
 [Instance] winreg.flags.KEY_READ
 Completeness Extension: Flush
 The underlying win32 registry API has a flush method for keys.
 The documentation is as follows:
 """Writes all the attributes of a key to the registry.
 It is not necessary to call RegFlushKey to change a key.
 Registry changes are flushed to disk by the registry using
 its lazy flusher. Registry changes are also flushed to
 disk at system shutdown. Unlike \function{CloseKey()}, the
 \function{FlushKey()} method returns only when all the data
 has been written to the registry. An application should
 only call \function{FlushKey()} if it requires absolute
 certainty that registry changes are on disk."""
 If all completeness extensions are implemented, the author believes
 that this API will be as complete as the underlying API so
 programmers can choose which to use based on familiarity rather 
 than feature-completeness.
-- 
 Paul Prescod - Not encumbered by corporate consensus
"I don't want you to describe to me -- not ever -- what you were doing
to that poor boy to make him sound like that; but if you ever do it
again, please cover his mouth with your hand," Grandmother said.
	-- John Irving, "A Prayer for Owen Meany"

AltStyle によって変換されたページ (->オリジナル) /