Skip to content

Commit 374d85f

Browse files
committed
Read __spec__ from the module dict when checking for initialization
1 parent f9f430a commit 374d85f

2 files changed

Lines changed: 24 additions & 3 deletions

File tree

‎Lib/test/test_lazy_import/__init__.py‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff 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("""

‎Python/import.c‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff 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);

0 commit comments

Comments
 (0)