This PEP is now accepted. Congratulations, Steve! And thanks for putting up with all of my last-minute questions :-)
Paul
On 23 July 2016 at 21:20, Guido van Rossum <guido@python.org> wrote: > I'll let Paul pronounce. But you should probably have a BDFL-Delegate: > ... header. > > On Sat, Jul 23, 2016 at 12:16 PM, Steve Dower <steve.dower@python.org> wrote: >> PEP 514 is now ready for pronouncement, so this is the last chance for any >> feedback (BDFL-delegate Paul has been active on the github PR, so I don't >> expect he has a lot of feedback left). >> >> The most major change from the previous post is the addition of some code >> examples at the end. Honestly, I don't expect many tools written in Python >> to be scanning the registry (since once you're in Python you probably don't >> need to find it), but hopefully they'll help clarify the PEP for people who >> prefer code. >> >> Full text below. >> >> Cheers, >> Steve >> >> ---------- >> >> PEP: 514 >> Title: Python registration in the Windows registry >> Version: $Revision$ >> Last-Modified: $Date$ >> Author: Steve Dower <steve.dower@python.org> >> Status: Draft >> Type: Informational >> Content-Type: text/x-rst >> Created: 02-Feb-2016 >> Post-History: 02-Feb-2016, 01-Mar-2016, 18-Jul-2016 >> >> Abstract >> ======== >> >> This PEP defines a schema for the Python registry key to allow third-party >> installers to register their installation, and to allow tools and >> applications >> to detect and correctly display all Python environments on a user's machine. >> No >> implementation changes to Python are proposed with this PEP. >> >> Python environments are not required to be registered unless they want to be >> automatically discoverable by external tools. As this relates to Windows >> only, >> these tools are expected to be predominantly GUI applications. However, >> console >> applications may also make use of the registered information. This PEP >> covers >> the information that may be made available, but the actual presentation and >> use >> of this information is left to the tool designers. >> >> The schema matches the registry values that have been used by the official >> installer since at least Python 2.5, and the resolution behaviour matches >> the >> behaviour of the official Python releases. Some backwards compatibility >> rules >> are provided to ensure tools can correctly detect versions of CPython that >> do >> not register full information. >> >> Motivation >> ========== >> >> When installed on Windows, the official Python installer creates a registry >> key >> for discovery and detection by other applications. This allows tools such as >> installers or IDEs to automatically detect and display a user's Python >> installations. For example, the PEP 397 ``py.exe`` launcher and editors such >> as >> PyCharm and Visual Studio already make use of this information. >> >> Third-party installers, such as those used by distributions, typically >> create >> identical keys for the same purpose. Most tools that use the registry to >> detect >> Python installations only inspect the keys used by the official installer. >> As a >> result, third-party installations that wish to be discoverable will >> overwrite >> these values, often causing users to "lose" their original Python >> installation. >> >> By describing a layout for registry keys that allows third-party >> installations >> to register themselves uniquely, as well as providing tool developers >> guidance >> for discovering all available Python installations, these collisions should >> be >> prevented. We also take the opportunity to add some well-known metadata so >> that >> more information can be presented to users. >> >> Definitions >> =========== >> >> A "registry key" is the equivalent of a file-system path into the registry. >> Each >> key may contain "subkeys" (keys nested within keys) and "values" (named and >> typed attributes attached to a key). These are used on Windows to store >> settings >> in much the same way that directories containing configuration files would >> work. >> >> ``HKEY_CURRENT_USER`` is the root of settings for the currently logged-in >> user, >> and this user can generally read and write all settings under this root. >> >> ``HKEY_LOCAL_MACHINE`` is the root of settings for all users. Generally, any >> user can read these settings but only administrators can modify them. It is >> typical for values under ``HKEY_CURRENT_USER`` to take precedence over those >> in >> ``HKEY_LOCAL_MACHINE``. >> >> On 64-bit Windows, ``HKEY_LOCAL_MACHINE\Software\Wow6432Node`` is a special >> key >> that 32-bit processes transparently read and write to rather than accessing >> the >> ``Software`` key directly. >> >> Further documentation regarding registry redirection on Windows is available >> from the MSDN Library [1]_. >> >> Structure >> ========= >> >> We consider there to be a single collection of Python environments on a >> machine, >> where the collection may be different for each user of the machine. There >> are >> three potential registry locations where the collection may be stored based >> on >> the installation options of each environment:: >> >> HKEY_CURRENT_USER\Software\Python\<Company>\<Tag> >> HKEY_LOCAL_MACHINE\Software\Python\<Company>\<Tag> >> HKEY_LOCAL_MACHINE\Software\Wow6432Node\Python\<Company>\<Tag> >> >> Official Python releases use ``PythonCore`` for Company, and the value of >> ``sys.winver`` for Tag. The Company ``PyLauncher`` is reserved. Other >> registered >> environments may use any values for Company and Tag. Recommendations are >> made >> later in this document. >> >> Company-Tag pairs are case-insensitive, and uniquely identify each >> environment. >> Depending on the purpose and intended use of a tool, there are two suggested >> approaches for resolving conflicts between Company-Tag pairs. >> >> Tools that list every installed environment may choose to include those >> even where the Company-Tag pairs match. They should ensure users can easily >> identify whether the registration was per-user or per-machine, and which >> registration has the higher priority. >> >> Tools that aim to select a single installed environment from all registered >> environments based on the Company-Tag pair, such as the ``py.exe`` launcher, >> should always select the environment registered in ``HKEY_CURRENT_USER`` >> when >> than the matching one in ``HKEY_LOCAL_MACHINE``. >> >> Conflicts between ``HKEY_LOCAL_MACHINE\Software\Python`` and >> ``HKEY_LOCAL_MACHINE\Software\Wow6432Node\Python`` should only occur when >> both >> 64-bit and 32-bit versions of an interpreter have the same Tag. In this >> case, >> the tool should select whichever is more appropriate for its use. >> >> If a tool is able to determine from the provided information (or lack >> thereof) >> that it cannot use a registered environment, there is no obligation to >> present >> it to users. >> >> Except as discussed in the section on backwards compatibility, Company and >> Tag >> values are considered opaque to tools, and no information about the >> interpreter >> should be inferred from the text. However, some tools may display the >> Company >> and Tag values to users, so ideally the Tag will be able to help users >> identify >> the associated environment. >> >> Python environments are not required to register themselves unless they want >> to >> be automatically discoverable by external tools. >> >> Backwards Compatibility >> ----------------------- >> >> Python 3.4 and earlier did not distinguish between 32-bit and 64-bit builds >> in >> ``sys.winver``. As a result, it is not possible to have valid side-by-side >> installations of both 32-bit and 64-bit interpreters under this scheme since >> it >> would result in duplicate Tags. >> >> To ensure backwards compatibility, applications should treat environments >> listed >> under the following two registry keys as distinct, even when the Tag >> matches:: >> >> HKEY_LOCAL_MACHINE\Software\Python\PythonCore\<Tag> >> HKEY_LOCAL_MACHINE\Software\Wow6432Node\Python\PythonCore\<Tag> >> >> Environments listed under ``HKEY_CURRENT_USER`` may be treated as distinct >> from >> both of the above keys, potentially resulting in three environments >> discovered >> using the same Tag. Alternatively, a tool may determine whether the per-user >> environment is 64-bit or 32-bit and give it priority over the per-machine >> environment, resulting in a maximum of two discovered environments. >> >> It is not possible to detect side-by-side installations of both 64-bit and >> 32-bit versions of Python prior to 3.5 when they have been installed for the >> current user. Python 3.5 and later always uses different Tags for 64-bit and >> 32-bit versions. >> >> The following section describe user-visible information that may be >> registered. >> For Python 3.5 and earlier, none of this information is available, but >> alternative defaults are specified for the ``PythonCore`` key. >> >> Environments registered under other Company names have no backward >> compatibility >> requirements and must use distinct Tags to support side-by-side >> installations. >> Tools consuming these registrations are not required to disambiguate tags >> other >> than by preferring the user's setting. >> >> Company >> ------- >> >> The Company part of the key is intended to group related environments and to >> ensure that Tags are namespaced appropriately. The key name should be >> alphanumeric without spaces and likely to be unique. For example, a >> trademarked >> name (preferred), a hostname, or as a last resort, a UUID would be >> appropriate:: >> >> HKEY_CURRENT_USER\Software\Python\ExampleCorp >> HKEY_CURRENT_USER\Software\Python\www.example.com >> HKEY_CURRENT_USER\Software\Python\6C465E66-5A8C-4942-9E6A-D29159480C60 >> >> The company name ``PyLauncher`` is reserved for the PEP 397 launcher >> (``py.exe``). It does not follow this convention and should be ignored by >> tools. >> >> If a string value named ``DisplayName`` exists, it should be used to >> identify >> the environment manufacturer/developer/destributor to users. Otherwise, the >> name >> of the key should be used. (For ``PythonCore``, the default display name is >> "Python Software Foundation".) >> >> If a string value named ``SupportUrl`` exists, it may be displayed or >> otherwise >> used to direct users to a web site related to the environment. (For >> ``PythonCore``, the default support URL is "http://www.python.org/".) >> >> A complete example may look like:: >> >> HKEY_CURRENT_USER\Software\Python\ExampleCorp >> (Default) = (value not set) >> DisplayName = "Example Corp" >> SupportUrl = "http://www.example.com" >> >> Tag >> --- >> >> The Tag part of the key is intended to uniquely identify an environment >> within >> those provided by a single company. The key name should be alphanumeric >> without >> spaces and stable across installations. For example, the Python language >> version, a UUID or a partial/complete hash would be appropriate, while a Tag >> based on the install directory or some aspect of the current machine may >> not. >> For example:: >> >> HKEY_CURRENT_USER\Software\Python\ExampleCorp\examplepy >> HKEY_CURRENT_USER\Software\Python\ExampleCorp\3.6 >> HKEY_CURRENT_USER\Software\Python\ExampleCorp\6C465E66 >> >> It is expected that some tools will require users to type the Tag into a >> command >> line, and that the Company may be optional provided the Tag is unique across >> all >> Python installations. Short, human-readable and easy to type Tags are >> recommended, and if possible, select a value likely to be unique across all >> other Companies. >> >> If a string value named ``DisplayName`` exists, it should be used to >> identify >> the environment to users. Otherwise, the name of the key should be used. >> (For >> ``PythonCore``, the default is "Python " followed by the Tag.) >> >> If a string value named ``SupportUrl`` exists, it may be displayed or >> otherwise >> used to direct users to a web site related to the environment. (For >> ``PythonCore``, the default is "http://www.python.org/".) >> >> If a string value named ``Version`` exists, it should be used to identify >> the >> version of the environment. This is independent from the version of Python >> implemented by the environment. (For ``PythonCore``, the default is the >> first >> three characters of the Tag.) >> >> If a string value named ``SysVersion`` exists, it must be in ``x.y`` or >> ``x.y.z`` format matching the version returned by ``sys.version_info`` in >> the >> interpreter. If omitted, the Python version is unknown. (For ``PythonCore``, >> the default is the first three characters of the Tag.) >> >> If a string value named ``SysArchitecture`` exists, it must match the first >> element of the tuple returned by ``platform.architecture()``. Typically, >> this >> will be "32bit" or "64bit". If omitted, the architecture is unknown. (For >> ``PythonCore``, the architecture is "32bit" when registered under >> ``HKEY_LOCAL_MACHINE\Software\Wow6432Node\Python`` *or* anywhere on a 32-bit >> operating system, "64bit" when registered under >> ``HKEY_LOCAL_MACHINE\Software\Python`` on a 64-bit machine, and unknown when >> registered under ``HKEY_CURRENT_USER``.) >> >> Note that each of these values is recommended, but optional. Omitting >> ``SysVersion`` or ``SysArchitecture`` may prevent some tools from correctly >> supporting the environment. A complete example may look like this:: >> >> HKEY_CURRENT_USER\Software\Python\ExampleCorp\examplepy >> (Default) = (value not set) >> DisplayName = "Example Py Distro 3" >> SupportUrl = "http://www.example.com/distro-3" >> Version = "3.0.12345.0" >> SysVersion = "3.6.0" >> SysArchitecture = "64bit" >> >> InstallPath >> ----------- >> >> Beneath the environment key, an ``InstallPath`` key must be created. This >> key is >> always named ``InstallPath``, and the default value must match >> ``sys.prefix``:: >> >> HKEY_CURRENT_USER\Software\Python\ExampleCorp\3.6\InstallPath >> (Default) = "C:\ExampleCorpPy36" >> >> If a string value named ``ExecutablePath`` exists, it must be the full path >> to >> the ``python.exe`` (or equivalent) executable. If omitted, the environment >> is >> not executable. (For ``PythonCore``, the default is the ``python.exe`` file >> in >> the directory referenced by the ``(Default)`` value.) >> >> If a string value named ``ExecutableArguments`` exists, tools should use the >> value as the first arguments when executing ``ExecutablePath``. Tools may >> add >> other arguments following these, and will reasonably expect standard Python >> command line options to be available. >> >> If a string value named ``WindowedExecutablePath`` exists, it must be a path >> to >> the ``pythonw.exe`` (or equivalent) executable. If omitted, the default is >> the >> value of ``ExecutablePath``, and if that is omitted the environment is not >> executable. (For ``PythonCore``, the default is the ``pythonw.exe`` file in >> the >> directory referenced by the ``(Default)`` value.) >> >> If a string value named ``WindowedExecutableArguments`` exists, tools should >> use >> the value as the first arguments when executing ``WindowedExecutablePath``. >> Tools may add other arguments following these, and will reasonably expect >> standard Python command line options to be available. >> >> A complete example may look like:: >> >> HKEY_CURRENT_USER\Software\Python\ExampleCorp\examplepy\InstallPath >> (Default) = "C:\ExampleDistro30" >> ExecutablePath = "C:\ExampleDistro30\ex_python.exe" >> ExecutableArguments = "--arg1" >> WindowedExecutablePath = "C:\ExampleDistro30\ex_pythonw.exe" >> WindowedExecutableArguments = "--arg1" >> >> Help >> ---- >> >> Beneath the environment key, a ``Help`` key may be created. This key is >> always >> named ``Help`` if present and has no default value. >> >> Each subkey of ``Help`` specifies a documentation file, tool, or URL >> associated >> with the environment. The subkey may have any name, and the default value is >> a >> string appropriate for passing to ``os.startfile`` or equivalent. >> >> If a string value named ``DisplayName`` exists, it should be used to >> identify >> the help file to users. Otherwise, the key name should be used. >> >> A complete example may look like:: >> >> HKEY_CURRENT_USER\Software\Python\ExampleCorp\6C465E66\Help >> Python\ >> (Default) = "C:\ExampleDistro30\python36.chm" >> DisplayName = "Python Documentation" >> Extras\ >> (Default) = "http://www.example.com/tutorial" >> DisplayName = "Example Distro Online Tutorial" >> >> Other Keys >> ---------- >> >> All other subkeys under a Company-Tag pair are available for private use. >> >> Official CPython releases have traditionally used certain keys in this space >> to >> determine the location of the Python standard library and other installed >> modules. This behaviour is retained primarily for backward compatibility. >> However, as the code that reads these values is embedded into the >> interpreter, >> third-party distributions may be affected by values written into >> ``PythonCore`` >> if using an unmodified interpreter. >> >> Sample Code >> =========== >> >> This sample code enumerates the registry and displays the available >> Company-Tag >> pairs that could be used to launch an environment and the target executable. >> It >> only shows the most-preferred target for the tag. Backwards-compatible >> handling >> of ``PythonCore`` is omitted but shown in a later example:: >> >> # Display most-preferred environments. >> # Assumes a 64-bit operating system >> # Does not correctly handle PythonCore compatibility >> >> import winreg >> >> def enum_keys(key): >> i = 0 >> while True: >> try: >> yield winreg.EnumKey(key, i) >> except OSError: >> break >> i += 1 >> >> def get_value(key, value_name): >> try: >> return winreg.QueryValue(key, value_name) >> except FileNotFoundError: >> return None >> >> seen = set() >> for hive, key, flags in [ >> (winreg.HKEY_CURRENT_USER, r'Software\Python', 0), >> (winreg.HKEY_LOCAL_MACHINE, r'Software\Python', >> winreg.KEY_WOW64_64KEY), >> (winreg.HKEY_LOCAL_MACHINE, r'Software\Python', >> winreg.KEY_WOW64_32KEY), >> ]: >> with winreg.OpenKeyEx(hive, key, access=winreg.KEY_READ | flags) as >> root_key: >> for comany in enum_keys(root_key): >> if company == 'PyLauncher': >> continue >> >> with winreg.OpenKey(root_key, company) as company_key: >> for tag in enum_keys(company_key): >> if (company, tag) in seen: >> if company == 'PythonCore': >> # TODO: Backwards compatibility handling >> pass >> continue >> seen.add((company, tag)) >> >> try: >> with winreg.OpenKey(company_key, tag + >> r'\InstallPath') as ip_key: >> exec_path = get_value(ip_key, >> 'ExecutablePath') >> exec_args = get_value(ip_key, >> 'ExecutableArguments') >> if company == 'PythonCore' and not >> exec_path: >> # TODO: Backwards compatibility handling >> pass >> except OSError: >> exec_path, exec_args = None, None >> >> if ex