aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Doc/library/sys.rst22
-rw-r--r--Doc/whatsnew/3.10.rst4
-rw-r--r--Lib/test/test_capi.py17
-rw-r--r--Lib/test/test_faulthandler.py8
-rw-r--r--Lib/test/test_sys.py5
-rw-r--r--Misc/NEWS.d/next/Library/2021-01-18-11-59-46.bpo-42955.CSWLC9.rst2
-rw-r--r--Python/module_names.h295
-rw-r--r--Python/pylifecycle.c59
-rw-r--r--Python/sysmodule.c62
-rw-r--r--Tools/scripts/generate_module_names.py102
10 files changed, 303 insertions, 273 deletions
diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst
index 0f13adcf0e5..d536fc9322e 100644
--- a/Doc/library/sys.rst
+++ b/Doc/library/sys.rst
@@ -153,10 +153,12 @@ always available.
.. data:: builtin_module_names
- A tuple of strings giving the names of all modules that are compiled into this
+ A tuple of strings containing the names of all modules that are compiled into this
Python interpreter. (This information is not available in any other way ---
``modules.keys()`` only lists the imported modules.)
+ See also the :attr:`sys.module_names` list.
+
.. function:: call_tracing(func, args)
@@ -1060,6 +1062,24 @@ always available.
This is still called as a fallback if a :data:`meta_path` entry doesn't
have a :meth:`~importlib.abc.MetaPathFinder.find_spec` method.
+.. data:: module_names
+
+ A frozenset of strings containing the names of standard library modules.
+
+ It is the same on all platforms. Modules which are not available on
+ some platforms and modules disabled at Python build are also listed.
+ All module kinds are listed: pure Python, built-in, frozen and extension
+ modules. Test modules are excluded.
+
+ For packages, only sub-packages are listed, not sub-modules. For example,
+ ``concurrent`` package and ``concurrent.futures`` sub-package are listed,
+ but not ``concurrent.futures.base`` sub-module.
+
+ See also the :attr:`sys.builtin_module_names` list.
+
+ .. versionchanged:: 3.10
+
+
.. data:: modules
This is a dictionary that maps module names to modules which have already been
diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst
index d822dda09d2..a6c3fbbff91 100644
--- a/Doc/whatsnew/3.10.rst
+++ b/Doc/whatsnew/3.10.rst
@@ -396,6 +396,10 @@ Add :data:`sys.orig_argv` attribute: the list of the original command line
arguments passed to the Python executable.
(Contributed by Victor Stinner in :issue:`23427`.)
+Add :data:`sys.module_names`, containing the list of the standard library
+module names.
+(Contributed by Victor Stinner in :issue:`42955`.)
+
threading
---------
diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py
index 67175cd044a..5f5c0d038d9 100644
--- a/Lib/test/test_capi.py
+++ b/Lib/test/test_capi.py
@@ -569,12 +569,23 @@ class CAPITest(unittest.TestCase):
self.assertEqual(len(modules), total)
def test_fatal_error(self):
+ # By default, stdlib extension modules are ignored,
+ # but not test modules.
expected = ('_testcapi',)
- not_expected = ('sys', 'builtins', '_imp', '_thread', '_weakref',
- '_io', 'marshal', '_signal', '_abc')
- code = 'import _testcapi; _testcapi.fatal_error(b"MESSAGE")'
+ not_expected = ('sys',)
+ code = 'import _testcapi, sys; _testcapi.fatal_error(b"MESSAGE")'
self.check_fatal_error(code, expected, not_expected)
+ # Mark _testcapi as stdlib module, but not sys
+ expected = ('sys',)
+ not_expected = ('_testcapi',)
+ code = textwrap.dedent('''
+ import _testcapi, sys
+ sys.module_names = frozenset({"_testcapi"})
+ _testcapi.fatal_error(b"MESSAGE")
+ ''')
+ self.check_fatal_error(code, expected)
+
class TestPendingCalls(unittest.TestCase):
diff --git a/Lib/test/test_faulthandler.py b/Lib/test/test_faulthandler.py
index b4a654f8a9c..02077a69bb4 100644
--- a/Lib/test/test_faulthandler.py
+++ b/Lib/test/test_faulthandler.py
@@ -334,8 +334,9 @@ class FaultHandlerTests(unittest.TestCase):
def test_dump_ext_modules(self):
code = """
import faulthandler
- # _testcapi is a test module and not considered as a stdlib module
- import _testcapi
+ import sys
+ # Don't filter stdlib module names
+ sys.module_names = frozenset()
faulthandler.enable()
faulthandler._sigsegv()
"""
@@ -346,7 +347,8 @@ class FaultHandlerTests(unittest.TestCase):
if not match:
self.fail(f"Cannot find 'Extension modules:' in {stderr!r}")
modules = set(match.group(1).strip().split(', '))
- self.assertIn('_testcapi', modules)
+ for name in ('sys', 'faulthandler'):
+ self.assertIn(name, modules)
def test_is_enabled(self):
orig_stderr = sys.stderr
diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py
index 3af5b117aff..729b8667fc8 100644
--- a/Lib/test/test_sys.py
+++ b/Lib/test/test_sys.py
@@ -986,6 +986,11 @@ class SysModuleTest(unittest.TestCase):
self.assertEqual(proc.stdout.rstrip().splitlines(), expected,
proc)
+ def test_module_names(self):
+ self.assertIsInstance(sys.module_names, frozenset)
+ for name in sys.module_names:
+ self.assertIsInstance(name, str)
+
@test.support.cpython_only
class UnraisableHookTest(unittest.TestCase):
diff --git a/Misc/NEWS.d/next/Library/2021-01-18-11-59-46.bpo-42955.CSWLC9.rst b/Misc/NEWS.d/next/Library/2021-01-18-11-59-46.bpo-42955.CSWLC9.rst
new file mode 100644
index 00000000000..0631acd7a98
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2021-01-18-11-59-46.bpo-42955.CSWLC9.rst
@@ -0,0 +1,2 @@
+Add :data:`sys.module_names`, containing the list of the standard library
+module names. Patch by Victor Stinner.
diff --git a/Python/module_names.h b/Python/module_names.h
index 533a73260ef..0dc2633916d 100644
--- a/Python/module_names.h
+++ b/Python/module_names.h
@@ -1,63 +1,123 @@
// Auto-generated by Tools/scripts/generate_module_names.py.
+// List used to create sys.module_names.
static const char* _Py_module_names[] = {
-
-// Built-in modules
+"__future__",
"_abc",
+"_aix_support",
"_ast",
+"_asyncio",
+"_bisect",
+"_blake2",
+"_bootsubprocess",
+"_bz2",
"_codecs",
+"_codecs_cn",
+"_codecs_hk",
+"_codecs_iso2022",
+"_codecs_jp",
+"_codecs_kr",
+"_codecs_tw",
"_collections",
+"_collections_abc",
+"_compat_pickle",
+"_compression",
+"_contextvars",
+"_crypt",
+"_csv",
+"_ctypes",
+"_curses",
+"_curses_panel",
+"_datetime",
+"_dbm",
+"_decimal",
+"_elementtree",
"_functools",
+"_gdbm",
+"_hashlib",
+"_heapq",
"_imp",
"_io",
+"_json",
"_locale",
+"_lsprof",
+"_lzma",
+"_markupbase",
+"_md5",
+"_msi",
+"_multibytecodec",
+"_multiprocessing",
+"_opcode",
"_operator",
+"_osx_support",
+"_pickle",
+"_posixshmem",
+"_posixsubprocess",
+"_py_abc",
+"_pydecimal",
+"_pyio",
+"_queue",
+"_random",
+"_sha1",
+"_sha256",
+"_sha3",
+"_sha512",
"_signal",
+"_sitebuiltins",
+"_socket",
+"_sqlite3",
"_sre",
+"_ssl",
"_stat",
+"_statistics",
"_string",
+"_strptime",
+"_struct",
"_symtable",
"_thread",
+"_threading_local",
+"_tkinter",
"_tracemalloc",
+"_uuid",
"_warnings",
"_weakref",
-"atexit",
-"builtins",
-"errno",
-"faulthandler",
-"gc",
-"itertools",
-"marshal",
-"posix",
-"pwd",
-"sys",
-"time",
-
-// Pure Python modules (Lib/*.py)
-"__future__",
+"_weakrefset",
+"_winapi",
+"_xxsubinterpreters",
+"_zoneinfo",
"abc",
"aifc",
"antigravity",
"argparse",
+"array",
"ast",
"asynchat",
+"asyncio",
"asyncore",
+"atexit",
+"audioop",
"base64",
"bdb",
+"binascii",
"binhex",
"bisect",
+"builtins",
"bz2",
"cProfile",
"calendar",
"cgi",
"cgitb",
"chunk",
+"cmath",
"cmd",
"code",
"codecs",
"codeop",
+"collections",
"colorsys",
"compileall",
+"concurrent",
+"concurrent.futures",
"configparser",
"contextlib",
"contextvars",
@@ -65,45 +125,80 @@ static const char* _Py_module_names[] = {
"copyreg",
"crypt",
"csv",
+"ctypes",
+"ctypes.macholib",
+"curses",
"dataclasses",
"datetime",
+"dbm",
"decimal",
"difflib",
"dis",
+"distutils",
+"distutils.command",
"doctest",
+"email",
+"email.mime",
+"encodings",
+"ensurepip",
+"ensurepip._bundled",
"enum",
+"errno",
+"faulthandler",
+"fcntl",
"filecmp",
"fileinput",
"fnmatch",
"fractions",
"ftplib",
"functools",
+"gc",
"genericpath",
"getopt",
"getpass",
"gettext",
"glob",
"graphlib",
+"grp",
"gzip",
"hashlib",
"heapq",
"hmac",
+"html",
+"http",
+"idlelib",
"imaplib",
"imghdr",
"imp",
+"importlib",
"inspect",
"io",
"ipaddress",
+"itertools",
+"json",
"keyword",
+"lib2to3",
+"lib2to3.fixes",
+"lib2to3.pgen2",
"linecache",
"locale",
+"logging",
"lzma",
"mailbox",
"mailcap",
+"marshal",
+"math",
"mimetypes",
+"mmap",
"modulefinder",
+"msilib",
+"msvcrt",
+"multiprocessing",
+"multiprocessing.dummy",
"netrc",
+"nis",
"nntplib",
+"nt",
"ntpath",
"nturl2path",
"numbers",
@@ -111,6 +206,7 @@ static const char* _Py_module_names[] = {
"operator",
"optparse",
"os",
+"ossaudiodev",
"pathlib",
"pdb",
"pickle",
@@ -120,23 +216,30 @@ static const char* _Py_module_names[] = {
"platform",
"plistlib",
"poplib",
+"posix",
"posixpath",
"pprint",
"profile",
"pstats",
"pty",
+"pwd",
"py_compile",
"pyclbr",
"pydoc",
+"pydoc_data",
+"pyexpat",
"queue",
"quopri",
"random",
"re",
+"readline",
"reprlib",
+"resource",
"rlcompleter",
"runpy",
"sched",
"secrets",
+"select",
"selectors",
"shelve",
"shlex",
@@ -148,6 +251,8 @@ static const char* _Py_module_names[] = {
"sndhdr",
"socket",
"socketserver",
+"spwd",
+"sqlite3",
"sre_compile",
"sre_constants",
"sre_parse",
@@ -160,15 +265,20 @@ static const char* _Py_module_names[] = {
"subprocess",
"sunau",
"symtable",
+"sys",
"sysconfig",
+"syslog",
"tabnanny",
"tarfile",
"telnetlib",
"tempfile",
+"termios",
"textwrap",
"this",
"threading",
+"time",
"timeit",
+"tkinter",
"token",
"tokenize",
"trace",
@@ -176,161 +286,32 @@ static const char* _Py_module_names[] = {
"tracemalloc",
"tty",
"turtle",
+"turtledemo",
"types",
"typing",
+"unicodedata",
+"unittest",
+"urllib",
"uu",
"uuid",
+"venv",
"warnings",
"wave",
"weakref",
"webbrowser",
-"xdrlib",
-"zipapp",
-"zipfile",
-"zipimport",
-
-// Packages and sub-packages
-"asyncio",
-"collections",
-"concurrent",
-"concurrent.futures",
-"ctypes",
-"ctypes.macholib",
-"curses",
-"dbm",
-"distutils",
-"distutils.command",
-"email",
-"email.mime",
-"encodings",
-"ensurepip",
-"ensurepip._bundled",
-"html",
-"http",
-"idlelib",
-"importlib",
-"json",
-"lib2to3",
-"lib2to3.fixes",
-"lib2to3.pgen2",
-"logging",
-"msilib",
-"multiprocessing",
-"multiprocessing.dummy",
-"pydoc_data",
-"sqlite3",
-"tkinter",
-"turtledemo",
-"unittest",
-"urllib",
-"venv",
+"winreg",
+"winsound",
"wsgiref",
+"xdrlib",
"xml",
"xml.dom",
"xml.etree",
"xml.parsers",
"xml.sax",
"xmlrpc",
-"zoneinfo",
-
-// Extension modules built by setup.py
-"_asyncio",
-"_bisect",
-"_blake2",
-"_bz2",
-"_codecs_cn",
-"_codecs_hk",
-"_codecs_iso2022",
-"_codecs_jp",
-"_codecs_kr",
-"_codecs_tw",
-"_contextvars",
-"_crypt",
-"_csv",
-"_ctypes",
-"_curses",
-"_curses_panel",
-"_datetime",
-"_dbm",
-"_decimal",
-"_elementtree",
-"_gdbm",
-"_hashlib",
-"_heapq",
-"_json",
-"_lsprof",
-"_lzma",
-"_md5",
-"_multibytecodec",
-"_multiprocessing",
-"_opcode",
-"_pickle",
-"_posixshmem",
-"_posixsubprocess",
-"_queue",
-"_random",
-"_sha1",
-"_sha256",
-"_sha3",
-"_sha512",
-"_socket",
-"_sqlite3",
-"_ssl",
-"_statistics",
-"_struct",
-"_tkinter",
-"_uuid",
-"_xxsubinterpreters",
-"_zoneinfo",
-"array",
-"audioop",
-"binascii",
-"cmath",
-"fcntl",
-"grp",
-"math",
-"mmap",
-"nis",
-"ossaudiodev",
-"pyexpat",
-"readline",
-"resource",
-"select",
-"spwd",
-"syslog",
-"termios",
-"unicodedata",
+"zipapp",
+"zipfile",
+"zipimport",
"zlib",
-
-// Built-in and extension modules built by Modules/Setup
-"_abc",
-"_codecs",
-"_collections",
-"_functools",
-"_io",
-"_locale",
-"_operator",
-"_signal",
-"_sre",
-"_stat",
-"_symtable",
-"_thread",
-"_tracemalloc",
-"_weakref",
-"atexit",
-"errno",
-"faulthandler",
-"itertools",
-"posix",
-"pwd",
-"time",
-
-// Windows extension modules
-"_msi",
-"_winapi",
-"msvcrt",
-"nt",
-"winreg",
-"winsound",
-
+"zoneinfo",
};
diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c
index e9df8fb5d27..a97f45d0d5d 100644
--- a/Python/pylifecycle.c
+++ b/Python/pylifecycle.c
@@ -18,8 +18,6 @@
#include "pycore_sysmodule.h" // _PySys_ClearAuditHooks()
#include "pycore_traceback.h" // _Py_DumpTracebackThreads()
-#include "module_names.h" // _Py_module_names
-
#include <locale.h> // setlocale()
#ifdef HAVE_SIGNAL_H
@@ -2499,7 +2497,7 @@ fatal_error_exit(int status)
// Dump the list of extension modules of sys.modules, excluding stdlib modules
-// (_Py_module_names), into fd file descriptor.
+// (sys.module_names), into fd file descriptor.
//
// This function is called by a signal handler in faulthandler: avoid memory
// allocations and keep the implementation simple. For example, the list is not
@@ -2515,10 +2513,31 @@ _Py_DumpExtensionModules(int fd, PyInterpreterState *interp)
return;
}
+ Py_ssize_t pos;
+ PyObject *key, *value;
+
+ // Avoid PyDict_GetItemString() which calls PyUnicode_FromString(),
+ // memory cannot be allocated on the heap in a signal handler.
+ // Iterate on the dict instead.
+ PyObject *module_names = NULL;
+ pos = 0;
+ while (PyDict_Next(interp->sysdict, &pos, &key, &value)) {
+ if (PyUnicode_Check(key)
+ && PyUnicode_CompareWithASCIIString(key, "module_names") == 0) {
+ module_names = value;
+ break;
+ }
+ }
+ // If we failed to get sys.module_names or it's not a frozenset,
+ // don't exclude stdlib modules.
+ if (module_names != NULL && !PyFrozenSet_Check(module_names)) {
+ module_names = NULL;
+ }
+
+ // List extensions
int header = 1;
Py_ssize_t count = 0;
- Py_ssize_t pos = 0;
- PyObject *key, *value;
+ pos = 0;
while (PyDict_Next(modules, &pos, &key, &value)) {
if (!PyUnicode_Check(key)) {
continue;
@@ -2526,22 +2545,26 @@ _Py_DumpExtensionModules(int fd, PyInterpreterState *interp)
if (!_PyModule_IsExtension(value)) {
continue;
}
-
- // Check if it is a stdlib extension module.
// Use the module name from the sys.modules key,
// don't attempt to get the module object name.
- const Py_ssize_t names_len = Py_ARRAY_LENGTH(_Py_module_names);
- int is_stdlib_mod = 0;
- for (Py_ssize_t i=0; i < names_len; i++) {
- const char *name = _Py_module_names[i];
- if (PyUnicode_CompareWithASCIIString(key, name) == 0) {
- is_stdlib_mod = 1;
- break;
+ if (module_names != NULL) {
+ int is_stdlib_ext = 0;
+
+ Py_ssize_t i;
+ PyObject *item;
+ Py_hash_t hash;
+ for (i=0; _PySet_NextEntry(module_names, &i, &item, &hash); ) {
+ if (PyUnicode_Check(item)
+ && PyUnicode_Compare(key, item) == 0)
+ {
+ is_stdlib_ext = 1;
+ break;
+ }
+ }
+ if (is_stdlib_ext) {
+ // Ignore stdlib extension
+ continue;
}
- }
- if (is_stdlib_mod) {
- // Ignore stdlib extension module.
- continue;
}
if (header) {
diff --git a/Python/sysmodule.c b/Python/sysmodule.c
index 720532eade2..e2f7e39f333 100644
--- a/Python/sysmodule.c
+++ b/Python/sysmodule.c
@@ -29,6 +29,7 @@ Data members:
#include "frameobject.h" // PyFrame_GetBack()
#include "pydtrace.h"
#include "osdefs.h" // DELIM
+#include "module_names.h" // _Py_module_names
#include <locale.h>
#ifdef MS_WINDOWS
@@ -2020,33 +2021,63 @@ static PyMethodDef sys_methods[] = {
{NULL, NULL} /* sentinel */
};
+
static PyObject *
list_builtin_module_names(void)
{
PyObject *list = PyList_New(0);
- int i;
- if (list == NULL)
+ if (list == NULL) {
return NULL;
- for (i = 0; PyImport_Inittab[i].name != NULL; i++) {
- PyObject *name = PyUnicode_FromString(
- PyImport_Inittab[i].name);
- if (name == NULL)
- break;
- PyList_Append(list, name);
+ }
+ for (Py_ssize_t i = 0; PyImport_Inittab[i].name != NULL; i++) {
+ PyObject *name = PyUnicode_FromString(PyImport_Inittab[i].name);
+ if (name == NULL) {
+ goto error;
+ }
+ if (PyList_Append(list, name) < 0) {
+ Py_DECREF(name);
+ goto error;
+ }
Py_DECREF(name);
}
if (PyList_Sort(list) != 0) {
- Py_DECREF(list);
- list = NULL;
+ goto error;
+ }
+ PyObject *tuple = PyList_AsTuple(list);
+ Py_DECREF(list);
+ return tuple;
+
+error:
+ Py_DECREF(list);
+ return NULL;
+}
+
+
+static PyObject *
+list_module_names(void)
+{
+ Py_ssize_t len = Py_ARRAY_LENGTH(_Py_module_names);
+ PyObject *names = PyTuple_New(len);
+ if (names == NULL) {
+ return NULL;
}
- if (list) {
- PyObject *v = PyList_AsTuple(list);
- Py_DECREF(list);
- list = v;
+
+ for (Py_ssize_t i = 0; i < len; i++) {
+ PyObject *name = PyUnicode_FromString(_Py_module_names[i]);
+ if (name == NULL) {
+ Py_DECREF(names);
+ return NULL;
+ }
+ PyTuple_SET_ITEM(names, i, name);
}
- return list;
+
+ PyObject *set = PyObject_CallFunction((PyObject *)&PyFrozenSet_Type,
+ "(O)", names);
+ Py_DECREF(names);
+ return set;
}
+
/* Pre-initialization support for sys.warnoptions and sys._xoptions
*
* Modern internal code paths:
@@ -2753,6 +2784,7 @@ _PySys_InitCore(PyThreadState *tstate, PyObject *sysdict)
SET_SYS("hash_info", get_hash_info(tstate));
SET_SYS("maxunicode", PyLong_FromLong(0x10FFFF));
SET_SYS("builtin_module_names", list_builtin_module_names());
+ SET_SYS("module_names", list_module_names());
#if PY_BIG_ENDIAN
SET_SYS_FROM_STRING("byteorder", "big");
#else
diff --git a/Tools/scripts/generate_module_names.py b/Tools/scripts/generate_module_names.py
index 985a1a5e5a2..9d363aa04b3 100644
--- a/Tools/scripts/generate_module_names.py
+++ b/Tools/scripts/generate_module_names.py
@@ -17,27 +17,6 @@ IGNORE = {
'__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',
@@ -69,40 +48,20 @@ WINDOWS_MODULES = (
)
-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 = []
+def list_python_modules(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)
+ names.add(name)
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
+ package_path = os.path.join(path, name)
if not os.path.isdir(package_path):
continue
if not any(package_file.endswith(".py")
@@ -114,40 +73,28 @@ def _list_sub_packages(path, names, parent=None):
qualname = name
if qualname in IGNORE:
continue
- names.append(qualname)
+ names.add(qualname)
_list_sub_packages(package_path, names, qualname)
# Packages and sub-packages
-def list_packages(fp):
- write_comment(fp, "Packages and sub-packages")
- names = []
+def list_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):
+def list_setup_extensions(names):
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)
+ extensions = output.splitlines()
+ names |= set(extensions)
# Built-in and extension modules built by Modules/Setup
-def list_modules_setup(fp):
+def list_modules_setup_extensions(names):
assign_var = re.compile("^[A-Z]+=")
- names = []
with open(MODULES_SETUP, encoding="utf-8") as modules_fp:
for line in modules_fp:
# Strip comment
@@ -165,25 +112,26 @@ def list_modules_setup(fp):
continue
# "errno errnomodule.c" => write "errno"
name = parts[0]
- names.append(name)
+ names.add(name)
- write_comment(fp, "Built-in and extension modules built by Modules/Setup")
- write_modules(fp, names)
+
+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)
+ names -= set(IGNORE)
+ return names
-def list_modules(fp):
+def write_modules(fp, names):
print("// Auto-generated by Tools/scripts/generate_module_names.py.", file=fp)
+ print("// List used to create sys.module_names.", 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)
-
+ for name in sorted(names):
+ print(f'"{name}",', file=fp)
print("};", file=fp)
@@ -193,7 +141,9 @@ def main():
file=sys.stderr)
sys.exit(1)
- list_modules(sys.stdout)
+ fp = sys.stdout
+ names = list_modules()
+ write_modules(fp, names)
if __name__ == "__main__":