Mercurial > repos > shellac > guppy_basecaller
comparison env/lib/python3.7/site-packages/virtualenv/discovery/windows/pep514.py @ 2:6af9afd405e9 draft
"planemo upload commit 0a63dd5f4d38a1f6944587f52a8cd79874177fc1"
author | shellac |
---|---|
date | Thu, 14 May 2020 14:56:58 -0400 |
parents | 26e78fe6e8c4 |
children |
comparison
equal
deleted
inserted
replaced
1:75ca89e9b81c | 2:6af9afd405e9 |
---|---|
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 name = str("python") if company == "PythonCore" else company | |
77 return name, major, minor, arch, exe, args | |
78 | |
79 | |
80 def load_exe(hive_name, company, company_key, tag): | |
81 key_path = "{}/{}/{}".format(hive_name, company, tag) | |
82 try: | |
83 with winreg.OpenKeyEx(company_key, r"{}\InstallPath".format(tag)) as ip_key: | |
84 with ip_key: | |
85 exe = get_value(ip_key, "ExecutablePath") | |
86 if exe is None: | |
87 ip = get_value(ip_key, None) | |
88 if ip is None: | |
89 msg(key_path, "no ExecutablePath or default for it") | |
90 | |
91 else: | |
92 exe = os.path.join(ip, str("python.exe")) | |
93 if exe is not None and os.path.exists(exe): | |
94 args = get_value(ip_key, "ExecutableArguments") | |
95 return exe, args | |
96 else: | |
97 msg(key_path, "exe does not exists {}".format(key_path, exe)) | |
98 except OSError: | |
99 msg("{}/{}".format(key_path, "InstallPath"), "missing") | |
100 return None | |
101 | |
102 | |
103 def load_arch_data(hive_name, company, tag, tag_key, default_arch): | |
104 arch_str = get_value(tag_key, "SysArchitecture") | |
105 if arch_str is not None: | |
106 key_path = "{}/{}/{}/SysArchitecture".format(hive_name, company, tag) | |
107 try: | |
108 return parse_arch(arch_str) | |
109 except ValueError as sys_arch: | |
110 msg(key_path, sys_arch) | |
111 return default_arch | |
112 | |
113 | |
114 def parse_arch(arch_str): | |
115 if isinstance(arch_str, six.string_types): | |
116 match = re.match(r"^(\d+)bit$", arch_str) | |
117 if match: | |
118 return int(next(iter(match.groups()))) | |
119 error = "invalid format {}".format(arch_str) | |
120 else: | |
121 error = "arch is not string: {}".format(repr(arch_str)) | |
122 raise ValueError(error) | |
123 | |
124 | |
125 def load_version_data(hive_name, company, tag, tag_key): | |
126 for candidate, key_path in [ | |
127 (get_value(tag_key, "SysVersion"), "{}/{}/{}/SysVersion".format(hive_name, company, tag)), | |
128 (tag, "{}/{}/{}".format(hive_name, company, tag)), | |
129 ]: | |
130 if candidate is not None: | |
131 try: | |
132 return parse_version(candidate) | |
133 except ValueError as sys_version: | |
134 msg(key_path, sys_version) | |
135 return None | |
136 | |
137 | |
138 def parse_version(version_str): | |
139 if isinstance(version_str, six.string_types): | |
140 match = re.match(r"^(\d+)(?:\.(\d+))?(?:\.(\d+))?$", version_str) | |
141 if match: | |
142 return tuple(int(i) if i is not None else None for i in match.groups()) | |
143 error = "invalid format {}".format(version_str) | |
144 else: | |
145 error = "version is not string: {}".format(repr(version_str)) | |
146 raise ValueError(error) | |
147 | |
148 | |
149 def msg(path, what): | |
150 LOGGER.warning("PEP-514 violation in Windows Registry at {} error: {}".format(path, what)) | |
151 | |
152 | |
153 def _run(): | |
154 basicConfig() | |
155 interpreters = [] | |
156 for spec in discover_pythons(): | |
157 interpreters.append(repr(spec)) | |
158 print("\n".join(sorted(interpreters))) | |
159 | |
160 | |
161 if __name__ == "__main__": | |
162 _run() |