| 
									
										
										
										
											2021-01-19 23:04:49 +01:00
										 |  |  | # This script lists the names of standard library modules | 
					
						
							| 
									
										
										
										
											2021-01-25 23:12:50 +01:00
										 |  |  | # to update Python/stdlib_mod_names.h | 
					
						
							| 
									
										
										
										
											2021-01-19 23:04:49 +01:00
										 |  |  | import os.path | 
					
						
							|  |  |  | import re | 
					
						
							|  |  |  | import subprocess | 
					
						
							|  |  |  | import sys | 
					
						
							|  |  |  | import sysconfig | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | SRC_DIR = os.path.dirname(os.path.dirname(os.path.dirname(__file__))) | 
					
						
							|  |  |  | STDLIB_PATH = os.path.join(SRC_DIR, 'Lib') | 
					
						
							|  |  |  | MODULES_SETUP = os.path.join(SRC_DIR, 'Modules', 'Setup') | 
					
						
							|  |  |  | SETUP_PY = os.path.join(SRC_DIR, 'setup.py') | 
					
						
							| 
									
										
										
										
											2021-03-10 11:14:07 +01:00
										 |  |  | TEST_EMBED = os.path.join(SRC_DIR, 'Programs', '_testembed') | 
					
						
							| 
									
										
										
										
											2021-01-19 23:04:49 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | IGNORE = { | 
					
						
							|  |  |  |     '__init__', | 
					
						
							|  |  |  |     '__pycache__', | 
					
						
							|  |  |  |     'site-packages', | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-10 11:14:07 +01:00
										 |  |  |     # Test modules and packages | 
					
						
							|  |  |  |     '__hello__', | 
					
						
							|  |  |  |     '__phello__', | 
					
						
							| 
									
										
										
										
											2021-01-19 23:04:49 +01:00
										 |  |  |     '_ctypes_test', | 
					
						
							|  |  |  |     '_testbuffer', | 
					
						
							|  |  |  |     '_testcapi', | 
					
						
							|  |  |  |     '_testconsole', | 
					
						
							|  |  |  |     '_testimportmultiple', | 
					
						
							|  |  |  |     '_testinternalcapi', | 
					
						
							|  |  |  |     '_testmultiphase', | 
					
						
							| 
									
										
										
										
											2021-03-10 12:10:01 +01:00
										 |  |  |     '_xxsubinterpreters', | 
					
						
							| 
									
										
										
										
											2021-01-19 23:04:49 +01:00
										 |  |  |     '_xxtestfuzz', | 
					
						
							|  |  |  |     'distutils.tests', | 
					
						
							|  |  |  |     'idlelib.idle_test', | 
					
						
							|  |  |  |     'lib2to3.tests', | 
					
						
							|  |  |  |     'test', | 
					
						
							|  |  |  |     'xxlimited', | 
					
						
							|  |  |  |     'xxlimited_35', | 
					
						
							|  |  |  |     'xxsubtype', | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Windows extension modules | 
					
						
							|  |  |  | WINDOWS_MODULES = ( | 
					
						
							|  |  |  |     '_msi', | 
					
						
							| 
									
										
										
										
											2021-04-01 02:28:23 +02:00
										 |  |  |     '_overlapped', | 
					
						
							| 
									
										
										
										
											2021-01-19 23:04:49 +01:00
										 |  |  |     '_testconsole', | 
					
						
							|  |  |  |     '_winapi', | 
					
						
							|  |  |  |     'msvcrt', | 
					
						
							|  |  |  |     'nt', | 
					
						
							|  |  |  |     'winreg', | 
					
						
							|  |  |  |     'winsound' | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Pure Python modules (Lib/*.py) | 
					
						
							| 
									
										
										
										
											2021-01-25 13:24:42 +01:00
										 |  |  | def list_python_modules(names): | 
					
						
							| 
									
										
										
										
											2021-01-19 23:04:49 +01:00
										 |  |  |     for filename in os.listdir(STDLIB_PATH): | 
					
						
							|  |  |  |         if not filename.endswith(".py"): | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         name = filename.removesuffix(".py") | 
					
						
							| 
									
										
										
										
											2021-01-25 13:24:42 +01:00
										 |  |  |         names.add(name) | 
					
						
							| 
									
										
										
										
											2021-01-19 23:04:49 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-28 00:03:23 +01:00
										 |  |  | # Packages in Lib/ | 
					
						
							|  |  |  | def list_packages(names): | 
					
						
							|  |  |  |     for name in os.listdir(STDLIB_PATH): | 
					
						
							| 
									
										
										
										
											2021-01-19 23:04:49 +01:00
										 |  |  |         if name in IGNORE: | 
					
						
							|  |  |  |             continue | 
					
						
							| 
									
										
										
										
											2021-01-28 00:03:23 +01:00
										 |  |  |         package_path = os.path.join(STDLIB_PATH, name) | 
					
						
							| 
									
										
										
										
											2021-01-19 23:04:49 +01:00
										 |  |  |         if not os.path.isdir(package_path): | 
					
						
							|  |  |  |             continue | 
					
						
							| 
									
										
										
										
											2021-01-28 00:03:23 +01:00
										 |  |  |         if any(package_file.endswith(".py") | 
					
						
							|  |  |  |                for package_file in os.listdir(package_path)): | 
					
						
							|  |  |  |             names.add(name) | 
					
						
							| 
									
										
										
										
											2021-01-19 23:04:49 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Extension modules built by setup.py | 
					
						
							| 
									
										
										
										
											2021-01-25 13:24:42 +01:00
										 |  |  | def list_setup_extensions(names): | 
					
						
							| 
									
										
										
										
											2021-01-19 23:04:49 +01:00
										 |  |  |     cmd = [sys.executable, SETUP_PY, "-q", "build", "--list-module-names"] | 
					
						
							|  |  |  |     output = subprocess.check_output(cmd) | 
					
						
							|  |  |  |     output = output.decode("utf8") | 
					
						
							| 
									
										
										
										
											2021-01-25 13:24:42 +01:00
										 |  |  |     extensions = output.splitlines() | 
					
						
							|  |  |  |     names |= set(extensions) | 
					
						
							| 
									
										
										
										
											2021-01-19 23:04:49 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Built-in and extension modules built by Modules/Setup | 
					
						
							| 
									
										
										
										
											2021-01-25 13:24:42 +01:00
										 |  |  | def list_modules_setup_extensions(names): | 
					
						
							| 
									
										
										
										
											2021-01-19 23:04:49 +01:00
										 |  |  |     assign_var = re.compile("^[A-Z]+=") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     with open(MODULES_SETUP, encoding="utf-8") as modules_fp: | 
					
						
							|  |  |  |         for line in modules_fp: | 
					
						
							|  |  |  |             # Strip comment | 
					
						
							|  |  |  |             line = line.partition("#")[0] | 
					
						
							|  |  |  |             line = line.rstrip() | 
					
						
							|  |  |  |             if not line: | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             if assign_var.match(line): | 
					
						
							|  |  |  |                 # Ignore "VAR=VALUE" | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             if line in ("*disabled*", "*shared*"): | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             parts = line.split() | 
					
						
							|  |  |  |             if len(parts) < 2: | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             # "errno errnomodule.c" => write "errno" | 
					
						
							|  |  |  |             name = parts[0] | 
					
						
							| 
									
										
										
										
											2021-01-25 13:24:42 +01:00
										 |  |  |             names.add(name) | 
					
						
							| 
									
										
										
										
											2021-01-19 23:04:49 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-25 13:24:42 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-10 11:14:07 +01:00
										 |  |  | # List frozen modules of the PyImport_FrozenModules list (Python/frozen.c). | 
					
						
							|  |  |  | # Use the "./Programs/_testembed list_frozen" command. | 
					
						
							|  |  |  | def list_frozen(names): | 
					
						
							|  |  |  |     args = [TEST_EMBED, 'list_frozen'] | 
					
						
							|  |  |  |     proc = subprocess.run(args, stdout=subprocess.PIPE, text=True) | 
					
						
							|  |  |  |     exitcode = proc.returncode | 
					
						
							|  |  |  |     if exitcode: | 
					
						
							|  |  |  |         cmd = ' '.join(args) | 
					
						
							|  |  |  |         print(f"{cmd} failed with exitcode {exitcode}") | 
					
						
							|  |  |  |         sys.exit(exitcode) | 
					
						
							| 
									
										
										
										
											2021-09-13 16:18:37 -06:00
										 |  |  |     submodules = set() | 
					
						
							| 
									
										
										
										
											2021-03-10 11:14:07 +01:00
										 |  |  |     for line in proc.stdout.splitlines(): | 
					
						
							|  |  |  |         name = line.strip() | 
					
						
							| 
									
										
										
										
											2021-09-13 16:18:37 -06:00
										 |  |  |         if '.' in name: | 
					
						
							|  |  |  |             submodules.add(name) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             names.add(name) | 
					
						
							|  |  |  |     # Make sure all frozen submodules have a known parent. | 
					
						
							|  |  |  |     for name in list(submodules): | 
					
						
							|  |  |  |         if name.partition('.')[0] in names: | 
					
						
							|  |  |  |             submodules.remove(name) | 
					
						
							|  |  |  |     if submodules: | 
					
						
							|  |  |  |         raise Exception(f'unexpected frozen submodules: {sorted(submodules)}') | 
					
						
							| 
									
										
										
										
											2021-03-10 11:14:07 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-25 13:24:42 +01:00
										 |  |  | def list_modules(): | 
					
						
							|  |  |  |     names = set(sys.builtin_module_names) | set(WINDOWS_MODULES) | 
					
						
							|  |  |  |     list_modules_setup_extensions(names) | 
					
						
							|  |  |  |     list_setup_extensions(names) | 
					
						
							|  |  |  |     list_packages(names) | 
					
						
							|  |  |  |     list_python_modules(names) | 
					
						
							| 
									
										
										
										
											2021-03-10 11:14:07 +01:00
										 |  |  |     list_frozen(names) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Remove ignored packages and modules | 
					
						
							|  |  |  |     for name in list(names): | 
					
						
							|  |  |  |         package_name = name.split('.')[0] | 
					
						
							|  |  |  |         # package_name can be equal to name | 
					
						
							|  |  |  |         if package_name in IGNORE: | 
					
						
							|  |  |  |             names.discard(name) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for name in names: | 
					
						
							|  |  |  |         if "." in name: | 
					
						
							|  |  |  |             raise Exception("sub-modules must not be listed") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-25 13:24:42 +01:00
										 |  |  |     return names | 
					
						
							| 
									
										
										
										
											2021-01-19 23:04:49 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-25 13:24:42 +01:00
										 |  |  | def write_modules(fp, names): | 
					
						
							| 
									
										
										
										
											2021-01-25 23:12:50 +01:00
										 |  |  |     print("// Auto-generated by Tools/scripts/generate_stdlib_module_names.py.", | 
					
						
							|  |  |  |           file=fp) | 
					
						
							|  |  |  |     print("// List used to create sys.stdlib_module_names.", file=fp) | 
					
						
							| 
									
										
										
										
											2021-01-19 23:04:49 +01:00
										 |  |  |     print(file=fp) | 
					
						
							| 
									
										
										
										
											2021-01-25 23:12:50 +01:00
										 |  |  |     print("static const char* _Py_stdlib_module_names[] = {", file=fp) | 
					
						
							| 
									
										
										
										
											2021-01-25 13:24:42 +01:00
										 |  |  |     for name in sorted(names): | 
					
						
							|  |  |  |         print(f'"{name}",', file=fp) | 
					
						
							| 
									
										
										
										
											2021-01-19 23:04:49 +01:00
										 |  |  |     print("};", file=fp) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def main(): | 
					
						
							|  |  |  |     if not sysconfig.is_python_build(): | 
					
						
							|  |  |  |         print(f"ERROR: {sys.executable} is not a Python build", | 
					
						
							|  |  |  |               file=sys.stderr) | 
					
						
							|  |  |  |         sys.exit(1) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-25 13:24:42 +01:00
										 |  |  |     fp = sys.stdout | 
					
						
							|  |  |  |     names = list_modules() | 
					
						
							|  |  |  |     write_modules(fp, names) | 
					
						
							| 
									
										
										
										
											2021-01-19 23:04:49 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | if __name__ == "__main__": | 
					
						
							|  |  |  |     main() |