Skip to content

bpo-42955: Add sys.modules_names #24238

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion Doc/library/sys.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions Doc/whatsnew/3.10.rst
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,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
---------

Expand Down
17 changes: 14 additions & 3 deletions Lib/test/test_capi.py
Original file line number Diff line number Diff line change
Expand Up @@ -569,12 +569,23 @@ def check_fatal_error(self, code, expected, not_expected=()):
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):

Expand Down
8 changes: 5 additions & 3 deletions Lib/test/test_faulthandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -334,8 +334,9 @@ def test_disable(self):
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()
"""
Expand All @@ -346,7 +347,8 @@ def test_dump_ext_modules(self):
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
Expand Down
5 changes: 5 additions & 0 deletions Lib/test/test_sys.py
Original file line number Diff line number Diff line change
Expand Up @@ -986,6 +986,11 @@ def test_orig_argv(self):
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):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Add :data:`sys.module_names`, containing the list of the standard library
module names. Patch by Victor Stinner.
Loading