Mercurial > repos > guerler > springsuite
comparison planemo/lib/python3.7/site-packages/virtualenv/discovery/windows/pep514.py @ 1:56ad4e20f292 draft
"planemo upload commit 6eee67778febed82ddd413c3ca40b3183a3898f1"
| author | guerler |
|---|---|
| date | Fri, 31 Jul 2020 00:32:28 -0400 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 0:d30785e31577 | 1:56ad4e20f292 |
|---|---|
| 1 """Implement https://www.python.org/dev/peps/pep-0514/ to discover interpreters - Windows only""" | |
| 2 from __future__ import absolute_import, print_function, unicode_literals | |
| 3 | |
| 4 import os | |
| 5 import re | |
| 6 from logging import basicConfig, getLogger | |
| 7 | |
| 8 import six | |
| 9 | |
| 10 if six.PY3: | |
| 11 import winreg | |
| 12 else: | |
| 13 # noinspection PyUnresolvedReferences | |
| 14 import _winreg as winreg | |
| 15 | |
| 16 LOGGER = getLogger(__name__) | |
| 17 | |
| 18 | |
| 19 def enum_keys(key): | |
| 20 at = 0 | |
| 21 while True: | |
| 22 try: | |
| 23 yield winreg.EnumKey(key, at) | |
| 24 except OSError: | |
| 25 break | |
| 26 at += 1 | |
| 27 | |
| 28 | |
| 29 def get_value(key, value_name): | |
| 30 try: | |
| 31 return winreg.QueryValueEx(key, value_name)[0] | |
| 32 except OSError: | |
| 33 return None | |
| 34 | |
| 35 | |
| 36 def discover_pythons(): | |
| 37 for hive, hive_name, key, flags, default_arch in [ | |
| 38 (winreg.HKEY_CURRENT_USER, "HKEY_CURRENT_USER", r"Software\Python", 0, 64), | |
| 39 (winreg.HKEY_LOCAL_MACHINE, "HKEY_LOCAL_MACHINE", r"Software\Python", winreg.KEY_WOW64_64KEY, 64), | |
| 40 (winreg.HKEY_LOCAL_MACHINE, "HKEY_LOCAL_MACHINE", r"Software\Python", winreg.KEY_WOW64_32KEY, 32), | |
| 41 ]: | |
| 42 for spec in process_set(hive, hive_name, key, flags, default_arch): | |
| 43 yield spec | |
| 44 | |
| 45 | |
| 46 def process_set(hive, hive_name, key, flags, default_arch): | |
| 47 try: | |
| 48 with winreg.OpenKeyEx(hive, key, 0, winreg.KEY_READ | flags) as root_key: | |
| 49 for company in enum_keys(root_key): | |
| 50 if company == "PyLauncher": # reserved | |
| 51 continue | |
| 52 for spec in process_company(hive_name, company, root_key, default_arch): | |
| 53 yield spec | |
| 54 except OSError: | |
| 55 pass | |
| 56 | |
| 57 | |
| 58 def process_company(hive_name, company, root_key, default_arch): | |
| 59 with winreg.OpenKeyEx(root_key, company) as company_key: | |
| 60 for tag in enum_keys(company_key): | |
| 61 spec = process_tag(hive_name, company, company_key, tag, default_arch) | |
| 62 if spec is not None: | |
| 63 yield spec | |
| 64 | |
| 65 | |
| 66 def process_tag(hive_name, company, company_key, tag, default_arch): | |
| 67 with winreg.OpenKeyEx(company_key, tag) as tag_key: | |
| 68 version = load_version_data(hive_name, company, tag, tag_key) | |
| 69 if version is not None: # if failed to get version bail | |
| 70 major, minor, _ = version | |
| 71 arch = load_arch_data(hive_name, company, tag, tag_key, default_arch) | |
| 72 if arch is not None: | |
| 73 exe_data = load_exe(hive_name, company, company_key, tag) | |
| 74 if exe_data is not None: | |
| 75 exe, args = exe_data | |
| 76 return company, major, minor, arch, exe, args | |
| 77 | |
| 78 | |
| 79 def load_exe(hive_name, company, company_key, tag): | |
| 80 key_path = "{}/{}/{}".format(hive_name, company, tag) | |
| 81 try: | |
| 82 with winreg.OpenKeyEx(company_key, r"{}\InstallPath".format(tag)) as ip_key: | |
| 83 with ip_key: | |
| 84 exe = get_value(ip_key, "ExecutablePath") | |
| 85 if exe is None: | |
| 86 ip = get_value(ip_key, None) | |
| 87 if ip is None: | |
| 88 msg(key_path, "no ExecutablePath or default for it") | |
| 89 | |
| 90 else: | |
| 91 exe = os.path.join(ip, str("python.exe")) | |
| 92 if exe is not None and os.path.exists(exe): | |
| 93 args = get_value(ip_key, "ExecutableArguments") | |
| 94 return exe, args | |
| 95 else: | |
| 96 msg(key_path, "could not load exe with value {}".format(exe)) | |
| 97 except OSError: | |
| 98 msg("{}/{}".format(key_path, "InstallPath"), "missing") | |
| 99 return None | |
| 100 | |
| 101 | |
| 102 def load_arch_data(hive_name, company, tag, tag_key, default_arch): | |
| 103 arch_str = get_value(tag_key, "SysArchitecture") | |
| 104 if arch_str is not None: | |
| 105 key_path = "{}/{}/{}/SysArchitecture".format(hive_name, company, tag) | |
| 106 try: | |
| 107 return parse_arch(arch_str) | |
| 108 except ValueError as sys_arch: | |
| 109 msg(key_path, sys_arch) | |
| 110 return default_arch | |
| 111 | |
| 112 | |
| 113 def parse_arch(arch_str): | |
| 114 if isinstance(arch_str, six.string_types): | |
| 115 match = re.match(r"^(\d+)bit$", arch_str) | |
| 116 if match: | |
| 117 return int(next(iter(match.groups()))) | |
| 118 error = "invalid format {}".format(arch_str) | |
| 119 else: | |
| 120 error = "arch is not string: {}".format(repr(arch_str)) | |
| 121 raise ValueError(error) | |
| 122 | |
| 123 | |
| 124 def load_version_data(hive_name, company, tag, tag_key): | |
| 125 for candidate, key_path in [ | |
| 126 (get_value(tag_key, "SysVersion"), "{}/{}/{}/SysVersion".format(hive_name, company, tag)), | |
| 127 (tag, "{}/{}/{}".format(hive_name, company, tag)), | |
| 128 ]: | |
| 129 if candidate is not None: | |
| 130 try: | |
| 131 return parse_version(candidate) | |
| 132 except ValueError as sys_version: | |
| 133 msg(key_path, sys_version) | |
| 134 return None | |
| 135 | |
| 136 | |
| 137 def parse_version(version_str): | |
| 138 if isinstance(version_str, six.string_types): | |
| 139 match = re.match(r"^(\d+)(?:\.(\d+))?(?:\.(\d+))?$", version_str) | |
| 140 if match: | |
| 141 return tuple(int(i) if i is not None else None for i in match.groups()) | |
| 142 error = "invalid format {}".format(version_str) | |
| 143 else: | |
| 144 error = "version is not string: {}".format(repr(version_str)) | |
| 145 raise ValueError(error) | |
| 146 | |
| 147 | |
| 148 def msg(path, what): | |
| 149 LOGGER.warning("PEP-514 violation in Windows Registry at {} error: {}".format(path, what)) | |
| 150 | |
| 151 | |
| 152 def _run(): | |
| 153 basicConfig() | |
| 154 interpreters = [] | |
| 155 for spec in discover_pythons(): | |
| 156 interpreters.append(repr(spec)) | |
| 157 print("\n".join(sorted(interpreters))) | |
| 158 | |
| 159 | |
| 160 if __name__ == "__main__": | |
| 161 _run() |
