File tree Expand file tree Collapse file tree
Lib/test/test_lazy_import Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -1349,6 +1349,25 @@ def test_initializing_module_is_still_tracked(self):
13491349 """)
13501350 assert_python_ok("-c", code)
13511351
1352+ def test_module_spec_descriptor_is_not_run(self):
1353+ """Checking whether a module is loaded must not run its descriptors."""
1354+ code = textwrap.dedent("""
1355+ import sys
1356+ import types
1357+
1358+ class RaisingSpec(types.ModuleType):
1359+ @property
1360+ def __spec__(self):
1361+ raise RuntimeError("__spec__ descriptor was run")
1362+
1363+ sys.modules["raising_spec"] = RaisingSpec("raising_spec")
1364+ lazy import raising_spec
1365+ assert "raising_spec" not in sys.lazy_modules, (
1366+ f"expected 'raising_spec' untracked, got {sys.lazy_modules}"
1367+ )
1368+ """)
1369+ assert_python_ok("-c", code)
1370+
13521371 def test_pending_submodule_is_still_tracked(self):
13531372 """`lazy from` a submodule that is not loaded must stay tracked."""
13541373 code = textwrap.dedent("""
Original file line number Diff line number Diff line change @@ -4370,10 +4370,12 @@ lazy_modules_add(PyThreadState *tstate, PyObject *name)
43704370 }
43714371 // A None entry blocks the import rather than satisfying it.
43724372 int loaded = (existing != NULL && existing != Py_None);
4373- if (loaded) {
4374- // Check if the module is still initializing.
4373+ if (loaded && PyModule_Check(existing)) {
4374+ // Check if the module is still initializing. Read __spec__ from the
4375+ // module dict so that a descriptor on a module subclass is not run.
43754376 PyObject *spec;
4376- int rc = PyObject_GetOptionalAttr(existing, &_Py_ID(__spec__), &spec);
4377+ int rc = PyDict_GetItemRef(_PyModule_GetDict(existing),
4378+ &_Py_ID(__spec__), &spec);
43774379 if (rc > 0) {
43784380 rc = _PyModuleSpec_IsInitializing(spec);
43794381 Py_DECREF(spec);
You can’t perform that action at this time.
0 commit comments