aboutsummaryrefslogtreecommitdiff
path: root/Tools
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@python.org>2021-01-19 23:04:49 +0100
committerGitHub <noreply@github.com>2021-01-19 23:04:49 +0100
commitcad8020cb83ec6d904f874c0e4f599e651022196 (patch)
tree7db4f105af783ecd5ac60488b081d945bcea14b3 /Tools
parentbpo-41713: Remove PyOS_InitInterrupts() from python3dll.c (GH-24257) (diff)
downloadcpython-cad8020cb83ec6d904f874c0e4f599e651022196.tar.gz
cpython-cad8020cb83ec6d904f874c0e4f599e651022196.tar.bz2
cpython-cad8020cb83ec6d904f874c0e4f599e651022196.zip
bpo-42955: Add Python/module_names.h (GH-24258)
Add a private list of all stdlib modules: _Py_module_names. * Add Tools/scripts/generate_module_names.py script. * Makefile: Add "make regen-module-names" command. * setup.py: Add --list-module-names option. * GitHub Action and Travis CI also runs "make regen-module-names", not ony "make regen-all", to ensure that the module names remains up to date.
Diffstat (limited to 'Tools')
-rw-r--r--Tools/scripts/generate_module_names.py200
1 files changed, 200 insertions, 0 deletions
diff --git a/Tools/scripts/generate_module_names.py b/Tools/scripts/generate_module_names.py
new file mode 100644
index 00000000000..985a1a5e5a2
--- /dev/null
+++ b/Tools/scripts/generate_module_names.py
@@ -0,0 +1,200 @@
+# 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()