[Python-Dev] PEP 514: Python registration in the Windows registry

Paul Moore p.f.moore at gmail.com
Tue Jul 19 08:40:57 EDT 2016


On 19 July 2016 at 10:49, Paul Moore <p.f.moore at gmail.com> wrote:
> On 18 July 2016 at 18:01, Paul Moore <p.f.moore at gmail.com> wrote:
>> On 18 July 2016 at 17:33, Steve Dower <steve.dower at python.org> wrote:
>>>> Some comments below.
>>>
>>> Awesome, thanks! Posted a pull request at
>>> https://github.com/python/peps/pull/59 for ease of diff reading, and some
>>> commentary below (with aggressive snipping).
>>
>> Thanks - I'll do a proper review of that, but just wanted to make a
>> few comments here.
>
> Added some comments to the PR. Basically:
>
> 1. We could do with a better descrition of use cases.
> 2. We either require registry keys to be user-friendly (no UUIDs!) or
> we find an alternative approach for the virtualenv-style use case.
> 3. Registering "how to start the interpreter" (python.exe or whatever)
> should be mandatory.
>
> I don't think we're far off, though.

For what it's worth, the following code seems to do a reasonable job
of scanning the registry according to the rules in the PEP. If anyone
has access to any 3rd party installations of Python that follow the
proposed PEP's rules, it would be interesting to try this script
against them.

import winreg

def list_subkeys(key):
    i = 0
    while True:
        try:
            yield winreg.EnumKey(key, i)
        except WindowsError:
            return
        i += 1

locations = [
    ("64-bit", winreg.HKEY_LOCAL_MACHINE, winreg.KEY_WOW64_64KEY),
    ("32-bit", winreg.HKEY_LOCAL_MACHINE, winreg.KEY_WOW64_32KEY),
    ("user",   winreg.HKEY_CURRENT_USER, 0),
]

if __name__ == "__main__":
    seen = {}
    for loc, hive, bits in locations:
        k = winreg.CreateKeyEx(hive, "Software\\Python", 0,
winreg.KEY_READ | bits)
        for company in list_subkeys(k):
            sk = winreg.CreateKey(k, company)
            for tag in list_subkeys(sk):
                try:
                    prefix = winreg.QueryValue(sk, "{}\InstallPath".format(tag))
                except WindowsError:
                    # If there's no InstallPath, it's not a valid registration
                    continue
                clash = ""
                if seen.get((company, tag)):
                    clash = "Overrides" if hive ==
winreg.HKEY_CURRENT_USER else "Ambiguous"
                print("{}\{} ({}) {} {}".format(company, tag, loc,
prefix, clash))
                seen[(company, tag)] = True

This code works (and gives the same results) on at least 2.7 and 3.4+
(32 and 64 bit). I didn't test on older versions. It was tricky enough
to get right that I'll probably package it up and publish it at some
point. Steve - if you want to add it to the PEP as a sample
implementation, that's fine with me, too.

Some notes:

1. Python 2.7 allows "Ambiguous" system installs. In other words, the
<Tag> is the same for 32 and 64 bit, but the installer doesn't stop
you installing both. Python 3.4 has the same <Tag> but the installer
prevents installing both 32 and 64 bit versions.
2. Prior to 3.5, it's impossible without running the interpreter or
inspecting the exe to determine if a user install is 32 or 64 bit. You
can tell for a system install based on which registry key you found
the data on.

As these are both legacy / "backward compatibility" issues, they
aren't a problem with the PEP as such.

Paul


More information about the Python-Dev mailing list