Skip to content

Instantly share code, notes, and snippets.

@sfaleron
Last active July 25, 2018 20:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sfaleron/01c4f10e48f1f60efc34be51c4d1c4a2 to your computer and use it in GitHub Desktop.
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.
# 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