Last active
July 25, 2018 20:56
-
-
Save sfaleron/01c4f10e48f1f60efc34be51c4d1c4a2 to your computer and use it in GitHub Desktop.
Queries Windows registry for Python installations, as specified in PEP514. The bitness is determined by invoking it, since only v3.5 and later include that in the registry.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# PEP514 defines these registry entries | |
# https://www.python.org/dev/peps/pep-0514/ | |
from __future__ import print_function | |
# https://gist.github.com/sfaleron/6d31cfe2a7188b6bcea5ca67346254a1 | |
import pybits | |
import sys | |
PY2 = sys.version_info[0] < 3 | |
if PY2: | |
import _winreg as wr | |
FileNotFoundError = WindowsError | |
else: | |
import winreg as wr | |
hkcu = wr.HKEY_CURRENT_USER | |
hklm = wr.HKEY_LOCAL_MACHINE | |
import os.path as osp | |
class KeywordToAttr(object): | |
__slots__ = () | |
def __init__(self, **kw): | |
for k, v in kw.items(): | |
setattr(self, k, v) | |
class ByBits(KeywordToAttr): | |
__slots__ = ('bits32', 'bits64') | |
class ByRole(KeywordToAttr): | |
__slots__ = ('user', 'system') | |
rootKey = r'Software\Python\PythonCore' | |
def OpenKey6432(parent, subPath): | |
if PY2: | |
return wr.OpenKey(parent, subPath, 0, | |
wr.KEY_READ | wr.KEY_WOW64_32KEY) | |
else: | |
return wr.OpenKey(parent, subPath, | |
access=wr.KEY_READ | wr.KEY_WOW64_32KEY) | |
def OpenKey6464(parent, subPath): | |
if PY2: | |
return wr.OpenKey(parent, subPath, 0, | |
wr.KEY_READ | wr.KEY_WOW64_64KEY) | |
else: | |
return wr.OpenKey(parent, subPath, | |
access=wr.KEY_READ | wr.KEY_WOW64_64KEY) | |
def get_bits(path): | |
return pybits.get_bits(osp.join(path, 'python.exe')) | |
def _inner_insts(OpenKey, hive, cont): | |
try: | |
k = OpenKey(hive, rootKey) | |
except FileNotFoundError: | |
return | |
n = wr.QueryInfoKey(k)[0] | |
for i in range(n): | |
verStr = wr.EnumKey(k, i) | |
kk = OpenKey(k, verStr) | |
try: | |
kPath = OpenKey(kk, 'InstallPath') | |
except FileNotFoundError: | |
continue | |
m = wr.QueryInfoKey(kPath)[1] | |
for j in range(m): | |
name, val, typ = wr.EnumValue(kPath, j) | |
if name == '': | |
pypath = val | |
if '-' in verStr: | |
verStr = verStr[:verStr.index('-')] | |
if get_bits(pypath) == 64: | |
cont.bits64.add((verStr, pypath)) | |
else: | |
cont.bits32.add((verStr, pypath)) | |
def find_insts(): | |
# defaults are okay: only one instance | |
found = ByRole( | |
user = ByBits(bits32=set(), bits64=set()), | |
system = ByBits(bits32=set(), bits64=set())) | |
# one of the 6432/6464 calls is equivalent to not | |
# using any extra flags, exactly which one depends | |
# on the "bitness" of the interpreter. | |
_inner_insts(OpenKey6432, hkcu, found.user) | |
_inner_insts(OpenKey6464, hkcu, found.user) | |
_inner_insts(OpenKey6432, hklm, found.system) | |
_inner_insts(OpenKey6464, hklm, found.system) | |
return found | |
def _toStr(l): | |
return ''.join(['\n {} {}'.format(v,p) for v,p in l]) | |
if __name__ == '__main__': | |
found = find_insts() | |
print('User') | |
print('32: ' + _toStr(found.user.bits32)) | |
print('64: ' + _toStr(found.user.bits64)) | |
print('System') | |
print('32: ' + _toStr(found.system.bits32)) | |
print('64: ' + _toStr(found.system.bits64)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment