Skip to content

Instantly share code, notes, and snippets.

@sfaleron sfaleron/pyinsts.py
Last active Jul 25, 2018

Embed
What would you like to do?
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.
# 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
You can’t perform that action at this time.