this script lists the names of standard library modules to update pythonstdlibmodulenames h test modules and packages builtin modules pure python modules lib py packages in lib builtin and extension modules built by modulessetup includes windows and macos extensions list frozen modules of the pyimportfrozenmodules list pythonfrozen c use the programstestembed listfrozen command to skip hello helloalias and etc make sure all frozen submodules have a known parent remove ignored packages and modules packagename can be equal to name sanity checks this script lists the names of standard library modules to update python stdlib_module_names h test modules and packages built in modules pure python modules lib py packages in lib built in and extension modules built by modules setup includes windows and macos extensions list frozen modules of the pyimport_frozenmodules list python frozen c use the programs _testembed list_frozen command to skip __hello__ __hello_alias__ and etc make sure all frozen submodules have a known parent remove ignored packages and modules package_name can be equal to name sanity checks
import _imp
import os.path
import sys
import sysconfig

from check_extension_modules import ModuleChecker


SCRIPT_NAME = 'Tools/build/generate_stdlib_module_names.py'

SRC_DIR = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
STDLIB_PATH = os.path.join(SRC_DIR, 'Lib')

IGNORE = {
    '__init__',
    '__pycache__',
    'site-packages',

    
    '__hello__',
    '__phello__',
    '__hello_alias__',
    '__phello_alias__',
    '__hello_only__',
    '_ctypes_test',
    '_testbuffer',
    '_testcapi',
    '_testclinic',
    '_testclinic_limited',
    '_testconsole',
    '_testimportmultiple',
    '_testinternalcapi',
    '_testmultiphase',
    '_testsinglephase',
    '_xxsubinterpreters',
    '_xxinterpchannels',
    '_xxtestfuzz',
    'idlelib.idle_test',
    'test',
    'xxlimited',
    'xxlimited_35',
    'xxsubtype',
}

ALLOW_TEST_MODULES = {
    'doctest',
    'unittest',
}


def list_builtin_modules(names):
    names |= set(sys.builtin_module_names)



def list_python_modules(names):
    for filename in os.listdir(STDLIB_PATH):
        if not filename.endswith(".py"):
            continue
        name = filename.removesuffix(".py")
        names.add(name)



def list_packages(names):
    for name in os.listdir(STDLIB_PATH):
        if name in IGNORE:
            continue
        package_path = os.path.join(STDLIB_PATH, name)
        if not os.path.isdir(package_path):
            continue
        if any(package_file.endswith(".py")
               for package_file in os.listdir(package_path)):
            names.add(name)




def list_modules_setup_extensions(names):
    checker = ModuleChecker()
    names.update(checker.list_module_names(all=True))




def list_frozen(names):
    submodules = set()
    for name in _imp._frozen_module_names():
        
        if name.startswith('__'):
            continue
        if '.' in name:
            submodules.add(name)
        else:
            names.add(name)
    
    for name in list(submodules):
        if name.partition('.')[0] in names:
            submodules.remove(name)
    if submodules:
        raise Exception(f'unexpected frozen submodules: {sorted(submodules)}')


def list_modules():
    names = set()

    list_builtin_modules(names)
    list_modules_setup_extensions(names)
    list_packages(names)
    list_python_modules(names)
    list_frozen(names)

    
    for name in list(names):
        package_name = name.split('.')[0]
        
        if package_name in IGNORE:
            names.discard(name)

    
    for name in names:
        if "." in name:
            raise Exception(f"sub-modules must not be listed: {name}")
        if ("test" in name or "xx" in name) and name not in ALLOW_TEST_MODULES:
            raise Exception(f"test modules must not be listed: {name}")

    return names


def write_modules(fp, names):
    print(f"// Auto-generated by {SCRIPT_NAME}.",
          file=fp)
    print("// List used to create sys.stdlib_module_names.", file=fp)
    print(file=fp)
    print("static const char* _Py_stdlib_module_names[] = {", file=fp)
    for name in sorted(names):
        print(f'"{name}",', file=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)

    fp = sys.stdout
    names = list_modules()
    write_modules(fp, names)


if __name__ == "__main__":
    main()