cpython/Tools/scripts/generate_module_names.py

201 lines
4.8 KiB
Python
Raw Normal View History

# This script lists the names of standard library modules
# to update Python/module_names.h
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')
IGNORE = {
'__init__',
'__pycache__',
'site-packages',
# Helper modules of public modules.
# For example, sysconfig uses _osx_support.
'_aix_support',
'_collections_abc',
'_compat_pickle',
'_compression',
'_markupbase',
'_osx_support',
'_sitebuiltins',
'_strptime',
'_threading_local',
'_weakrefset',
# Used to bootstrap setup.py
'_bootsubprocess',
# pure Python implementation
'_py_abc',
'_pydecimal',
'_pyio',
# test modules
'__phello__.foo',
'_ctypes_test',
'_testbuffer',
'_testcapi',
'_testconsole',
'_testimportmultiple',
'_testinternalcapi',
'_testmultiphase',
'_xxtestfuzz',
'distutils.tests',
'idlelib.idle_test',
'lib2to3.tests',
'test',
'xxlimited',
'xxlimited_35',
'xxsubtype',
}
# Windows extension modules
WINDOWS_MODULES = (
'_msi',
'_testconsole',
'_winapi',
'msvcrt',
'nt',
'winreg',
'winsound'
)
def write_comment(fp, comment):
print(f"// {comment}", file=fp)
def write_modules(fp, names):
for name in sorted(names):
if name in IGNORE:
continue
print(f'"{name}",', file=fp)
print(file=fp)
def list_builtin_modules(fp):
write_comment(fp, "Built-in modules")
write_modules(fp, sys.builtin_module_names)
# Pure Python modules (Lib/*.py)
def list_python_modules(fp):
write_comment(fp, "Pure Python modules (Lib/*.py)")
names = []
for filename in os.listdir(STDLIB_PATH):
if not filename.endswith(".py"):
continue
name = filename.removesuffix(".py")
names.append(name)
write_modules(fp, names)
def _list_sub_packages(path, names, parent=None):
for name in os.listdir(path):
package_path = os.path.join(path, name)
if name in IGNORE:
continue
if not os.path.isdir(package_path):
continue
if not any(package_file.endswith(".py")
for package_file in os.listdir(package_path)):
continue
if parent:
qualname = f"{parent}.{name}"
else:
qualname = name
if qualname in IGNORE:
continue
names.append(qualname)
_list_sub_packages(package_path, names, qualname)
# Packages and sub-packages
def list_packages(fp):
write_comment(fp, "Packages and sub-packages")
names = []
_list_sub_packages(STDLIB_PATH, names)
write_modules(fp, names)
# Windows extensions
def list_windows_extensions(fp):
write_comment(fp, "Windows extension modules")
write_modules(fp, WINDOWS_MODULES)
# Extension modules built by setup.py
def list_setup(fp):
cmd = [sys.executable, SETUP_PY, "-q", "build", "--list-module-names"]
output = subprocess.check_output(cmd)
output = output.decode("utf8")
names = output.splitlines()
write_comment(fp, "Extension modules built by setup.py")
write_modules(fp, names)
# Built-in and extension modules built by Modules/Setup
def list_modules_setup(fp):
assign_var = re.compile("^[A-Z]+=")
names = []
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]
names.append(name)
write_comment(fp, "Built-in and extension modules built by Modules/Setup")
write_modules(fp, names)
def list_modules(fp):
print("// Auto-generated by Tools/scripts/generate_module_names.py.", file=fp)
print(file=fp)
print("static const char* _Py_module_names[] = {", file=fp)
print(file=fp)
list_builtin_modules(fp)
list_python_modules(fp)
list_packages(fp)
list_setup(fp)
list_modules_setup(fp)
list_windows_extensions(fp)
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)
list_modules(sys.stdout)
if __name__ == "__main__":
main()