https://github.com/python/cpython/commit/a6a63b6f5b5e4b921dd98ca8eeea90bca3519814
commit: a6a63b6f5b5e4b921dd98ca8eeea90bca3519814
branch: main
author: Pablo Galindo Salgado <[email protected]>
committer: hugovk <[email protected]>
date: 2026-10-01T16:20:45Z
summary:

gh-142349: Simplify lazy import resolution (#158282)

Co-authored-by: Petr Viktorin <[email protected]>
Co-authored-by: Hugo van Kemenade <[email protected]>

files:
A Lib/test/test_lazy_import/data/broken_module_chained_cause.py
A Lib/test/test_lazy_import/data/broken_module_chained_context.py
A Lib/test/test_lazy_import/data/broken_module_chained_suppressed.py
M Include/internal/pycore_dict.h
M Include/internal/pycore_import.h
M Include/internal/pycore_interp_structs.h
M Include/internal/pycore_lazyimportobject.h
M Include/internal/pycore_opcode_metadata.h
M Include/internal/pycore_tstate.h
M Include/internal/pycore_uop_metadata.h
M Lib/test/test_lazy_import/__init__.py
M Modules/_testinternalcapi/test_cases.c.h
M Objects/dictobject.c
M Objects/lazyimportobject.c
M Objects/moduleobject.c
M Python/bytecodes.c
M Python/ceval.c
M Python/clinic/import.c.h
M Python/executor_cases.c.h
M Python/generated_cases.c.h
M Python/import.c
M Python/optimizer_cases.c.h
M Python/pystate.c

diff --git a/Include/internal/pycore_dict.h b/Include/internal/pycore_dict.h
index 7032b61d7654b89..81f1de3a5be8650 100644
--- a/Include/internal/pycore_dict.h
+++ b/Include/internal/pycore_dict.h
@@ -23,6 +23,11 @@ PyAPI_FUNC(int) _PyDict_DelItemIf(PyObject *mp, PyObject 
*key,
                                   int (*predicate)(PyObject *value, void *arg),
                                   void *arg);
 
+// Atomically replace an existing value if it is expected (by identity).
+// Return 1 if replaced, 0 if absent or different, or -1 on error.
+extern int _PyDict_ReplaceItemIf(PyObject *dict, PyObject *key,
+                               PyObject *expected, PyObject *replacement);
+
 // "KnownHash" variants
 // Export for '_asyncio' shared extension
 PyAPI_FUNC(int) _PyDict_SetItem_KnownHash(PyObject *mp, PyObject *key,
@@ -147,8 +152,8 @@ PyAPI_FUNC(Py_ssize_t) 
_PyDictKeys_StringLookup(PyDictKeysObject* dictkeys, PyOb
  */
 PyAPI_FUNC(Py_ssize_t) _PyDictKeys_StringLookupAndVersion(PyDictKeysObject* 
dictkeys, PyObject *key, uint32_t *version);
 PyAPI_FUNC(Py_ssize_t) _PyDictKeys_StringLookupSplit(PyDictKeysObject* 
dictkeys, PyObject *key);
-PyAPI_FUNC(PyObject *)_PyDict_LoadGlobal(PyDictObject *, PyDictObject *, 
PyObject *);
-PyAPI_FUNC(void) _PyDict_LoadGlobalStackRef(PyDictObject *, PyDictObject *, 
PyObject *, _PyStackRef *);
+// Return the borrowed source dictionary, or NULL if absent or on error.
+PyAPI_FUNC(PyObject *) _PyDict_LoadGlobalStackRef(PyDictObject *, PyDictObject 
*, PyObject *, _PyStackRef *);
 
 // Loads the __builtins__ object from the globals dict. Returns a new 
reference.
 extern PyObject *_PyDict_LoadBuiltinsFromGlobals(PyObject *globals);
diff --git a/Include/internal/pycore_import.h b/Include/internal/pycore_import.h
index 669e328c266d00f..81448e23787fb39 100644
--- a/Include/internal/pycore_import.h
+++ b/Include/internal/pycore_import.h
@@ -32,20 +32,16 @@ extern int _PyImport_FixupBuiltin(
     PyObject *modules
     );
 
-extern PyObject * _PyImport_ResolveName(
-    PyThreadState *tstate, PyObject *name, PyObject *globals, int level);
 extern PyObject * _PyImport_GetAbsName(
     PyThreadState *tstate, PyObject *name, PyObject *globals, int level);
 // Symbol is exported for the JIT on Windows builds.
 PyAPI_FUNC(PyObject *) _PyImport_LoadLazyImportTstate(
     PyThreadState *tstate, PyObject *lazy_import);
-typedef enum {
-    _Py_LAZY_SUBMODULE_ERROR = -1,
-    _Py_LAZY_SUBMODULE_NOT_FOUND = 0,
-    _Py_LAZY_SUBMODULE_LOADED = 1,
-} _PyLazySubmoduleImportResult;
-extern _PyLazySubmoduleImportResult _PyImport_TryLoadLazySubmodule(
-    PyObject *mod_name, PyObject *attr_name, PyObject **result);
+// Bind a pending child on module before removing its registration. Return a
+// new reference, NULL without an exception if absent, or NULL on error.
+// Set recheck_dict if a concurrent lookup may have already bound the child.
+extern PyObject * _PyImport_TryLoadLazySubmodule(
+    PyObject *module, PyObject *attr_name, int *recheck_dict);
 extern PyObject * _PyImport_LazyImportModuleLevelObject(
     PyThreadState *tstate, PyObject *name, PyObject *builtins,
     PyObject *globals, PyObject *locals, PyObject *fromlist, int level);
diff --git a/Include/internal/pycore_interp_structs.h 
b/Include/internal/pycore_interp_structs.h
index 6c907e0cf79894d..a9c61ea6db3a8c4 100644
--- a/Include/internal/pycore_interp_structs.h
+++ b/Include/internal/pycore_interp_structs.h
@@ -352,15 +352,12 @@ struct _import_state {
     PyObject *lazy_import_func;
     int lazy_imports_mode;
     PyObject *lazy_imports_filter;
-    PyObject *lazy_importing_modules;
     // The set stored in sys.lazy_modules if values that have been
     // lazily imported. This value is only for debugging/introspection
     // purposes and is not used by the runtime.
     PyObject *lazy_modules;
     // A dict mapping package names to a set of submodule names that
-    // have been imported lazily from packages which have been imported
-    // lazily. When the package is reified we need to add a
-    // LazyImportObject which refers to the submodule on the module.
+    // may need to be imported when an attribute is missing on the package.
     PyObject *lazy_pending_submodules;
 #ifdef Py_GIL_DISABLED
     PyMutex lazy_mutex;
diff --git a/Include/internal/pycore_lazyimportobject.h 
b/Include/internal/pycore_lazyimportobject.h
index b81e4211b08ff39..c3f8417c0893166 100644
--- a/Include/internal/pycore_lazyimportobject.h
+++ b/Include/internal/pycore_lazyimportobject.h
@@ -14,20 +14,18 @@ extern "C" {
 PyAPI_DATA(PyTypeObject) PyLazyImport_Type;
 #define PyLazyImport_CheckExact(op) Py_IS_TYPE((op), &PyLazyImport_Type)
 
-typedef struct {
-    PyObject_HEAD
-    PyObject *lz_builtins;
-    PyObject *lz_from;
-    PyObject *lz_attr;
-    // Frame information for the original import location.
-    PyCodeObject *lz_code;     // Code object where the lazy import was 
created.
-    int lz_instr_offset;       // Instruction offset where the lazy import was 
created.
-} PyLazyImportObject;
-
-
-PyAPI_FUNC(PyObject *) _PyLazyImport_GetName(PyObject *lazy_import);
 PyAPI_FUNC(PyObject *) _PyLazyImport_New(
-    struct _PyInterpreterFrame *frame, PyObject *import_func, PyObject *from, 
PyObject *attr);
+    struct _PyInterpreterFrame *frame, PyObject *builtins,
+    PyObject *name, PyObject *fromlist);
+
+extern int _PyLazyImport_IsResolving(PyThreadState *tstate, PyObject *op);
+
+// Resolve a placeholder and replace its binding if it is unchanged or holds
+// the child module published by the normal importer during resolution.
+// namespace is the source captured during lookup, before resolution runs.
+PyAPI_FUNC(PyObject *) _PyLazyImport_Reify(
+    PyThreadState *tstate, PyObject *placeholder,
+    PyObject *name, PyObject *ns);
 
 #ifdef __cplusplus
 }
diff --git a/Include/internal/pycore_opcode_metadata.h 
b/Include/internal/pycore_opcode_metadata.h
index 38bccdd48c0f862..d3546119bc9ee0e 100644
--- a/Include/internal/pycore_opcode_metadata.h
+++ b/Include/internal/pycore_opcode_metadata.h
@@ -1253,7 +1253,7 @@ const struct opcode_metadata 
_PyOpcode_opcode_metadata[267] = {
     [LOAD_FAST_CHECK] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG | 
HAS_ERROR_FLAG },
     [LOAD_FAST_LOAD_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | 
HAS_LOCAL_FLAG },
     [LOAD_FROM_DICT_OR_DEREF] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | 
HAS_FREE_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG },
-    [LOAD_FROM_DICT_OR_GLOBALS] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | 
HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG },
+    [LOAD_FROM_DICT_OR_GLOBALS] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | 
HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
     [LOAD_GLOBAL] = { true, INSTR_FMT_IBC000, HAS_ARG_FLAG | HAS_NAME_FLAG | 
HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
     [LOAD_GLOBAL_BUILTIN] = { true, INSTR_FMT_IBC000, HAS_ARG_FLAG | 
HAS_DEOPT_FLAG },
     [LOAD_GLOBAL_MODULE] = { true, INSTR_FMT_IBC000, HAS_ARG_FLAG | 
HAS_DEOPT_FLAG },
@@ -1476,6 +1476,7 @@ _PyOpcode_macro_expansion[256] = {
     [LOAD_FAST_CHECK] = { .nuops = 1, .uops = { { _LOAD_FAST_CHECK, 
OPARG_SIMPLE, 0 } } },
     [LOAD_FAST_LOAD_FAST] = { .nuops = 2, .uops = { { _LOAD_FAST, OPARG_TOP, 0 
}, { _LOAD_FAST, OPARG_BOTTOM, 0 } } },
     [LOAD_FROM_DICT_OR_DEREF] = { .nuops = 1, .uops = { { 
_LOAD_FROM_DICT_OR_DEREF, OPARG_SIMPLE, 0 } } },
+    [LOAD_FROM_DICT_OR_GLOBALS] = { .nuops = 1, .uops = { { 
_LOAD_FROM_DICT_OR_GLOBALS, OPARG_SIMPLE, 0 } } },
     [LOAD_GLOBAL] = { .nuops = 2, .uops = { { _LOAD_GLOBAL, OPARG_SIMPLE, 3 }, 
{ _PUSH_NULL_CONDITIONAL, OPARG_SIMPLE, 3 } } },
     [LOAD_GLOBAL_BUILTIN] = { .nuops = 4, .uops = { { _GUARD_GLOBALS_VERSION, 
1, 1 }, { _LOAD_GLOBAL_BUILTINS, 1, 2 }, { _LOAD_GLOBAL_BUILTINS, OPERAND1_1, 3 
}, { _PUSH_NULL_CONDITIONAL, OPARG_SIMPLE, 4 } } },
     [LOAD_GLOBAL_MODULE] = { .nuops = 4, .uops = { { _NOP, OPARG_SIMPLE, 1 }, 
{ _LOAD_GLOBAL_MODULE, 1, 1 }, { _LOAD_GLOBAL_MODULE, OPERAND1_1, 3 }, { 
_PUSH_NULL_CONDITIONAL, OPARG_SIMPLE, 4 } } },
diff --git a/Include/internal/pycore_tstate.h b/Include/internal/pycore_tstate.h
index eb2b0c84acdc7c8..58dd66b69efc9da 100644
--- a/Include/internal/pycore_tstate.h
+++ b/Include/internal/pycore_tstate.h
@@ -51,6 +51,9 @@ typedef struct _PyThreadStateImpl {
     PyObject *asyncio_running_loop; // Strong reference
     PyObject *asyncio_running_task; // Strong reference
 
+    // Reused for the thread's lifetime; owns placeholders while they resolve.
+    PyObject *lazy_imports;
+
     // Distinguishes between yield and return from PyEval_EvalFrame().
     // See gen_send_ex2() in Objects/genobject.c
     enum {
diff --git a/Include/internal/pycore_uop_metadata.h 
b/Include/internal/pycore_uop_metadata.h
index 177564a75459412..86b449158f00d0d 100644
--- a/Include/internal/pycore_uop_metadata.h
+++ b/Include/internal/pycore_uop_metadata.h
@@ -190,6 +190,7 @@ const uint32_t _PyUop_Flags[MAX_UOP_ID+1] = {
     [_STORE_ATTR] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | 
HAS_ESCAPES_FLAG,
     [_STORE_GLOBAL] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | 
HAS_ESCAPES_FLAG,
     [_LOAD_LOCALS] = HAS_ERROR_FLAG,
+    [_LOAD_FROM_DICT_OR_GLOBALS] = HAS_ARG_FLAG | HAS_NAME_FLAG | 
HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
     [_LOAD_NAME] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | 
HAS_ESCAPES_FLAG,
     [_LOAD_GLOBAL] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | 
HAS_ESCAPES_FLAG,
     [_PUSH_NULL_CONDITIONAL] = HAS_ARG_FLAG,
@@ -1841,6 +1842,15 @@ const _PyUopCachingInfo _PyUop_Caching[MAX_UOP_ID+1] = {
             { -1, -1, -1 },
         },
     },
+    [_LOAD_FROM_DICT_OR_GLOBALS] = {
+        .best = { 1, 1, 1, 1 },
+        .entries = {
+            { -1, -1, -1 },
+            { 1, 1, _LOAD_FROM_DICT_OR_GLOBALS_r11 },
+            { -1, -1, -1 },
+            { -1, -1, -1 },
+        },
+    },
     [_LOAD_NAME] = {
         .best = { 0, 0, 0, 0 },
         .entries = {
@@ -4316,6 +4326,7 @@ const uint16_t _PyUop_Uncached[MAX_UOP_REGS_ID+1] = {
     [_LOAD_LOCALS_r01] = _LOAD_LOCALS,
     [_LOAD_LOCALS_r12] = _LOAD_LOCALS,
     [_LOAD_LOCALS_r23] = _LOAD_LOCALS,
+    [_LOAD_FROM_DICT_OR_GLOBALS_r11] = _LOAD_FROM_DICT_OR_GLOBALS,
     [_LOAD_NAME_r01] = _LOAD_NAME,
     [_LOAD_GLOBAL_r00] = _LOAD_GLOBAL,
     [_PUSH_NULL_CONDITIONAL_r00] = _PUSH_NULL_CONDITIONAL,
@@ -5829,6 +5840,8 @@ const char *const _PyOpcode_uop_name[MAX_UOP_REGS_ID+1] = 
{
     [_LOAD_FAST_CHECK_r23] = "_LOAD_FAST_CHECK_r23",
     [_LOAD_FROM_DICT_OR_DEREF] = "_LOAD_FROM_DICT_OR_DEREF",
     [_LOAD_FROM_DICT_OR_DEREF_r11] = "_LOAD_FROM_DICT_OR_DEREF_r11",
+    [_LOAD_FROM_DICT_OR_GLOBALS] = "_LOAD_FROM_DICT_OR_GLOBALS",
+    [_LOAD_FROM_DICT_OR_GLOBALS_r11] = "_LOAD_FROM_DICT_OR_GLOBALS_r11",
     [_LOAD_GLOBAL] = "_LOAD_GLOBAL",
     [_LOAD_GLOBAL_r00] = "_LOAD_GLOBAL_r00",
     [_LOAD_GLOBAL_BUILTINS] = "_LOAD_GLOBAL_BUILTINS",
@@ -6495,6 +6508,8 @@ int _PyUop_num_popped(int opcode, int oparg)
             return 1;
         case _LOAD_LOCALS:
             return 0;
+        case _LOAD_FROM_DICT_OR_GLOBALS:
+            return 1;
         case _LOAD_NAME:
             return 0;
         case _LOAD_GLOBAL:
diff --git a/Lib/test/test_lazy_import/__init__.py 
b/Lib/test/test_lazy_import/__init__.py
index 5026c9670d81d23..f9ef8ce2cfef8c9 100644
--- a/Lib/test/test_lazy_import/__init__.py
+++ b/Lib/test/test_lazy_import/__init__.py
@@ -13,7 +13,7 @@
 import contextlib
 
 from test import support
-from test.support.script_helper import assert_python_ok
+from test.support.script_helper import assert_python_ok, assert_python_failure
 
 try:
     import _testcapi
@@ -617,6 +617,14 @@ def test_dunder_lazy_import_invalid_arguments(self):
         with self.assertRaises(TypeError):
             __lazy_import__("sys", globals=1)
 
+        code = textwrap.dedent("""
+            __lazy_import__("sys", fromlist=(1, 2, 3))
+        """)
+        result = assert_python_failure("-c", code, NO_COLOR='y')
+        self.assertIn(
+            b"TypeError: Item in ``from list'' must be str, not int",
+            result.err)
+
     def test_dunder_lazy_import_builtins(self):
         """__lazy_import__ should use module's __builtins__ for __import__."""
         from test.test_lazy_import.data import dunder_lazy_import_builtins
@@ -766,6 +774,28 @@ def 
test_missing_lazy_from_import_shows_chained_traceback(self):
         """)
         assert_python_ok("-c", code)
 
+    @support.subTests('name', (
+        'test.test_lazy_import.data.broken_module_chained_cause',
+        'test.test_lazy_import.data.broken_module_chained_context',
+        'test.test_lazy_import.data.broken_module_chained_suppressed',
+    ))
+    def test_chained_exception_import_shows_notes(self, name):
+        """Accessing missing attribute from lazy from-import should chain 
errors."""
+        code = textwrap.dedent(f"""
+            lazy import {name}
+
+            try:
+                _ = test
+            except ValueError as e:
+                assert any(
+                    note.startswith("lazy import of '{name}' declared in ")
+                    for note in e.__notes__
+                ), e.__notes__
+            else:
+                raise AssertionError("ImportError was not raised")
+        """)
+        assert_python_ok("-c", code)
+
     def test_reification_retries_on_failure(self):
         """Failed reification should allow retry on subsequent access.
 
diff --git a/Lib/test/test_lazy_import/data/broken_module_chained_cause.py 
b/Lib/test/test_lazy_import/data/broken_module_chained_cause.py
new file mode 100644
index 000000000000000..786607b7bb557e7
--- /dev/null
+++ b/Lib/test/test_lazy_import/data/broken_module_chained_cause.py
@@ -0,0 +1,3 @@
+# Module that raises an exception with explicit cause during import
+cause = ValueError("Cause of failure")
+raise ValueError("This module always fails to import") from cause
diff --git a/Lib/test/test_lazy_import/data/broken_module_chained_context.py 
b/Lib/test/test_lazy_import/data/broken_module_chained_context.py
new file mode 100644
index 000000000000000..82640856e3e2d8a
--- /dev/null
+++ b/Lib/test/test_lazy_import/data/broken_module_chained_context.py
@@ -0,0 +1,5 @@
+# Module that raises an exception with context during import
+try:
+    raise ValueError("Cause of failure")
+except:
+    raise ValueError("This module always fails to import")
diff --git a/Lib/test/test_lazy_import/data/broken_module_chained_suppressed.py 
b/Lib/test/test_lazy_import/data/broken_module_chained_suppressed.py
new file mode 100644
index 000000000000000..5c34654afc13bf5
--- /dev/null
+++ b/Lib/test/test_lazy_import/data/broken_module_chained_suppressed.py
@@ -0,0 +1,2 @@
+# Module that raises an exception with suppressed context during import
+raise ValueError("This module always fails to import") from None
diff --git a/Modules/_testinternalcapi/test_cases.c.h 
b/Modules/_testinternalcapi/test_cases.c.h
index 19c6cb7517d6ff8..3bdc16437e2bc61 100644
--- a/Modules/_testinternalcapi/test_cases.c.h
+++ b/Modules/_testinternalcapi/test_cases.c.h
@@ -9914,6 +9914,16 @@
                     JUMP_TO_LABEL(error);
                 }
             }
+            else if (PyLazyImport_CheckExact(value_o)) {
+                assert(stack_pointer == _PyFrame_GetStackPointer(frame));
+                _PyFrame_StackPointerValidate(frame);
+                Py_SETREF(value_o, _PyLazyImport_Reify(
+                              tstate, value_o, name, class_dict));
+                _PyFrame_StackPointerInvalidate(frame);
+                if (value_o == NULL) {
+                    JUMP_TO_LABEL(error);
+                }
+            }
             stack_pointer += -1;
             ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
             _PyFrame_SetStackPointer(frame, stack_pointer);
@@ -9939,11 +9949,21 @@
             _PyStackRef v;
             mod_or_class_dict = stack_pointer[-1];
             PyObject *name = GETITEM(FRAME_CO_NAMES, oparg);
+            PyObject *namespace = 
PyStackRef_AsPyObjectBorrow(mod_or_class_dict);
             int err;
             _PyFrame_SetStackPointer(frame, stack_pointer);
             _PyFrame_StackPointerValidate(frame);
-            PyObject *v_o = 
_PyMapping_GetOptionalItem2(PyStackRef_AsPyObjectBorrow(mod_or_class_dict), 
name, &err);
+            PyObject *v_o = _PyMapping_GetOptionalItem2(namespace, name, &err);
             _PyFrame_StackPointerInvalidate(frame);
+            if (v_o != NULL && PyLazyImport_CheckExact(v_o)) {
+                assert(stack_pointer == _PyFrame_GetStackPointer(frame));
+                _PyFrame_StackPointerValidate(frame);
+                Py_SETREF(v_o, _PyLazyImport_Reify(tstate, v_o, name, 
namespace));
+                _PyFrame_StackPointerInvalidate(frame);
+                if (v_o == NULL) {
+                    err = -1;
+                }
+            }
             stack_pointer += -1;
             ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
             _PyFrame_SetStackPointer(frame, stack_pointer);
@@ -9954,81 +9974,17 @@
                 JUMP_TO_LABEL(error);
             }
             if (v_o == NULL) {
-                if (PyDict_CheckExact(GLOBALS())
-                    && PyDict_CheckExact(BUILTINS()))
-                {
-                    assert(stack_pointer == _PyFrame_GetStackPointer(frame));
-                    _PyFrame_StackPointerValidate(frame);
-                    v_o = _PyDict_LoadGlobal((PyDictObject *)GLOBALS(),
-                        (PyDictObject *)BUILTINS(),
-                        name);
-                    _PyFrame_StackPointerInvalidate(frame);
-                    if (v_o == NULL) {
-                        if (!_PyErr_Occurred(tstate)) {
-                            assert(stack_pointer == 
_PyFrame_GetStackPointer(frame));
-                            _PyFrame_StackPointerValidate(frame);
-                            _PyEval_FormatExcCheckArg(tstate, PyExc_NameError,
-                                NAME_ERROR_MSG, name);
-                            _PyFrame_StackPointerInvalidate(frame);
-                        }
-                        JUMP_TO_LABEL(error);
-                    }
-                    if (PyLazyImport_CheckExact(v_o)) {
-                        assert(stack_pointer == 
_PyFrame_GetStackPointer(frame));
-                        _PyFrame_StackPointerValidate(frame);
-                        PyObject *l_v = _PyImport_LoadLazyImportTstate(tstate, 
v_o);
-                        _PyFrame_StackPointerInvalidate(frame);
-                        assert(stack_pointer == 
_PyFrame_GetStackPointer(frame));
-                        _PyFrame_StackPointerValidate(frame);
-                        Py_SETREF(v_o, l_v);
-                        _PyFrame_StackPointerInvalidate(frame);
-                        if (v_o == NULL) {
-                            JUMP_TO_LABEL(error);
-                        }
-                    }
-                }
-                else {
-                    assert(stack_pointer == _PyFrame_GetStackPointer(frame));
-                    _PyFrame_StackPointerValidate(frame);
-                    v_o = _PyMapping_GetOptionalItem2(GLOBALS(), name, &err);
-                    _PyFrame_StackPointerInvalidate(frame);
-                    if (err < 0) {
-                        JUMP_TO_LABEL(error);
-                    }
-                    if (v_o == NULL) {
-                        assert(stack_pointer == 
_PyFrame_GetStackPointer(frame));
-                        _PyFrame_StackPointerValidate(frame);
-                        v_o = _PyMapping_GetOptionalItem2(BUILTINS(), name, 
&err);
-                        _PyFrame_StackPointerInvalidate(frame);
-                        if (err < 0) {
-                            JUMP_TO_LABEL(error);
-                        }
-                        if (v_o == NULL) {
-                            assert(stack_pointer == 
_PyFrame_GetStackPointer(frame));
-                            _PyFrame_StackPointerValidate(frame);
-                            _PyEval_FormatExcCheckArg(
-                                tstate, PyExc_NameError,
-                                NAME_ERROR_MSG, name);
-                            _PyFrame_StackPointerInvalidate(frame);
-                            JUMP_TO_LABEL(error);
-                        }
-                    }
-                    if (PyLazyImport_CheckExact(v_o)) {
-                        assert(stack_pointer == 
_PyFrame_GetStackPointer(frame));
-                        _PyFrame_StackPointerValidate(frame);
-                        PyObject *l_v = _PyImport_LoadLazyImportTstate(tstate, 
v_o);
-                        _PyFrame_StackPointerInvalidate(frame);
-                        assert(stack_pointer == 
_PyFrame_GetStackPointer(frame));
-                        _PyFrame_StackPointerValidate(frame);
-                        Py_SETREF(v_o, l_v);
-                        _PyFrame_StackPointerInvalidate(frame);
-                        if (v_o == NULL) {
-                            JUMP_TO_LABEL(error);
-                        }
-                    }
+                assert(stack_pointer == _PyFrame_GetStackPointer(frame));
+                _PyFrame_StackPointerValidate(frame);
+                _PyEval_LoadGlobalStackRef(GLOBALS(), BUILTINS(), name, &v);
+                _PyFrame_StackPointerInvalidate(frame);
+                if (PyStackRef_IsNull(v)) {
+                    JUMP_TO_LABEL(error);
                 }
             }
-            v = PyStackRef_FromPyObjectSteal(v_o);
+            else {
+                v = PyStackRef_FromPyObjectSteal(v_o);
+            }
             stack_pointer[0] = v;
             stack_pointer += 1;
             ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
@@ -10282,38 +10238,6 @@
             if (v_o == NULL) {
                 JUMP_TO_LABEL(error);
             }
-            if (PyLazyImport_CheckExact(v_o)) {
-                assert(stack_pointer == _PyFrame_GetStackPointer(frame));
-                _PyFrame_StackPointerValidate(frame);
-                PyObject *l_v = _PyImport_LoadLazyImportTstate(tstate, v_o);
-                _PyFrame_StackPointerInvalidate(frame);
-                if (l_v == NULL) {
-                    assert(stack_pointer == _PyFrame_GetStackPointer(frame));
-                    _PyFrame_StackPointerValidate(frame);
-                    Py_DECREF(v_o);
-                    _PyFrame_StackPointerInvalidate(frame);
-                    JUMP_TO_LABEL(error);
-                }
-                assert(stack_pointer == _PyFrame_GetStackPointer(frame));
-                _PyFrame_StackPointerValidate(frame);
-                int err = PyDict_SetItem(GLOBALS(), name, l_v);
-                _PyFrame_StackPointerInvalidate(frame);
-                if (err < 0) {
-                    assert(stack_pointer == _PyFrame_GetStackPointer(frame));
-                    _PyFrame_StackPointerValidate(frame);
-                    Py_DECREF(v_o);
-                    _PyFrame_StackPointerInvalidate(frame);
-                    assert(stack_pointer == _PyFrame_GetStackPointer(frame));
-                    _PyFrame_StackPointerValidate(frame);
-                    Py_DECREF(l_v);
-                    _PyFrame_StackPointerInvalidate(frame);
-                    JUMP_TO_LABEL(error);
-                }
-                assert(stack_pointer == _PyFrame_GetStackPointer(frame));
-                _PyFrame_StackPointerValidate(frame);
-                Py_SETREF(v_o, l_v);
-                _PyFrame_StackPointerInvalidate(frame);
-            }
             v = PyStackRef_FromPyObjectSteal(v_o);
             stack_pointer[0] = v;
             stack_pointer += 1;
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index 49eb8481e128d0b..c6d055a412a515b 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -2013,6 +2013,35 @@ _PyDict_InsertSplitValue(PyDictObject *mp, PyObject 
*key, PyObject *value, Py_ss
     ASSERT_CONSISTENT(mp);
 }
 
+// Replace a value at an existing entry. Steals the new value reference.
+static void
+replace_value(PyDictObject *mp, PyObject *key, Py_ssize_t ix,
+              PyObject *old_value, PyObject *value)
+{
+    assert(can_modify_dict(mp));
+    assert(old_value != NULL);
+
+    if (old_value != value) {
+        _PyDict_NotifyEvent(PyDict_EVENT_MODIFIED, mp, key, value);
+        if (DK_IS_UNICODE(mp->ma_keys)) {
+            if (_PyDict_HasSplitTable(mp)) {
+                STORE_SPLIT_VALUE(mp, ix, value);
+            }
+            else {
+                PyDictUnicodeEntry *ep = &DK_UNICODE_ENTRIES(mp->ma_keys)[ix];
+                STORE_VALUE(ep, value);
+            }
+        }
+        else {
+            PyDictKeyEntry *ep = &DK_ENTRIES(mp->ma_keys)[ix];
+            STORE_VALUE(ep, value);
+        }
+    }
+    Py_DECREF(old_value); /* which **CAN** re-enter (see gh-66843) */
+
+    ASSERT_CONSISTENT(mp);
+}
+
 /*
 Internal routine to insert a new item into the table.
 Used both by the internal resize routine and by the public insert routine.
@@ -2060,25 +2089,7 @@ insertdict(PyDictObject *mp,
         return 0;
     }
 
-    if (old_value != value) {
-        _PyDict_NotifyEvent(PyDict_EVENT_MODIFIED, mp, key, value);
-        assert(old_value != NULL);
-        if (DK_IS_UNICODE(mp->ma_keys)) {
-            if (_PyDict_HasSplitTable(mp)) {
-                STORE_SPLIT_VALUE(mp, ix, value);
-            }
-            else {
-                PyDictUnicodeEntry *ep = &DK_UNICODE_ENTRIES(mp->ma_keys)[ix];
-                STORE_VALUE(ep, value);
-            }
-        }
-        else {
-            PyDictKeyEntry *ep = &DK_ENTRIES(mp->ma_keys)[ix];
-            STORE_VALUE(ep, value);
-        }
-    }
-    Py_XDECREF(old_value); /* which **CAN** re-enter (see issue #22653) */
-    ASSERT_CONSISTENT(mp);
+    replace_value(mp, key, ix, old_value, value);
     Py_DECREF(key);
     return 0;
 
@@ -2704,44 +2715,7 @@ _PyDict_GetItemStringWithError(PyObject *v, const char 
*key)
     return rv;
 }
 
-/* Fast version of global value lookup (LOAD_GLOBAL).
- * Lookup in globals, then builtins.
- *
- *
- *
- *
- * Raise an exception and return NULL if an error occurred (ex: computing the
- * key hash failed, key comparison failed, ...). Return NULL if the key doesn't
- * exist. Return the value if the key exists.
- *
- * Returns a new reference.
- */
 PyObject *
-_PyDict_LoadGlobal(PyDictObject *globals, PyDictObject *builtins, PyObject 
*key)
-{
-    Py_ssize_t ix;
-    Py_hash_t hash;
-    PyObject *value;
-
-    hash = _PyObject_HashDictKey(key);
-    if (hash == -1) {
-        return NULL;
-    }
-
-    /* namespace 1: globals */
-    ix = _Py_dict_lookup_threadsafe(globals, key, hash, &value);
-    if (ix == DKIX_ERROR)
-        return NULL;
-    if (ix != DKIX_EMPTY && value != NULL)
-        return value;
-
-    /* namespace 2: builtins */
-    ix = _Py_dict_lookup_threadsafe(builtins, key, hash, &value);
-    assert(ix >= 0 || value == NULL);
-    return value;
-}
-
-void
 _PyDict_LoadGlobalStackRef(PyDictObject *globals, PyDictObject *builtins, 
PyObject *key, _PyStackRef *res)
 {
     Py_ssize_t ix;
@@ -2750,21 +2724,22 @@ _PyDict_LoadGlobalStackRef(PyDictObject *globals, 
PyDictObject *builtins, PyObje
     hash = _PyObject_HashDictKey(key);
     if (hash == -1) {
         *res = PyStackRef_NULL;
-        return;
+        return NULL;
     }
 
     /* namespace 1: globals */
     ix = _Py_dict_lookup_threadsafe_stackref(globals, key, hash, res);
     if (ix == DKIX_ERROR) {
-        return;
+        return NULL;
     }
     if (ix != DKIX_EMPTY && !PyStackRef_IsNull(*res)) {
-        return;
+        return (PyObject *)globals;
     }
 
     /* namespace 2: builtins */
     ix = _Py_dict_lookup_threadsafe_stackref(builtins, key, hash, res);
     assert(ix >= 0 || PyStackRef_IsNull(*res));
+    return PyStackRef_IsNull(*res) ? NULL : (PyObject *)builtins;
 }
 
 PyObject *
@@ -3109,6 +3084,35 @@ _PyDict_DelItemIf(PyObject *op, PyObject *key,
     return res;
 }
 
+int
+_PyDict_ReplaceItemIf(PyObject *op, PyObject *key,
+                      PyObject *expected, PyObject *replacement)
+{
+    assert(PyDict_Check(op));
+    assert(expected != NULL);
+    assert(replacement != NULL);
+
+    Py_hash_t hash = PyObject_Hash(key);
+    if (hash == -1) {
+        return -1;
+    }
+    int result = 0;
+    Py_BEGIN_CRITICAL_SECTION(op);
+    PyDictObject *mp = (PyDictObject *)op;
+    PyObject *current;
+    Py_ssize_t ix = _Py_dict_lookup(mp, key, hash, &current);
+    if (ix == DKIX_ERROR) {
+        result = -1;
+    }
+    else if (current == expected) {
+        // Do not look up the key again: equality can execute Python code.
+        replace_value(mp, key, ix, current, Py_NewRef(replacement));
+        result = 1;
+    }
+    Py_END_CRITICAL_SECTION();
+    return result;
+}
+
 static void
 clear_embedded_values(PyDictValues *values, Py_ssize_t nentries)
 {
diff --git a/Objects/lazyimportobject.c b/Objects/lazyimportobject.c
index e008c076352ebbe..e4a949a5456cfd2 100644
--- a/Objects/lazyimportobject.c
+++ b/Objects/lazyimportobject.c
@@ -2,18 +2,39 @@
 
 #include "Python.h"
 #include "pycore_ceval.h"
-#include "pycore_frame.h"
+#include "pycore_dict.h"
+#include "pycore_gc.h"
 #include "pycore_import.h"
 #include "pycore_interpframe.h"
 #include "pycore_lazyimportobject.h"
-#include "pycore_modsupport.h"
+#include "pycore_long.h"
+#include "pycore_moduleobject.h"
+#include "pycore_pyerrors.h"
+#include "pycore_traceback.h"
+#include "pycore_tstate.h"
+
+typedef struct {
+    PyObject_HEAD
+    PyObject *lz_builtins;  // Roots own the mapping; projections retain the 
root.
+    // A root stores its absolute name (PyUnicode) in lz_from, and original
+    // fromlist in lz_attr.
+    // A projection stores its source placeholder (a PyLazyImportObject)
+    // in lz_from, and the attribute to import from (PyUnicode) it in lz_attr.
+    PyObject *lz_from;
+    PyObject *lz_attr;
+    // Declaration location.
+    PyCodeObject *lz_code;
+    int lz_instr_offset;
+} PyLazyImportObject;
 
 #define PyLazyImportObject_CAST(op) ((PyLazyImportObject *)(op))
 
+static PyObject *lazy_import_name(PyLazyImportObject *m);
+
 PyObject *
-_PyLazyImport_New(_PyInterpreterFrame *frame, PyObject *builtins, PyObject 
*name, PyObject *fromlist)
+_PyLazyImport_New(_PyInterpreterFrame *frame, PyObject *builtins,
+                  PyObject *name, PyObject *fromlist)
 {
-    PyLazyImportObject *m;
     if (!name || !(PyUnicode_Check(name) || PyLazyImport_CheckExact(name))) {
         PyErr_SetString(PyExc_TypeError, "expected str or lazy_import for 
name");
         return NULL;
@@ -26,7 +47,20 @@ _PyLazyImport_New(_PyInterpreterFrame *frame, PyObject 
*builtins, PyObject *name
             "lazy_import: fromlist must be None, a string, or a tuple");
         return NULL;
     }
-    m = PyObject_GC_New(PyLazyImportObject, &PyLazyImport_Type);
+#ifndef NDEBUG
+    if (PyLazyImport_CheckExact(name)) {
+        // projection
+        assert(builtins == NULL);
+        assert(fromlist != NULL);
+        assert(PyUnicode_Check(fromlist));
+    }
+    else {
+        // root
+        assert(builtins != NULL);
+    }
+#endif
+    PyLazyImportObject *m = PyObject_GC_New(
+        PyLazyImportObject, &PyLazyImport_Type);
     if (m == NULL) {
         return NULL;
     }
@@ -34,23 +68,83 @@ _PyLazyImport_New(_PyInterpreterFrame *frame, PyObject 
*builtins, PyObject *name
     m->lz_from = Py_NewRef(name);
     m->lz_attr = Py_XNewRef(fromlist);
 
-    // Capture frame information for the original import location.
     m->lz_code = NULL;
     m->lz_instr_offset = -1;
 
     if (frame != NULL) {
-        PyCodeObject *code = _PyFrame_GetCode(frame);
-        if (code != NULL) {
-            m->lz_code = (PyCodeObject *)Py_NewRef(code);
-            // Calculate the instruction offset from the current frame.
-            m->lz_instr_offset = _PyInterpreterFrame_LASTI(frame);
-        }
+        m->lz_code = (PyCodeObject *)Py_NewRef(_PyFrame_GetCode(frame));
+        m->lz_instr_offset = _PyInterpreterFrame_LASTI(frame);
     }
 
     _PyObject_GC_TRACK(m);
     return (PyObject *)m;
 }
 
+// Reuse concrete attributes of initialized modules without waiting for imports
+// or resolving lazy attributes. Failed cache lookups are retried at 
resolution.
+// May return NULL with or without an exception set.
+static PyObject *
+lazy_import_get_loaded_attr(PyThreadState *tstate, PyObject *name,
+                            PyObject *attr_name)
+{
+    PyObject *mod = NULL, *spec = NULL, *current = NULL, *attr = NULL;
+    PyObject *modules = Py_XNewRef(_PyImport_GetModules(tstate->interp));
+    if (modules == NULL) {
+        return NULL;
+    }
+    int rc = PyMapping_GetOptionalItem(modules, name, &mod);
+    if (rc <= 0 || !PyModule_Check(mod)) {
+        goto done;
+    }
+    PyObject *dict = _PyModule_GetDict(mod);
+    if (PyObject_GetOptionalAttr(mod, &_Py_ID(__spec__), &spec) < 0 ||
+        _PyModuleSpec_IsInitializing(spec) != 0) {
+        goto done;
+    }
+    // An initialization check can replace the module in sys.modules.
+    if (modules != _PyImport_GetModules(tstate->interp) ||
+        PyMapping_GetOptionalItem(modules, name, &current) <= 0 ||
+        current != mod) {
+        goto done;
+    }
+    if (PyDict_GetItemRef(dict, attr_name, &attr) < 0) {
+        goto done;
+    }
+    if (attr != NULL && PyLazyImport_CheckExact(attr)) {
+        Py_CLEAR(attr);
+    }
+
+done:
+    Py_XDECREF(current);
+    Py_XDECREF(spec);
+    Py_XDECREF(mod);
+    Py_DECREF(modules);
+    if (PyErr_ExceptionMatches(PyExc_Exception)) {
+        PyErr_Clear();
+    }
+    return attr;
+}
+
+PyObject *
+_PyEval_LazyImportFrom(PyThreadState *tstate, _PyInterpreterFrame *frame,
+                       PyObject *v, PyObject *name)
+{
+    assert(PyLazyImport_CheckExact(v));
+    assert(name);
+    assert(PyUnicode_Check(name));
+    PyLazyImportObject *lz = PyLazyImportObject_CAST(v);
+    // Only `from a import b` can take b off an already imported a;
+    // `import a.b as c` has to import a.b first.
+    if (lz->lz_attr != NULL && PyTuple_Check(lz->lz_attr) &&
+        PyTuple_GET_SIZE(lz->lz_attr) > 0) {
+        PyObject *attr = lazy_import_get_loaded_attr(tstate, lz->lz_from, 
name);
+        if (attr != NULL || PyErr_Occurred()) {
+            return attr;
+        }
+    }
+    return _PyLazyImport_New(frame, NULL, v, name);
+}
+
 static int
 lazy_import_traverse(PyObject *op, visitproc visit, void *arg)
 {
@@ -85,23 +179,20 @@ lazy_import_dealloc(PyObject *op)
 static PyObject *
 lazy_import_getattro(PyObject *op, PyObject *name)
 {
-    PyObject *value = _PyObject_GenericGetAttrWithDict(op, name, NULL, /* 
suppress */1);
-    if (value == NULL) {
-        if (PyErr_Occurred()) {
-            // pass up non-AttributeError exception
-            return NULL;
-        }
-        PyObject *lz_name = _PyLazyImport_GetName(op);
-        if (lz_name == NULL) {
-            return NULL;
-        }
-        PyErr_Format(PyExc_AttributeError,
-                     "cannot access attribute %R on unresolved lazy import %R",
-                     name, lz_name);
-        Py_DECREF(lz_name);
+    PyObject *value = _PyObject_GenericGetAttrWithDict(
+        op, name, NULL, /* suppress */ 1);
+    if (value != NULL || PyErr_Occurred()) {
+        return value;
+    }
+    PyObject *lz_name = lazy_import_name(PyLazyImportObject_CAST(op));
+    if (lz_name == NULL) {
         return NULL;
     }
-    return value;
+    PyErr_Format(PyExc_AttributeError,
+                 "cannot access attribute %R on unresolved lazy import %R",
+                 name, lz_name);
+    Py_DECREF(lz_name);
+    return NULL;
 }
 
 // The dotted name of the object that resolving the placeholder returns.
@@ -160,12 +251,320 @@ lazy_import_repr(PyObject *op)
     return res;
 }
 
-PyObject *
-_PyLazyImport_GetName(PyObject *op)
+// Consume a result, resolving a placeholder returned by an import hook or
+// an attribute lookup under the same cycle and recursion checks.
+static PyObject *
+lazy_import_resolve_result(PyThreadState *tstate, PyObject *obj)
+{
+    if (obj == NULL || !PyLazyImport_CheckExact(obj)) {
+        return obj;
+    }
+    PyObject *result = _PyImport_LoadLazyImportTstate(tstate, obj);
+    Py_DECREF(obj);
+    return result;
+}
+
+// Look up, in order, the attributes recorded from the root placeholder to lz
+// on the module the root's import returned.
+static PyObject *
+lazy_import_replay_from(PyThreadState *tstate, PyObject *mod,
+                        PyLazyImportObject *lz)
+{
+    if (!PyLazyImport_CheckExact(lz->lz_from)) {
+        return Py_NewRef(mod);
+    }
+    PyObject *from = lazy_import_replay_from(
+        tstate, mod, (PyLazyImportObject *)lz->lz_from);
+    if (from == NULL) {
+        return NULL;
+    }
+    PyObject *obj = _PyEval_ImportFrom(tstate, from, lz->lz_attr);
+    Py_DECREF(from);
+    return lazy_import_resolve_result(tstate, obj);
+}
+
+// Preserve the resolution error and attach the import's declaration location.
+static void
+lazy_import_add_exception_cause(PyThreadState *tstate, PyLazyImportObject *lz)
 {
-    PyLazyImportObject *lazy_import = PyLazyImportObject_CAST(op);
+    if (!PyErr_Occurred() || lz->lz_code == NULL || lz->lz_instr_offset < 0) {
+        return;
+    }
+    PyObject *exc = _PyErr_GetRaisedException(tstate);
+    PyObject *name = lazy_import_name(lz);
+    if (name == NULL) {
+        goto done;
+    }
+    int lineno = PyCode_Addr2Line(lz->lz_code, lz->lz_instr_offset * 2);
+    const char *filename = PyUnicode_AsUTF8(lz->lz_code->co_filename);
+    if (filename == NULL) {
+        goto done;
+    }
+    const char *funcname = PyUnicode_AsUTF8(lz->lz_code->co_name);
+    if (funcname == NULL) {
+        goto done;
+    }
+    PyBaseExceptionObject *base_exc = (PyBaseExceptionObject *)exc;
+    if (base_exc->cause != NULL || base_exc->context != NULL ||
+        base_exc->suppress_context) {
+        // Preserve the original chain, including `raise ... from None`.
+        PyObject *note = PyUnicode_FromFormat(
+            "lazy import of '%U' declared in %s at %s:%d",
+            name, funcname, filename, lineno);
+        if (note != NULL) {
+            PyObject *notes;
+            if (PyObject_GetOptionalAttr(exc, &_Py_ID(__notes__), &notes) >= 
0) {
+                if (notes == NULL || PySequence_Contains(notes, note) == 0) {
+                    (void)_PyException_AddNote(exc, note);
+                }
+                Py_XDECREF(notes);
+            }
+            Py_DECREF(note);
+        }
+        goto done;
+    }
+    PyObject *msg = PyUnicode_FromFormat(
+        "lazy import of '%U' raised an exception during resolution", name);
+    if (msg == NULL) {
+        goto done;
+    }
+    PyObject *cause = PyObject_CallOneArg(PyExc_ImportError, msg);
+    Py_DECREF(msg);
+    if (cause == NULL) {
+        goto done;
+    }
+    _PyErr_SetRaisedException(tstate, cause);
+    _PyTraceback_Add(funcname, filename, lineno);
+    PyException_SetCause(exc, _PyErr_GetRaisedException(tstate));
+
+done:
+    Py_XDECREF(name);
+    _PyErr_SetRaisedException(tstate, exc);
+}
+
+int
+_PyLazyImport_IsResolving(PyThreadState *tstate, PyObject *op)
+{
+    _PyThreadStateImpl *ts = (_PyThreadStateImpl *)tstate;
+    assert(PyLazyImport_CheckExact(op));
+    int active = ts->lazy_imports == NULL ? 0 : 
PySet_Contains(ts->lazy_imports, op);
+    assert(active >= 0);  // Exact placeholders use identity hashing and 
equality.
+    return active;
+}
+
+static PyObject *
+lazy_import_resolve_impl(PyThreadState *tstate, PyObject *lazy_import,
+                         PyObject **imported_module)
+{
+    PyObject *obj = NULL;
+    PyObject *fromlist = NULL;
+    PyObject *import_func = NULL;
+    PyObject *resolving = NULL;
+    assert(lazy_import != NULL);
     assert(PyLazyImport_CheckExact(lazy_import));
-    return lazy_import_name(lazy_import);
+
+    PyLazyImportObject *lz = (PyLazyImportObject *)lazy_import;
+
+    // Walk back to the placeholder IMPORT_NAME left, and the first lookup on 
it.
+    PyLazyImportObject *root = lz, *first = NULL;
+    while (PyLazyImport_CheckExact(root->lz_from)) {
+        first = root;
+        root = (PyLazyImportObject *)root->lz_from;
+    }
+
+    if (_PyLazyImport_IsResolving(tstate, lazy_import)) {
+        PyObject *name = lazy_import_name(lz);
+        if (name == NULL) {
+            return NULL;
+        }
+        PyObject *errmsg = PyUnicode_FromFormat(
+            "cannot import name %R (most likely due to a circular import)",
+            name);
+        Py_DECREF(name);
+        if (errmsg != NULL) {
+            PyErr_SetImportErrorSubclass(PyExc_ImportCycleError, errmsg,
+                                         root->lz_from, NULL);
+            Py_DECREF(errmsg);
+        }
+        return NULL;
+    }
+    if (_Py_EnterRecursiveCallTstate(tstate, " while resolving a lazy 
import")) {
+        return NULL;
+    }
+    _PyThreadStateImpl *ts = (_PyThreadStateImpl *)tstate;
+    if (ts->lazy_imports == NULL) {
+        ts->lazy_imports = PySet_New(NULL);
+        if (ts->lazy_imports == NULL) {
+            goto done;
+        }
+    }
+    resolving = ts->lazy_imports;
+    if (PySet_Add(resolving, lazy_import) < 0) {
+        goto done;
+    }
+
+    // `from a import b, c`: import only the name being resolved.
+    // Keep an empty tuple intact for custom __import__ hooks.
+    if (first != NULL && root->lz_attr != NULL &&
+        PyTuple_Check(root->lz_attr) && PyTuple_GET_SIZE(root->lz_attr) > 0) {
+        fromlist = PyTuple_Pack(1, first->lz_attr);
+    }
+    else {
+        fromlist = Py_NewRef(root->lz_attr != NULL ? root->lz_attr : Py_None);
+    }
+    if (fromlist == NULL) {
+        goto done;
+    }
+
+    PyObject *globals = PyEval_GetGlobals();
+    if (globals == NULL) {
+        globals = Py_None;
+    }
+
+    if (PyMapping_GetOptionalItem(root->lz_builtins, &_Py_ID(__import__),
+                                  &import_func) < 0) {
+        goto done;
+    }
+    if (import_func == NULL) {
+        PyErr_SetString(PyExc_ImportError, "__import__ not found");
+        goto done;
+    }
+    obj = _PyEval_ImportNameWithImport(
+        tstate, import_func, globals, globals,
+        root->lz_from, fromlist, _PyLong_GetZero()
+    );
+    obj = lazy_import_resolve_result(tstate, obj);
+    // The normal importer may publish this module on its parent. Custom
+    // hooks retain control of their own assignments to the parent.
+    if (imported_module != NULL && obj != NULL && PyModule_Check(obj) &&
+        _PyImport_IsDefaultImportFunc(tstate->interp, import_func)) {
+        *imported_module = Py_NewRef(obj);
+    }
+    if (obj != NULL && first != NULL) {
+        // Keep the hook and root result alive until all attribute lookups 
finish.
+        PyObject *from = obj;
+        obj = lazy_import_replay_from(tstate, from, lz);
+        Py_DECREF(from);
+    }
+
+done:
+    if (obj == NULL) {
+        lazy_import_add_exception_cause(tstate, lz);
+    }
+    assert(obj == NULL || !PyLazyImport_CheckExact(obj));
+    if (resolving != NULL) {
+        // A failed set resize can leave the placeholder inserted. Removing by
+        // identity also permits greenlets to finish in a different order.
+        if (PySet_Discard(resolving, lazy_import) < 0) {
+            Py_CLEAR(obj);
+        }
+        if (PySet_GET_SIZE(resolving) == 0) {
+            // Keep the set, but release the capacity used by deep resolutions.
+            (void)PySet_Clear(resolving);
+        }
+    }
+
+    Py_XDECREF(fromlist);
+    Py_XDECREF(import_func);
+    _Py_LeaveRecursiveCallTstate(tstate);
+    return obj;
+}
+
+PyObject *
+_PyImport_LoadLazyImportTstate(PyThreadState *tstate, PyObject *lazy_import)
+{
+    return lazy_import_resolve_impl(tstate, lazy_import, NULL);
+}
+
+// Loading pkg.child can replace a placeholder in pkg.child with the module
+// before a from-import retrieves the value that belongs in that binding.
+// This is an optimization that can be safely skipped.
+static int
+lazy_import_replace_child(PyThreadState *tstate, PyObject *placeholder,
+                          PyObject *name, PyObject *namespace,
+                          PyObject *child, PyObject *value)
+{
+    PyLazyImportObject *root = (PyLazyImportObject *)placeholder;
+    if (!PyLazyImport_CheckExact(root->lz_from)) {
+        return 0;
+    }
+    while (PyLazyImport_CheckExact(root->lz_from)) {
+        root = (PyLazyImportObject *)root->lz_from;
+    }
+    Py_ssize_t end = PyUnicode_GET_LENGTH(root->lz_from);
+    Py_ssize_t dot = PyUnicode_FindChar(root->lz_from, '.', 0, end, -1);
+    if (dot < 0) {
+        return dot == -1 ? 0 : -1;
+    }
+    if (end - dot - 1 != PyUnicode_GET_LENGTH(name)) {
+        return 0;
+    }
+    Py_ssize_t matches = PyUnicode_Tailmatch(root->lz_from, name, dot + 1, 
end, 1);
+    if (matches <= 0) {
+        return matches ? -1 : 0;
+    }
+    PyObject *parent_name = PyUnicode_Substring(root->lz_from, 0, dot);
+    if (parent_name == NULL) {
+        return -1;
+    }
+    PyObject *modules = Py_XNewRef(_PyImport_GetModules(tstate->interp));
+    PyObject *parent = NULL;
+    int rc = 0;
+    if (modules != NULL) {
+        rc = PyMapping_GetOptionalItem(modules, parent_name, &parent);
+        if (rc > 0 && PyModule_Check(parent) &&
+            _PyModule_GetDict(parent) == namespace) {
+            rc = _PyDict_ReplaceItemIf(namespace, name, child, value);
+        }
+    }
+    Py_XDECREF(parent);
+    Py_XDECREF(modules);
+    Py_DECREF(parent_name);
+    return rc;
+}
+
+PyObject *
+_PyLazyImport_Reify(PyThreadState *tstate, PyObject *placeholder,
+                    PyObject *name, PyObject *namespace)
+{
+    PyObject *imported_module = NULL;
+    PyObject *value = lazy_import_resolve_impl(
+        tstate, placeholder, &imported_module);
+    if (value == NULL) {
+        Py_XDECREF(imported_module);
+        return NULL;
+    }
+    int rc;
+    if (PyDict_CheckExact(namespace)) {
+        rc = _PyDict_ReplaceItemIf(namespace, name, placeholder, value);
+        if (rc == 0 && imported_module != NULL) {
+            rc = lazy_import_replace_child(
+                tstate, placeholder, name, namespace, imported_module, value);
+        }
+    }
+    else if (Py_TYPE(namespace)->tp_as_mapping == NULL ||
+             Py_TYPE(namespace)->tp_as_mapping->mp_ass_subscript == NULL) {
+        // Read-only namespaces can resolve a value without caching it.
+        Py_XDECREF(imported_module);
+        return value;
+    }
+    else {
+        // Custom namespaces retain their mapping protocol. Atomic replacement
+        // is only available for exact dictionaries.
+        PyObject *current;
+        rc = PyMapping_GetOptionalItem(namespace, name, &current);
+        if (rc > 0) {
+            if (current == placeholder) {
+                rc = PyObject_SetItem(namespace, name, value);
+            }
+            Py_DECREF(current);
+        }
+    }
+    if (rc < 0) {
+        Py_CLEAR(value);
+    }
+    Py_XDECREF(imported_module);
+    return value;
 }
 
 static PyObject *
@@ -177,7 +576,7 @@ lazy_import_resolve(PyObject *self, PyObject *args)
 static PyMethodDef lazy_import_methods[] = {
     {
         "resolve", lazy_import_resolve, METH_NOARGS,
-        PyDoc_STR("resolves the lazy import and returns the actual object")
+        PyDoc_STR("Resolve the lazy import and return the imported object.")
     },
     {NULL, NULL}
 };
diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c
index b8cd6025c20ba56..57df195b7f32014 100644
--- a/Objects/moduleobject.c
+++ b/Objects/moduleobject.c
@@ -7,7 +7,7 @@
 #include "pycore_fileutils.h"     // _Py_wgetcwd
 #include "pycore_import.h"        // _PyImport_GetNextModuleIndex()
 #include "pycore_interp.h"        // PyInterpreterState.importlib
-#include "pycore_lazyimportobject.h" // _PyLazyImportObject_Check()
+#include "pycore_lazyimportobject.h" // PyLazyImport_CheckExact()
 #include "pycore_long.h"          // _PyLong_GetOne()
 #include "pycore_modsupport.h"    // _PyModule_CreateInitialized()
 #include "pycore_moduleobject.h"  // _PyModule_GetDefOrNull()
@@ -1299,32 +1299,21 @@ _PyModule_IsPossiblyShadowing(PyObject *origin)
     return result;
 }
 
-static PyObject *
-try_load_lazy_submodule(PyModuleObject *m, PyObject *name)
+static int
+module_get_resolved_dict_item(PyObject *dict, PyObject *name, PyObject 
**result)
 {
-    PyObject *mod_name;
-    int rc = PyDict_GetItemRef(m->md_dict, &_Py_ID(__name__), &mod_name);
-    if (rc <= 0) {
-        return NULL;
-    }
-    if (!PyUnicode_Check(mod_name)) {
-        Py_DECREF(mod_name);
-        return NULL;
-    }
-    PyObject *result = NULL;
-    _PyLazySubmoduleImportResult status =
-        _PyImport_TryLoadLazySubmodule(mod_name, name, &result);
-    Py_DECREF(mod_name);
-    if (status != _Py_LAZY_SUBMODULE_LOADED) {
-        assert(status == _Py_LAZY_SUBMODULE_ERROR ||
-               status == _Py_LAZY_SUBMODULE_NOT_FOUND);
-        return NULL;
+    int rc = PyDict_GetItemRef(dict, name, result);
+    if (rc <= 0 || !PyLazyImport_CheckExact(*result)) {
+        return rc;
     }
-    if (PyDict_SetItem(m->md_dict, name, result) < 0) {
-        Py_DECREF(result);
-        return NULL;
+    PyThreadState *tstate = PyThreadState_GET();
+    if (_PyLazyImport_IsResolving(tstate, *result)) {
+        Py_CLEAR(*result);
+        return 0;
     }
-    return result;
+    PyObject *value = _PyLazyImport_Reify(tstate, *result, name, dict);
+    Py_SETREF(*result, value);
+    return value == NULL ? -1 : 1;
 }
 
 PyObject*
@@ -1333,11 +1322,52 @@ _Py_module_getattro_impl(PyModuleObject *m, PyObject 
*name, int suppress)
     // When suppress=1, this function suppresses AttributeError.
     PyObject *attr, *mod_name, *getattr;
     attr = _PyObject_GenericGetAttrWithDict((PyObject *)m, name, NULL, 
suppress);
+    if (attr == NULL) {
+        if (suppress == 1) {
+            if (PyErr_Occurred()) {
+                // pass up non-AttributeError exception
+                return NULL;
+            }
+        }
+        else {
+            if (!PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                // pass up non-AttributeError exception
+                return NULL;
+            }
+            PyErr_Clear();
+        }
+        assert(m->md_dict != NULL);
+        int recheck_dict;
+        attr = _PyImport_TryLoadLazySubmodule((PyObject *)m, name, 
&recheck_dict);
+        if (attr != NULL || PyErr_Occurred()) {
+            return attr;
+        }
+        // A concurrent load may have bound the child and removed its pending
+        // registration after our initial dictionary lookup.
+        if (recheck_dict) {
+            if (Py_TYPE(m) != &PyModule_Type) {
+                PyObject *descr = _PyType_LookupRef(Py_TYPE(m), name);
+                if (descr != NULL) {
+                    // Preserve the fallback after a descriptor raised.
+                    recheck_dict = Py_TYPE(descr)->tp_descr_get == NULL;
+                    Py_DECREF(descr);
+                }
+            }
+            if (recheck_dict &&
+                PyDict_GetItemRef(m->md_dict, name, &attr) < 0) {
+                return NULL;
+            }
+        }
+    }
     if (attr) {
         if (PyLazyImport_CheckExact(attr)) {
             // gh-144957: Module __getattr__ should get a chance to provide
             // the attribute before resolving a lazy import placeholder.
-            if (PyDict_GetItemRef(m->md_dict, &_Py_ID(__getattr__), &getattr) 
< 0) {
+            // Resolving __getattr__ itself must not invoke the hook.
+            getattr = NULL;
+            if (!_PyUnicode_EqualToASCIIString(name, "__getattr__") &&
+                module_get_resolved_dict_item(
+                    m->md_dict, &_Py_ID(__getattr__), &getattr) < 0) {
                 Py_DECREF(attr);
                 return NULL;
             }
@@ -1354,51 +1384,21 @@ _Py_module_getattro_impl(PyModuleObject *m, PyObject 
*name, int suppress)
                 }
                 PyErr_Clear();
             }
-            PyObject *new_value = _PyImport_LoadLazyImportTstate(
-                PyThreadState_GET(), attr);
-            if (new_value == NULL) {
-                if (suppress &&
-                    PyErr_ExceptionMatches(PyExc_ImportCycleError)) {
-                    // ImportCycleError is raised when a lazy object tries
-                    // to import itself. In this case, the error should not
-                    // propagate to the caller and instead treated as if the
-                    // attribute doesn't exist.
-                    PyErr_Clear();
-                }
+            PyThreadState *tstate = PyThreadState_GET();
+            if (suppress && _PyLazyImport_IsResolving(tstate, attr)) {
+                // Only direct reentry means this attribute is unavailable.
                 Py_DECREF(attr);
                 return NULL;
             }
-
-            if (PyDict_SetItem(m->md_dict, name, new_value) < 0) {
-                Py_CLEAR(new_value);
-            }
+            PyObject *new_value = _PyLazyImport_Reify(
+                tstate, attr, name, m->md_dict);
             Py_DECREF(attr);
             return new_value;
         }
         return attr;
     }
-    if (suppress == 1) {
-        if (PyErr_Occurred()) {
-            // pass up non-AttributeError exception
-            return NULL;
-        }
-    }
-    else {
-        if (!PyErr_ExceptionMatches(PyExc_AttributeError)) {
-            // pass up non-AttributeError exception
-            return NULL;
-        }
-        PyErr_Clear();
-    }
-    assert(m->md_dict != NULL);
-    attr = try_load_lazy_submodule(m, name);
-    if (attr != NULL) {
-        return attr;
-    }
-    if (PyErr_Occurred()) {
-        return NULL;
-    }
-    if (PyDict_GetItemRef(m->md_dict, &_Py_ID(__getattr__), &getattr) < 0) {
+    if (module_get_resolved_dict_item(
+            m->md_dict, &_Py_ID(__getattr__), &getattr) < 0) {
         return NULL;
     }
     if (getattr) {
@@ -1589,11 +1589,14 @@ module_dir(PyObject *self, PyObject *args)
 
     if (dict != NULL) {
         if (PyDict_Check(dict)) {
-            PyObject *dirfunc = PyDict_GetItemWithError(dict, 
&_Py_ID(__dir__));
-            if (dirfunc) {
+            PyObject *dirfunc;
+            int rc = module_get_resolved_dict_item(
+                dict, &_Py_ID(__dir__), &dirfunc);
+            if (rc > 0) {
                 result = _PyObject_CallNoArgs(dirfunc);
+                Py_DECREF(dirfunc);
             }
-            else if (!PyErr_Occurred()) {
+            else if (rc == 0) {
                 result = PyDict_Keys(dict);
             }
         }
diff --git a/Python/bytecodes.c b/Python/bytecodes.c
index 3f329274f06b110..31eaeab0d67841f 100644
--- a/Python/bytecodes.c
+++ b/Python/bytecodes.c
@@ -2192,80 +2192,30 @@ dummy_func(
 
         inst(LOAD_FROM_DICT_OR_GLOBALS, (mod_or_class_dict -- v)) {
             PyObject *name = GETITEM(FRAME_CO_NAMES, oparg);
+            PyObject *namespace = 
PyStackRef_AsPyObjectBorrow(mod_or_class_dict);
             int err;
-            PyObject *v_o = 
_PyMapping_GetOptionalItem2(PyStackRef_AsPyObjectBorrow(mod_or_class_dict), 
name, &err);
-
+            PyObject *v_o = _PyMapping_GetOptionalItem2(namespace, name, &err);
+            if (v_o != NULL && PyLazyImport_CheckExact(v_o)) {
+                Py_SETREF(v_o, _PyLazyImport_Reify(tstate, v_o, name, 
namespace));
+                if (v_o == NULL) {
+                    err = -1;
+                }
+            }
             PyStackRef_CLOSE(mod_or_class_dict);
             ERROR_IF(err < 0);
             if (v_o == NULL) {
-                if (PyDict_CheckExact(GLOBALS())
-                    && PyDict_CheckExact(BUILTINS()))
-                {
-                    v_o = _PyDict_LoadGlobal((PyDictObject *)GLOBALS(),
-                                             (PyDictObject *)BUILTINS(),
-                                             name);
-                    if (v_o == NULL) {
-                        if (!_PyErr_Occurred(tstate)) {
-                            /* _PyDict_LoadGlobal() returns NULL without 
raising
-                            * an exception if the key doesn't exist */
-                            _PyEval_FormatExcCheckArg(tstate, PyExc_NameError,
-                                                    NAME_ERROR_MSG, name);
-                        }
-                        ERROR_NO_POP();
-                    }
-
-                    if (PyLazyImport_CheckExact(v_o)) {
-                        PyObject *l_v = _PyImport_LoadLazyImportTstate(tstate, 
v_o);
-                        Py_SETREF(v_o, l_v);
-                        ERROR_IF(v_o == NULL);
-                    }
-                }
-                else {
-                    /* Slow-path if globals or builtins is not a dict */
-                    /* namespace 1: globals */
-                    v_o = _PyMapping_GetOptionalItem2(GLOBALS(), name, &err);
-                    ERROR_IF(err < 0);
-                    if (v_o == NULL) {
-                        /* namespace 2: builtins */
-                        v_o = _PyMapping_GetOptionalItem2(BUILTINS(), name, 
&err);
-                        ERROR_IF(err < 0);
-                        if (v_o == NULL) {
-                            _PyEval_FormatExcCheckArg(
-                                        tstate, PyExc_NameError,
-                                        NAME_ERROR_MSG, name);
-                            ERROR_IF(true);
-                        }
-                    }
-                    if (PyLazyImport_CheckExact(v_o)) {
-                        PyObject *l_v = _PyImport_LoadLazyImportTstate(tstate, 
v_o);
-                        Py_SETREF(v_o, l_v);
-                        ERROR_IF(v_o == NULL);
-                    }
-                }
+                _PyEval_LoadGlobalStackRef(GLOBALS(), BUILTINS(), name, &v);
+                ERROR_IF(PyStackRef_IsNull(v));
+            }
+            else {
+                v = PyStackRef_FromPyObjectSteal(v_o);
             }
-            v = PyStackRef_FromPyObjectSteal(v_o);
         }
 
         inst(LOAD_NAME, (-- v)) {
             PyObject *name = GETITEM(FRAME_CO_NAMES, oparg);
             PyObject *v_o = _PyEval_LoadName(tstate, frame, name);
             ERROR_IF(v_o == NULL);
-            if (PyLazyImport_CheckExact(v_o)) {
-                PyObject *l_v = _PyImport_LoadLazyImportTstate(tstate, v_o);
-                // cannot early-decref v_o as it may cause a side-effect on l_v
-                if (l_v == NULL) {
-                    Py_DECREF(v_o);
-                    ERROR_IF(true);
-                }
-                int err = PyDict_SetItem(GLOBALS(), name, l_v);
-                if (err < 0) {
-                    Py_DECREF(v_o);
-                    Py_DECREF(l_v);
-                    ERROR_IF(true);
-                }
-                Py_SETREF(v_o, l_v);
-            }
-
             v = PyStackRef_FromPyObjectSteal(v_o);
         }
 
@@ -2431,6 +2381,13 @@ dummy_func(
                     ERROR_NO_POP();
                 }
             }
+            else if (PyLazyImport_CheckExact(value_o)) {
+                Py_SETREF(value_o, _PyLazyImport_Reify(
+                    tstate, value_o, name, class_dict));
+                if (value_o == NULL) {
+                    ERROR_NO_POP();
+                }
+            }
             PyStackRef_CLOSE(class_dict_st);
             value = PyStackRef_FromPyObjectSteal(value_o);
         }
diff --git a/Python/ceval.c b/Python/ceval.c
index c1fbcb0611384c5..b90de789accd44f 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -3150,8 +3150,8 @@ _PyEval_LazyImportName(PyThreadState *tstate, PyObject 
*builtins,
         goto error;
     }
 
-    PyObject *args[6] = {name, globals, locals, fromlist, level, builtins};
-    res = PyObject_Vectorcall(lazy_import_func, args, 6, NULL);
+    PyObject *args[5] = {name, globals, locals, fromlist, level};
+    res = PyObject_Vectorcall(lazy_import_func, args, 5, NULL);
 error:
     Py_XDECREF(lazy_import_func);
     return res;
@@ -3325,43 +3325,6 @@ _PyEval_ImportFrom(PyThreadState *tstate, PyObject *v, 
PyObject *name)
     return NULL;
 }
 
-PyObject *
-_PyEval_LazyImportFrom(PyThreadState *tstate, _PyInterpreterFrame *frame, 
PyObject *v, PyObject *name)
-{
-    assert(PyLazyImport_CheckExact(v));
-    assert(name);
-    assert(PyUnicode_Check(name));
-    PyObject *ret;
-    PyLazyImportObject *d = (PyLazyImportObject *)v;
-    PyObject *mod = NULL;
-    // Only `from a import b` can take b off an already imported a;
-    // `import a.b as c` has to import a.b first.
-    if (d->lz_attr != NULL && PyTuple_Check(d->lz_attr) &&
-        PyTuple_GET_SIZE(d->lz_attr) > 0) {
-        mod = PyImport_GetModule(d->lz_from);
-    }
-    if (mod != NULL) {
-        // Check if the module already has the attribute, if so, resolve it
-        // eagerly.
-        if (PyModule_Check(mod)) {
-            PyObject *mod_dict = PyModule_GetDict(mod);
-            if (mod_dict != NULL) {
-                if (PyDict_GetItemRef(mod_dict, name, &ret) < 0) {
-                    Py_DECREF(mod);
-                    return NULL;
-                }
-                if (ret != NULL) {
-                    Py_DECREF(mod);
-                    return ret;
-                }
-            }
-        }
-        Py_DECREF(mod);
-    }
-
-    return _PyLazyImport_New(frame, d->lz_builtins, v, name);
-}
-
 #define CANNOT_CATCH_MSG "catching classes that do not inherit from "\
                          "BaseException is not allowed"
 
@@ -3627,13 +3590,13 @@ _PyEval_GetANext(PyObject *aiter)
 void
 _PyEval_LoadGlobalStackRef(PyObject *globals, PyObject *builtins, PyObject 
*name, _PyStackRef *writeto)
 {
+    PyObject *namespace = globals;
     if (PyAnyDict_CheckExact(globals) && PyAnyDict_CheckExact(builtins)) {
-        _PyDict_LoadGlobalStackRef((PyDictObject *)globals,
-                                    (PyDictObject *)builtins,
-                                    name, writeto);
+        namespace = _PyDict_LoadGlobalStackRef((PyDictObject *)globals,
+                                             (PyDictObject *)builtins,
+                                             name, writeto);
         if (PyStackRef_IsNull(*writeto) && !PyErr_Occurred()) {
-            /* _PyDict_LoadGlobal() returns NULL without raising
-                * an exception if the key doesn't exist */
+            // A missing key does not set an exception in the dictionary 
helper.
             _PyEval_FormatExcCheckArg(PyThreadState_GET(), PyExc_NameError,
                                         NAME_ERROR_MSG, name);
         }
@@ -3648,6 +3611,7 @@ _PyEval_LoadGlobalStackRef(PyObject *globals, PyObject 
*builtins, PyObject *name
         }
         if (res == NULL) {
             /* namespace 2: builtins */
+            namespace = builtins;
             if (PyMapping_GetOptionalItem(builtins, name, &res) < 0) {
                 *writeto = PyStackRef_NULL;
                 return;
@@ -3665,20 +3629,10 @@ _PyEval_LoadGlobalStackRef(PyObject *globals, PyObject 
*builtins, PyObject *name
 
     PyObject *res_o = PyStackRef_AsPyObjectBorrow(*writeto);
     if (res_o != NULL && PyLazyImport_CheckExact(res_o)) {
-        PyObject *l_v = _PyImport_LoadLazyImportTstate(PyThreadState_GET(), 
res_o);
+        PyObject *l_v = _PyLazyImport_Reify(
+            PyThreadState_GET(), res_o, name, namespace);
         PyStackRef_CLOSE(writeto[0]);
-        if (l_v == NULL) {
-            assert(PyErr_Occurred());
-            *writeto = PyStackRef_NULL;
-            return;
-        }
-        int err = PyDict_SetItem(globals, name, l_v);
-        if (err < 0) {
-            Py_DECREF(l_v);
-            *writeto = PyStackRef_NULL;
-            return;
-        }
-        *writeto = PyStackRef_FromPyObjectSteal(l_v);
+        *writeto = l_v == NULL ? PyStackRef_NULL : 
PyStackRef_FromPyObjectSteal(l_v);
     }
 }
 
@@ -3709,32 +3663,39 @@ _PyEval_GetAwaitable(PyObject *iterable, int oparg)
 PyObject *
 _PyEval_LoadName(PyThreadState *tstate, _PyInterpreterFrame *frame, PyObject 
*name)
 {
-
     PyObject *value;
-    if (frame->f_locals == NULL) {
+    PyObject *namespace = frame->f_locals;
+    if (namespace == NULL) {
         _PyErr_SetString(tstate, PyExc_SystemError,
                             "no locals found");
         return NULL;
     }
-    if (PyMapping_GetOptionalItem(frame->f_locals, name, &value) < 0) {
+    if (PyMapping_GetOptionalItem(namespace, name, &value) < 0) {
         return NULL;
     }
     if (value != NULL) {
-        return value;
+        goto found;
     }
-    if (PyDict_GetItemRef(frame->f_globals, name, &value) < 0) {
+    namespace = frame->f_globals;
+    if (PyDict_GetItemRef(namespace, name, &value) < 0) {
         return NULL;
     }
     if (value != NULL) {
-        return value;
+        goto found;
     }
-    if (PyMapping_GetOptionalItem(frame->f_builtins, name, &value) < 0) {
+    namespace = frame->f_builtins;
+    if (PyMapping_GetOptionalItem(namespace, name, &value) < 0) {
         return NULL;
     }
     if (value == NULL) {
         _PyEval_FormatExcCheckArg(
                     tstate, PyExc_NameError,
-                    NAME_ERROR_MSG, name);
+                            NAME_ERROR_MSG, name);
+        return NULL;
+    }
+found:
+    if (PyLazyImport_CheckExact(value)) {
+        Py_SETREF(value, _PyLazyImport_Reify(tstate, value, name, namespace));
     }
     return value;
 }
diff --git a/Python/clinic/import.c.h b/Python/clinic/import.c.h
index 2e4e178b3084063..749eaebca19dc53 100644
--- a/Python/clinic/import.c.h
+++ b/Python/clinic/import.c.h
@@ -627,7 +627,7 @@ PyDoc_STRVAR(_imp__set_lazy_attributes__doc__,
 "_set_lazy_attributes($module, modobj, name, /)\n"
 "--\n"
 "\n"
-"Sets attributes to lazy submodules on the module, as side effects.");
+"Remove the resolved module name from sys.lazy_modules.");
 
 #define _IMP__SET_LAZY_ATTRIBUTES_METHODDEF    \
     {"_set_lazy_attributes", _PyCFunction_CAST(_imp__set_lazy_attributes), 
METH_FASTCALL, _imp__set_lazy_attributes__doc__},
@@ -665,4 +665,4 @@ _imp__set_lazy_attributes(PyObject *module, PyObject *const 
*args, Py_ssize_t na
 #ifndef _IMP_EXEC_DYNAMIC_METHODDEF
     #define _IMP_EXEC_DYNAMIC_METHODDEF
 #endif /* !defined(_IMP_EXEC_DYNAMIC_METHODDEF) */
-/*[clinic end generated code: output=0974db098d601372 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=ae9cf67e39955555 input=a9049054013a1b77]*/
diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h
index 400f07b58e7fa53..c5b2dfcf5f618f3 100644
--- a/Python/executor_cases.c.h
+++ b/Python/executor_cases.c.h
@@ -10179,55 +10179,77 @@
             break;
         }
 
-        /* _LOAD_FROM_DICT_OR_GLOBALS is not a viable micro-op for tier 2 
because it has both popping and not-popping errors */
-
-        case _LOAD_NAME_r01: {
-            CHECK_CURRENT_CACHED_VALUES(0);
+        case _LOAD_FROM_DICT_OR_GLOBALS_r11: {
+            CHECK_CURRENT_CACHED_VALUES(1);
             ASSERT_WITHIN_STACK_BOUNDS_IGNORING_CACHE(__FILE__, __LINE__);
+            _PyStackRef mod_or_class_dict;
             _PyStackRef v;
+            _PyStackRef _stack_item_0 = _tos_cache0;
             oparg = CURRENT_OPARG();
+            mod_or_class_dict = _stack_item_0;
             PyObject *name = GETITEM(FRAME_CO_NAMES, oparg);
+            PyObject *namespace = 
PyStackRef_AsPyObjectBorrow(mod_or_class_dict);
+            int err;
+            stack_pointer[0] = mod_or_class_dict;
+            stack_pointer += 1;
+            ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
             _PyFrame_SetStackPointer(frame, stack_pointer);
             _PyFrame_StackPointerValidate(frame);
-            PyObject *v_o = _PyEval_LoadName(tstate, frame, name);
+            PyObject *v_o = _PyMapping_GetOptionalItem2(namespace, name, &err);
             _PyFrame_StackPointerInvalidate(frame);
-            if (v_o == NULL) {
-                SET_CURRENT_CACHED_VALUES(0);
-                JUMP_TO_ERROR();
-            }
-            if (PyLazyImport_CheckExact(v_o)) {
+            if (v_o != NULL && PyLazyImport_CheckExact(v_o)) {
                 assert(stack_pointer == _PyFrame_GetStackPointer(frame));
                 _PyFrame_StackPointerValidate(frame);
-                PyObject *l_v = _PyImport_LoadLazyImportTstate(tstate, v_o);
+                Py_SETREF(v_o, _PyLazyImport_Reify(tstate, v_o, name, 
namespace));
                 _PyFrame_StackPointerInvalidate(frame);
-                if (l_v == NULL) {
-                    assert(stack_pointer == _PyFrame_GetStackPointer(frame));
-                    _PyFrame_StackPointerValidate(frame);
-                    Py_DECREF(v_o);
-                    _PyFrame_StackPointerInvalidate(frame);
-                    SET_CURRENT_CACHED_VALUES(0);
-                    JUMP_TO_ERROR();
+                if (v_o == NULL) {
+                    err = -1;
                 }
+            }
+            stack_pointer += -1;
+            ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
+            _PyFrame_SetStackPointer(frame, stack_pointer);
+            _PyFrame_StackPointerValidate(frame);
+            PyStackRef_CLOSE(mod_or_class_dict);
+            _PyFrame_StackPointerInvalidate(frame);
+            if (err < 0) {
+                SET_CURRENT_CACHED_VALUES(0);
+                JUMP_TO_ERROR();
+            }
+            if (v_o == NULL) {
                 assert(stack_pointer == _PyFrame_GetStackPointer(frame));
                 _PyFrame_StackPointerValidate(frame);
-                int err = PyDict_SetItem(GLOBALS(), name, l_v);
+                _PyEval_LoadGlobalStackRef(GLOBALS(), BUILTINS(), name, &v);
                 _PyFrame_StackPointerInvalidate(frame);
-                if (err < 0) {
-                    assert(stack_pointer == _PyFrame_GetStackPointer(frame));
-                    _PyFrame_StackPointerValidate(frame);
-                    Py_DECREF(v_o);
-                    _PyFrame_StackPointerInvalidate(frame);
-                    assert(stack_pointer == _PyFrame_GetStackPointer(frame));
-                    _PyFrame_StackPointerValidate(frame);
-                    Py_DECREF(l_v);
-                    _PyFrame_StackPointerInvalidate(frame);
+                if (PyStackRef_IsNull(v)) {
                     SET_CURRENT_CACHED_VALUES(0);
                     JUMP_TO_ERROR();
                 }
-                assert(stack_pointer == _PyFrame_GetStackPointer(frame));
-                _PyFrame_StackPointerValidate(frame);
-                Py_SETREF(v_o, l_v);
-                _PyFrame_StackPointerInvalidate(frame);
+            }
+            else {
+                v = PyStackRef_FromPyObjectSteal(v_o);
+            }
+            _tos_cache0 = v;
+            _tos_cache1 = PyStackRef_ZERO_BITS;
+            _tos_cache2 = PyStackRef_ZERO_BITS;
+            SET_CURRENT_CACHED_VALUES(1);
+            ASSERT_WITHIN_STACK_BOUNDS_IGNORING_CACHE(__FILE__, __LINE__);
+            break;
+        }
+
+        case _LOAD_NAME_r01: {
+            CHECK_CURRENT_CACHED_VALUES(0);
+            ASSERT_WITHIN_STACK_BOUNDS_IGNORING_CACHE(__FILE__, __LINE__);
+            _PyStackRef v;
+            oparg = CURRENT_OPARG();
+            PyObject *name = GETITEM(FRAME_CO_NAMES, oparg);
+            _PyFrame_SetStackPointer(frame, stack_pointer);
+            _PyFrame_StackPointerValidate(frame);
+            PyObject *v_o = _PyEval_LoadName(tstate, frame, name);
+            _PyFrame_StackPointerInvalidate(frame);
+            if (v_o == NULL) {
+                SET_CURRENT_CACHED_VALUES(0);
+                JUMP_TO_ERROR();
             }
             v = PyStackRef_FromPyObjectSteal(v_o);
             _tos_cache0 = v;
@@ -10669,6 +10691,17 @@
                     JUMP_TO_ERROR();
                 }
             }
+            else if (PyLazyImport_CheckExact(value_o)) {
+                assert(stack_pointer == _PyFrame_GetStackPointer(frame));
+                _PyFrame_StackPointerValidate(frame);
+                Py_SETREF(value_o, _PyLazyImport_Reify(
+                              tstate, value_o, name, class_dict));
+                _PyFrame_StackPointerInvalidate(frame);
+                if (value_o == NULL) {
+                    SET_CURRENT_CACHED_VALUES(0);
+                    JUMP_TO_ERROR();
+                }
+            }
             stack_pointer += -1;
             ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
             _PyFrame_SetStackPointer(frame, stack_pointer);
diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h
index d9fb82d713154ba..dd0ce41e4b06b4a 100644
--- a/Python/generated_cases.c.h
+++ b/Python/generated_cases.c.h
@@ -9912,6 +9912,16 @@
                     JUMP_TO_LABEL(error);
                 }
             }
+            else if (PyLazyImport_CheckExact(value_o)) {
+                assert(stack_pointer == _PyFrame_GetStackPointer(frame));
+                _PyFrame_StackPointerValidate(frame);
+                Py_SETREF(value_o, _PyLazyImport_Reify(
+                              tstate, value_o, name, class_dict));
+                _PyFrame_StackPointerInvalidate(frame);
+                if (value_o == NULL) {
+                    JUMP_TO_LABEL(error);
+                }
+            }
             stack_pointer += -1;
             ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
             _PyFrame_SetStackPointer(frame, stack_pointer);
@@ -9937,11 +9947,21 @@
             _PyStackRef v;
             mod_or_class_dict = stack_pointer[-1];
             PyObject *name = GETITEM(FRAME_CO_NAMES, oparg);
+            PyObject *namespace = 
PyStackRef_AsPyObjectBorrow(mod_or_class_dict);
             int err;
             _PyFrame_SetStackPointer(frame, stack_pointer);
             _PyFrame_StackPointerValidate(frame);
-            PyObject *v_o = 
_PyMapping_GetOptionalItem2(PyStackRef_AsPyObjectBorrow(mod_or_class_dict), 
name, &err);
+            PyObject *v_o = _PyMapping_GetOptionalItem2(namespace, name, &err);
             _PyFrame_StackPointerInvalidate(frame);
+            if (v_o != NULL && PyLazyImport_CheckExact(v_o)) {
+                assert(stack_pointer == _PyFrame_GetStackPointer(frame));
+                _PyFrame_StackPointerValidate(frame);
+                Py_SETREF(v_o, _PyLazyImport_Reify(tstate, v_o, name, 
namespace));
+                _PyFrame_StackPointerInvalidate(frame);
+                if (v_o == NULL) {
+                    err = -1;
+                }
+            }
             stack_pointer += -1;
             ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
             _PyFrame_SetStackPointer(frame, stack_pointer);
@@ -9952,81 +9972,17 @@
                 JUMP_TO_LABEL(error);
             }
             if (v_o == NULL) {
-                if (PyDict_CheckExact(GLOBALS())
-                    && PyDict_CheckExact(BUILTINS()))
-                {
-                    assert(stack_pointer == _PyFrame_GetStackPointer(frame));
-                    _PyFrame_StackPointerValidate(frame);
-                    v_o = _PyDict_LoadGlobal((PyDictObject *)GLOBALS(),
-                        (PyDictObject *)BUILTINS(),
-                        name);
-                    _PyFrame_StackPointerInvalidate(frame);
-                    if (v_o == NULL) {
-                        if (!_PyErr_Occurred(tstate)) {
-                            assert(stack_pointer == 
_PyFrame_GetStackPointer(frame));
-                            _PyFrame_StackPointerValidate(frame);
-                            _PyEval_FormatExcCheckArg(tstate, PyExc_NameError,
-                                NAME_ERROR_MSG, name);
-                            _PyFrame_StackPointerInvalidate(frame);
-                        }
-                        JUMP_TO_LABEL(error);
-                    }
-                    if (PyLazyImport_CheckExact(v_o)) {
-                        assert(stack_pointer == 
_PyFrame_GetStackPointer(frame));
-                        _PyFrame_StackPointerValidate(frame);
-                        PyObject *l_v = _PyImport_LoadLazyImportTstate(tstate, 
v_o);
-                        _PyFrame_StackPointerInvalidate(frame);
-                        assert(stack_pointer == 
_PyFrame_GetStackPointer(frame));
-                        _PyFrame_StackPointerValidate(frame);
-                        Py_SETREF(v_o, l_v);
-                        _PyFrame_StackPointerInvalidate(frame);
-                        if (v_o == NULL) {
-                            JUMP_TO_LABEL(error);
-                        }
-                    }
-                }
-                else {
-                    assert(stack_pointer == _PyFrame_GetStackPointer(frame));
-                    _PyFrame_StackPointerValidate(frame);
-                    v_o = _PyMapping_GetOptionalItem2(GLOBALS(), name, &err);
-                    _PyFrame_StackPointerInvalidate(frame);
-                    if (err < 0) {
-                        JUMP_TO_LABEL(error);
-                    }
-                    if (v_o == NULL) {
-                        assert(stack_pointer == 
_PyFrame_GetStackPointer(frame));
-                        _PyFrame_StackPointerValidate(frame);
-                        v_o = _PyMapping_GetOptionalItem2(BUILTINS(), name, 
&err);
-                        _PyFrame_StackPointerInvalidate(frame);
-                        if (err < 0) {
-                            JUMP_TO_LABEL(error);
-                        }
-                        if (v_o == NULL) {
-                            assert(stack_pointer == 
_PyFrame_GetStackPointer(frame));
-                            _PyFrame_StackPointerValidate(frame);
-                            _PyEval_FormatExcCheckArg(
-                                tstate, PyExc_NameError,
-                                NAME_ERROR_MSG, name);
-                            _PyFrame_StackPointerInvalidate(frame);
-                            JUMP_TO_LABEL(error);
-                        }
-                    }
-                    if (PyLazyImport_CheckExact(v_o)) {
-                        assert(stack_pointer == 
_PyFrame_GetStackPointer(frame));
-                        _PyFrame_StackPointerValidate(frame);
-                        PyObject *l_v = _PyImport_LoadLazyImportTstate(tstate, 
v_o);
-                        _PyFrame_StackPointerInvalidate(frame);
-                        assert(stack_pointer == 
_PyFrame_GetStackPointer(frame));
-                        _PyFrame_StackPointerValidate(frame);
-                        Py_SETREF(v_o, l_v);
-                        _PyFrame_StackPointerInvalidate(frame);
-                        if (v_o == NULL) {
-                            JUMP_TO_LABEL(error);
-                        }
-                    }
+                assert(stack_pointer == _PyFrame_GetStackPointer(frame));
+                _PyFrame_StackPointerValidate(frame);
+                _PyEval_LoadGlobalStackRef(GLOBALS(), BUILTINS(), name, &v);
+                _PyFrame_StackPointerInvalidate(frame);
+                if (PyStackRef_IsNull(v)) {
+                    JUMP_TO_LABEL(error);
                 }
             }
-            v = PyStackRef_FromPyObjectSteal(v_o);
+            else {
+                v = PyStackRef_FromPyObjectSteal(v_o);
+            }
             stack_pointer[0] = v;
             stack_pointer += 1;
             ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
@@ -10280,38 +10236,6 @@
             if (v_o == NULL) {
                 JUMP_TO_LABEL(error);
             }
-            if (PyLazyImport_CheckExact(v_o)) {
-                assert(stack_pointer == _PyFrame_GetStackPointer(frame));
-                _PyFrame_StackPointerValidate(frame);
-                PyObject *l_v = _PyImport_LoadLazyImportTstate(tstate, v_o);
-                _PyFrame_StackPointerInvalidate(frame);
-                if (l_v == NULL) {
-                    assert(stack_pointer == _PyFrame_GetStackPointer(frame));
-                    _PyFrame_StackPointerValidate(frame);
-                    Py_DECREF(v_o);
-                    _PyFrame_StackPointerInvalidate(frame);
-                    JUMP_TO_LABEL(error);
-                }
-                assert(stack_pointer == _PyFrame_GetStackPointer(frame));
-                _PyFrame_StackPointerValidate(frame);
-                int err = PyDict_SetItem(GLOBALS(), name, l_v);
-                _PyFrame_StackPointerInvalidate(frame);
-                if (err < 0) {
-                    assert(stack_pointer == _PyFrame_GetStackPointer(frame));
-                    _PyFrame_StackPointerValidate(frame);
-                    Py_DECREF(v_o);
-                    _PyFrame_StackPointerInvalidate(frame);
-                    assert(stack_pointer == _PyFrame_GetStackPointer(frame));
-                    _PyFrame_StackPointerValidate(frame);
-                    Py_DECREF(l_v);
-                    _PyFrame_StackPointerInvalidate(frame);
-                    JUMP_TO_LABEL(error);
-                }
-                assert(stack_pointer == _PyFrame_GetStackPointer(frame));
-                _PyFrame_StackPointerValidate(frame);
-                Py_SETREF(v_o, l_v);
-                _PyFrame_StackPointerInvalidate(frame);
-            }
             v = PyStackRef_FromPyObjectSteal(v_o);
             stack_pointer[0] = v;
             stack_pointer += 1;
diff --git a/Python/import.c b/Python/import.c
index 2fa63dd01833a64..576b8d47639fa4b 100644
--- a/Python/import.c
+++ b/Python/import.c
@@ -11,7 +11,6 @@
 #include "pycore_interp.h"        // struct _import_runtime_state
 #include "pycore_interpframe.h"
 #include "pycore_lazyimportobject.h"
-#include "pycore_long.h"          // _PyLong_GetZero
 #include "pycore_magic_number.h"  // PYC_MAGIC_NUMBER_TOKEN
 #include "pycore_moduleobject.h"  // _PyModule_GetDef()
 #include "pycore_namespace.h"     // _PyNamespace_Type
@@ -25,7 +24,6 @@
 #include "pycore_setobject.h"     // _PySet_NextEntry()
 #include "pycore_sysmodule.h"     // _PySys_ClearAttrString()
 #include "pycore_time.h"          // _PyTime_AsMicroseconds()
-#include "pycore_traceback.h"
 #include "pycore_unicodeobject.h" // _PyUnicode_AsUTF8NoNUL()
 #include "pycore_weakref.h"       // _PyWeakref_GET_REF()
 
@@ -3891,227 +3889,6 @@ resolve_name(PyThreadState *tstate, PyObject *name, 
PyObject *globals, int level
     return NULL;
 }
 
-PyObject *
-_PyImport_ResolveName(PyThreadState *tstate, PyObject *name,
-                      PyObject *globals, int level)
-{
-  return resolve_name(tstate, name, globals, level);
-}
-
-// Look up, in order, the attributes recorded from the root placeholder to lz
-// on the module the root's import returned.
-static PyObject *
-lazy_import_replay_from(PyThreadState *tstate, PyObject *mod,
-                        PyLazyImportObject *lz)
-{
-    if (!PyLazyImport_CheckExact(lz->lz_from)) {
-        return Py_NewRef(mod);
-    }
-    PyObject *from = lazy_import_replay_from(
-        tstate, mod, (PyLazyImportObject *)lz->lz_from);
-    if (from == NULL) {
-        return NULL;
-    }
-    PyObject *obj = _PyEval_ImportFrom(tstate, from, lz->lz_attr);
-    Py_DECREF(from);
-    return obj;
-}
-
-PyObject *
-_PyImport_LoadLazyImportTstate(PyThreadState *tstate, PyObject *lazy_import)
-{
-    PyObject *obj = NULL;
-    PyObject *fromlist = Py_None;
-    PyObject *import_func = NULL;
-    assert(lazy_import != NULL);
-    assert(PyLazyImport_CheckExact(lazy_import));
-
-    PyLazyImportObject *lz = (PyLazyImportObject *)lazy_import;
-    PyInterpreterState *interp = tstate->interp;
-
-    // Walk back to the placeholder IMPORT_NAME left, and the first lookup on 
it.
-    PyLazyImportObject *root = lz, *first = NULL;
-    while (PyLazyImport_CheckExact(root->lz_from)) {
-        first = root;
-        root = (PyLazyImportObject *)root->lz_from;
-    }
-
-    // Acquire the global import lock to serialize reification
-    _PyImport_AcquireLock(interp);
-
-    // Check if we are already importing this module, if so, then we want to
-    // return an error that indicates we've hit a cycle which will indicate
-    // the value isn't yet available.
-    PyObject *importing = interp->imports.lazy_importing_modules;
-    if (importing == NULL) {
-        importing = interp->imports.lazy_importing_modules = PySet_New(NULL);
-        if (importing == NULL) {
-            _PyImport_ReleaseLock(interp);
-            return NULL;
-        }
-    }
-
-    assert(PyAnySet_CheckExact(importing));
-    int is_loading = _PySet_Contains((PySetObject *)importing, lazy_import);
-    if (is_loading < 0) {
-        _PyImport_ReleaseLock(interp);
-        return NULL;
-    }
-    else if (is_loading == 1) {
-        PyObject *name = _PyLazyImport_GetName(lazy_import);
-        if (name == NULL) {
-            _PyImport_ReleaseLock(interp);
-            return NULL;
-        }
-        PyObject *errmsg = PyUnicode_FromFormat(
-            "cannot import name %R (most likely due to a circular import)",
-            name);
-        if (errmsg == NULL) {
-            Py_DECREF(name);
-            _PyImport_ReleaseLock(interp);
-            return NULL;
-        }
-        PyErr_SetImportErrorSubclass(PyExc_ImportCycleError, errmsg,
-                                     root->lz_from, NULL);
-        Py_DECREF(errmsg);
-        Py_DECREF(name);
-        _PyImport_ReleaseLock(interp);
-        return NULL;
-    }
-    else if (PySet_Add(importing, lazy_import) < 0) {
-        goto error;
-    }
-
-    if (root->lz_attr != NULL) {
-        // `from a import b, c`: import only the name being resolved.
-        // Keep an empty tuple intact for custom __import__ hooks.
-        fromlist = first && PyTuple_GET_SIZE(root->lz_attr) > 0
-            ? PyTuple_Pack(1, first->lz_attr)
-            : Py_NewRef(root->lz_attr);
-        if (fromlist == NULL) {
-            goto error;
-        }
-    }
-
-    PyObject *globals = PyEval_GetGlobals();
-
-    if (PyMapping_GetOptionalItem(root->lz_builtins, &_Py_ID(__import__),
-                                  &import_func) < 0) {
-        goto error;
-    }
-    if (import_func == NULL) {
-        PyErr_SetString(PyExc_ImportError, "__import__ not found");
-        goto error;
-    }
-    obj = _PyEval_ImportNameWithImport(
-        tstate, import_func, globals, globals,
-        root->lz_from, fromlist, _PyLong_GetZero()
-    );
-    if (obj == NULL) {
-        goto error;
-    }
-
-    PyObject *from = obj;
-    obj = lazy_import_replay_from(tstate, from, lz);
-    Py_DECREF(from);
-    if (obj == NULL) {
-        goto error;
-    }
-
-    assert(!PyLazyImport_CheckExact(obj));
-
-    goto ok;
-
-error:
-    Py_CLEAR(obj);
-
-    // If an error occurred and we have frame information, add it to the
-    // exception.
-    if (PyErr_Occurred() && lz->lz_code != NULL && lz->lz_instr_offset >= 0) {
-        // Get the current exception - this already has the full traceback
-        // from the access point.
-        PyObject *exc = _PyErr_GetRaisedException(tstate);
-
-        // Get import name - this can fail and set an exception.
-        PyObject *import_name = _PyLazyImport_GetName(lazy_import);
-        if (!import_name) {
-            // Failed to get import name, just restore original exception.
-            _PyErr_SetRaisedException(tstate, exc);
-            goto ok;
-        }
-
-        // Resolve line number from instruction offset on demand.
-        int lineno = PyCode_Addr2Line((PyCodeObject *)lz->lz_code,
-                                      lz->lz_instr_offset*2);
-
-        // Get strings - these can return NULL on encoding errors.
-        const char *filename_str = PyUnicode_AsUTF8(lz->lz_code->co_filename);
-        if (!filename_str) {
-            // Unicode conversion failed - clear error and restore original
-            // exception.
-            PyErr_Clear();
-            Py_DECREF(import_name);
-            _PyErr_SetRaisedException(tstate, exc);
-            goto ok;
-        }
-
-        const char *funcname_str = PyUnicode_AsUTF8(lz->lz_code->co_name);
-        if (!funcname_str) {
-            // Unicode conversion failed - clear error and restore original
-            // exception.
-            PyErr_Clear();
-            Py_DECREF(import_name);
-            _PyErr_SetRaisedException(tstate, exc);
-            goto ok;
-        }
-
-        // Create a cause exception showing where the lazy import was declared.
-        PyObject *msg = PyUnicode_FromFormat(
-            "lazy import of '%U' raised an exception during resolution",
-            import_name
-        );
-        Py_DECREF(import_name); // Done with import_name.
-
-        if (!msg) {
-            // Failed to create message - restore original exception.
-            _PyErr_SetRaisedException(tstate, exc);
-            goto ok;
-        }
-
-        PyObject *cause_exc = PyObject_CallOneArg(PyExc_ImportError, msg);
-        Py_DECREF(msg);  // Done with msg.
-
-        if (!cause_exc) {
-            // Failed to create exception - restore original.
-            _PyErr_SetRaisedException(tstate, exc);
-            goto ok;
-        }
-
-        // Add traceback entry for the lazy import declaration.
-        _PyErr_SetRaisedException(tstate, cause_exc);
-        _PyTraceback_Add(funcname_str, filename_str, lineno);
-        PyObject *cause_with_tb = _PyErr_GetRaisedException(tstate);
-
-        // Set the cause on the original exception.
-        PyException_SetCause(exc, cause_with_tb);  // Steals ref to 
cause_with_tb.
-
-        // Restore the original exception with its full traceback.
-        _PyErr_SetRaisedException(tstate, exc);
-    }
-
-ok:
-    if (PySet_Discard(importing, lazy_import) < 0) {
-        Py_CLEAR(obj);
-    }
-
-    // Release the global import lock.
-    _PyImport_ReleaseLock(interp);
-
-    Py_XDECREF(fromlist);
-    Py_XDECREF(import_func);
-    return obj;
-}
-
 static PyObject *
 import_find_and_load_with_name(PyThreadState *tstate, PyObject *abs_name,
                                PyObject *find_and_load,
@@ -4180,9 +3957,9 @@ import_find_and_load(PyThreadState *tstate, PyObject 
*abs_name)
         tstate, abs_name, &_Py_ID(_find_and_load), NULL);
 }
 
-static PyObject *
-get_abs_name(PyThreadState *tstate, PyObject *name, PyObject *globals,
-             int level)
+PyObject *
+_PyImport_GetAbsName(PyThreadState *tstate, PyObject *name, PyObject *globals,
+                     int level)
 {
     if (level > 0) {
         return resolve_name(tstate, name, globals, level);
@@ -4194,13 +3971,6 @@ get_abs_name(PyThreadState *tstate, PyObject *name, 
PyObject *globals,
     return Py_NewRef(name);
 }
 
-PyObject *
-_PyImport_GetAbsName(PyThreadState *tstate, PyObject *name,
-                     PyObject *globals, int level)
-{
-    return get_abs_name(tstate, name, globals, level);
-}
-
 
 PyObject *
 PyImport_ImportModuleLevelObject(PyObject *name, PyObject *globals,
@@ -4232,7 +4002,7 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject 
*globals,
         goto error;
     }
 
-    abs_name = get_abs_name(tstate, name, globals, level);
+    abs_name = _PyImport_GetAbsName(tstate, name, globals, level);
     if (abs_name == NULL) {
         goto error;
     }
@@ -4358,7 +4128,7 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject 
*globals,
     return final_mod;
 }
 
-// ensure we have the set for the parent module name in sys.lazy_modules.
+// Ensure a set of pending submodule names exists for the parent.
 // Returns a new reference.
 static PyObject *
 ensure_lazy_pending_submodules(PyDictObject *lazy_modules, PyObject *parent)
@@ -4387,59 +4157,35 @@ ensure_lazy_pending_submodules(PyDictObject 
*lazy_modules, PyObject *parent)
 static int
 register_lazy_on_parent(PyThreadState *tstate, PyObject *name)
 {
-    int ret = -1;
-    PyObject *parent = NULL;
-    PyObject *child = NULL;
-
-    PyInterpreterState *interp = tstate->interp;
-    PyObject *lazy_pending_submodules = LAZY_PENDING_SUBMODULES(interp);
-    assert(lazy_pending_submodules != NULL);
-
-    Py_INCREF(name);
+    PyDictObject *pending =
+        (PyDictObject *)LAZY_PENDING_SUBMODULES(tstate->interp);
+    assert(pending != NULL);
+    Py_ssize_t end = PyUnicode_GET_LENGTH(name);
     while (true) {
-        Py_ssize_t dot = PyUnicode_FindChar(name, '.', 0,
-                                            PyUnicode_GET_LENGTH(name), -1);
+        Py_ssize_t dot = PyUnicode_FindChar(name, '.', 0, end, -1);
         if (dot < 0) {
-            PyObject *lazy_submodules = ensure_lazy_pending_submodules(
-                (PyDictObject *)lazy_pending_submodules, name);
-            if (lazy_submodules == NULL) {
-                goto done;
-            }
-            Py_DECREF(lazy_submodules);
-            ret = 0;
-            goto done;
+            return dot == -1 ? 0 : -1;
         }
-        parent = PyUnicode_Substring(name, 0, dot);
+        PyObject *parent = PyUnicode_Substring(name, 0, dot);
         if (parent == NULL) {
-            goto done;
+            return -1;
         }
-        Py_XDECREF(child);
-        child = PyUnicode_Substring(name, dot + 1, PyUnicode_GET_LENGTH(name));
+        PyObject *child = PyUnicode_Substring(name, dot + 1, end);
         if (child == NULL) {
-            goto done;
-        }
-
-        PyObject *lazy_submodules = ensure_lazy_pending_submodules(
-            (PyDictObject *)lazy_pending_submodules, parent);
-        if (lazy_submodules == NULL) {
-            goto done;
+            Py_DECREF(parent);
+            return -1;
         }
 
-        if (PySet_Add(lazy_submodules, child) < 0) {
-            Py_DECREF(lazy_submodules);
-            goto done;
+        PyObject *submodules = ensure_lazy_pending_submodules(pending, parent);
+        Py_DECREF(parent);
+        int err = submodules == NULL ? -1 : PySet_Add(submodules, child);
+        Py_DECREF(child);
+        Py_XDECREF(submodules);
+        if (err < 0) {
+            return -1;
         }
-        Py_DECREF(lazy_submodules);
-
-        Py_SETREF(name, parent);
-        parent = NULL;
+        end = dot;
     }
-
-done:
-    Py_XDECREF(child);
-    Py_XDECREF(parent);
-    Py_XDECREF(name);
-    return ret;
 }
 
 static int
@@ -4453,80 +4199,65 @@ register_from_lazy_on_parent(PyThreadState *tstate, 
PyObject *abs_name,
 
     // Add the module name to sys.lazy_modules set (PEP 810).
     PyObject *lazy_modules = LAZY_MODULES(tstate->interp);
-    if (PySet_Add(lazy_modules, fromname) < 0) {
-        Py_DECREF(fromname);
-        return -1;
+    int res = PySet_Add(lazy_modules, fromname);
+    if (res == 0) {
+        res = register_lazy_on_parent(tstate, fromname);
     }
-
-    int res = register_lazy_on_parent(tstate, fromname);
     Py_DECREF(fromname);
     return res;
 }
 
-_PyLazySubmoduleImportResult
-_PyImport_TryLoadLazySubmodule(PyObject *mod_name, PyObject *attr_name,
-                               PyObject **result)
+PyObject *
+_PyImport_TryLoadLazySubmodule(PyObject *module, PyObject *attr_name,
+                              int *recheck_dict)
 {
-    assert(result != NULL);
-    *result = NULL;
-
-    PyThreadState *tstate = _PyThreadState_GET();
-    PyInterpreterState *interp = tstate->interp;
-    PyObject *lazy_pending = LAZY_PENDING_SUBMODULES(interp);
-    if (lazy_pending == NULL) {
-        return _Py_LAZY_SUBMODULE_NOT_FOUND;
+    *recheck_dict = 0;
+    PyObject *mod_dict = _PyModule_GetDict(module);
+    PyObject *mod_name;
+    if (PyDict_GetItemRef(mod_dict, &_Py_ID(__name__), &mod_name) <= 0) {
+        return NULL;
     }
-
-    PyObject *pending_set;
-    int rc = PyDict_GetItemRef(lazy_pending, mod_name, &pending_set);
-    if (rc < 0) {
-        return _Py_LAZY_SUBMODULE_ERROR;
+    PyObject *mod = NULL, *pending_set = NULL;
+    if (!PyUnicode_Check(mod_name)) {
+        goto done;
     }
-    if (rc == 0) {
-        return _Py_LAZY_SUBMODULE_NOT_FOUND;
+    PyThreadState *tstate = _PyThreadState_GET();
+    PyObject *lazy_pending = LAZY_PENDING_SUBMODULES(tstate->interp);
+    if (lazy_pending == NULL ||
+        PyDict_GetItemRef(lazy_pending, mod_name, &pending_set) <= 0) {
+        goto done;
     }
 
-    int contains = PySet_Contains(pending_set, attr_name);
-    if (contains < 0) {
-        Py_DECREF(pending_set);
-        return _Py_LAZY_SUBMODULE_ERROR;
-    }
-    if (contains == 0) {
-        Py_DECREF(pending_set);
-        return _Py_LAZY_SUBMODULE_NOT_FOUND;
+    *recheck_dict = 1;
+    if (PySet_Contains(pending_set, attr_name) <= 0) {
+        goto done;
     }
-
     PyObject *full_name = PyUnicode_FromFormat("%U.%U", mod_name, attr_name);
     if (full_name == NULL) {
-        Py_DECREF(pending_set);
-        return _Py_LAZY_SUBMODULE_ERROR;
+        goto done;
     }
-
-    PyObject *mod = import_find_and_load_with_name(
-        tstate, full_name, &_Py_ID(_find_and_load_lazy_submodule), Py_None);
+    // Match eager from-imports: accept a partial module in an import cycle.
+    mod = PyImport_GetModule(full_name);
+    if ((mod == NULL && !PyErr_Occurred()) || mod == Py_None) {
+        Py_XDECREF(mod);
+        mod = import_find_and_load_with_name(
+            tstate, full_name, &_Py_ID(_find_and_load_lazy_submodule), 
Py_None);
+    }
+    Py_DECREF(full_name);
     if (mod == NULL) {
-        Py_DECREF(pending_set);
-        Py_DECREF(full_name);
         remove_importlib_frames(tstate);
-        return _Py_LAZY_SUBMODULE_ERROR;
     }
-    if (mod == Py_None) {
-        Py_DECREF(mod);
-        Py_DECREF(pending_set);
-        Py_DECREF(full_name);
-        return _Py_LAZY_SUBMODULE_NOT_FOUND;
+    /* Keep missing children pending: a finder may provide them later. */
+    else if (mod == Py_None ||
+             PyDict_SetItem(mod_dict, attr_name, mod) < 0 ||
+             PySet_Discard(pending_set, attr_name) < 0) {
+        Py_CLEAR(mod);
     }
 
-    if (PySet_Discard(pending_set, attr_name) < 0) {
-        Py_DECREF(mod);
-        Py_DECREF(pending_set);
-        Py_DECREF(full_name);
-        return _Py_LAZY_SUBMODULE_ERROR;
-    }
-    Py_DECREF(pending_set);
-    Py_DECREF(full_name);
-    *result = mod;
-    return _Py_LAZY_SUBMODULE_LOADED;
+done:
+    Py_XDECREF(pending_set);
+    Py_DECREF(mod_name);
+    return mod;
 }
 
 PyObject *
@@ -4546,12 +4277,11 @@ _PyImport_LazyImportModuleLevelObject(PyThreadState 
*tstate,
         return NULL;
     }
 
-    PyObject *abs_name = get_abs_name(tstate, name, globals, level);
+    PyObject *abs_name = _PyImport_GetAbsName(tstate, name, globals, level);
     if (abs_name == NULL) {
         return NULL;
     }
 
-    PyInterpreterState *interp = tstate->interp;
     _PyInterpreterFrame *frame = _PyEval_GetFrame();
     if (frame == NULL || frame->f_globals != frame->f_locals) {
         Py_DECREF(abs_name);
@@ -4560,71 +4290,69 @@ _PyImport_LazyImportModuleLevelObject(PyThreadState 
*tstate,
         return NULL;
     }
 
+    PyObject *res = NULL;
+    if (fromlist != NULL && PyUnicode_Check(fromlist)) {
+        fromlist = PyTuple_Pack(1, fromlist);
+        if (fromlist == NULL) {
+            goto done;
+        }
+    }
+    else {
+        fromlist = Py_NewRef(fromlist != NULL ? fromlist : Py_None);
+    }
+
     // Check if the filter disables the lazy import.
-    // We must hold a reference to the filter while calling it to prevent
-    // use-after-free if another thread replaces it via
-    // PyImport_SetLazyImportsFilter.
-    LAZY_IMPORTS_LOCK(interp);
-    PyObject *filter = Py_XNewRef(LAZY_IMPORTS_FILTER(interp));
-    LAZY_IMPORTS_UNLOCK(interp);
+    PyObject *filter = PyImport_GetLazyImportsFilter();
 
     if (filter != NULL) {
         PyObject *modname;
         if (PyDict_GetItemRef(globals, &_Py_ID(__name__), &modname) < 0) {
             Py_DECREF(filter);
-            Py_DECREF(abs_name);
-            return NULL;
+            goto done;
         }
         if (modname == NULL) {
             assert(!PyErr_Occurred());
             modname = Py_NewRef(Py_None);
         }
-        if (fromlist == NULL) {
-            assert(!PyErr_Occurred());
-            fromlist = Py_None;
-        }
         PyObject *args[] = {modname, abs_name, fromlist};
-        PyObject *res = PyObject_Vectorcall(filter, args, 3, NULL);
+        PyObject *decision = PyObject_Vectorcall(filter, args, 3, NULL);
 
         Py_DECREF(modname);
         Py_DECREF(filter);
 
-        if (res == NULL) {
-            Py_DECREF(abs_name);
-            return NULL;
+        if (decision == NULL) {
+            goto done;
         }
 
-        int is_true = PyObject_IsTrue(res);
-        Py_DECREF(res);
+        int is_true = PyObject_IsTrue(decision);
+        Py_DECREF(decision);
 
         if (is_true < 0) {
-            Py_DECREF(abs_name);
-            return NULL;
+            goto done;
         }
         if (!is_true) {
-            Py_DECREF(abs_name);
-            return PyImport_ImportModuleLevelObject(
+            res = PyImport_ImportModuleLevelObject(
                 name, globals, locals, fromlist, level
             );
+            goto done;
         }
     }
 
-    // here, 'filter' is either NULL or is equivalent to a borrowed reference
-    if (fromlist && PyUnicode_Check(fromlist)) {
-        fromlist = PyTuple_Pack(1, fromlist);
-        if (fromlist == NULL) {
-            Py_DECREF(abs_name);
-            return NULL;
+    // Validate the entire fromlist before registering any pending imports.
+    if (PyTuple_Check(fromlist)) {
+        for (Py_ssize_t i = 0; i < PyTuple_GET_SIZE(fromlist); i++) {
+            PyObject *item = PyTuple_GET_ITEM(fromlist, i);
+            if (!PyUnicode_Check(item)) {
+                _PyErr_Format(tstate, PyExc_TypeError,
+                              "Item in ``from list'' must be str, not %.200s",
+                              Py_TYPE(item)->tp_name);
+                goto done;
+            }
         }
     }
-    else {
-        Py_XINCREF(fromlist);
-    }
-    PyObject *res = _PyLazyImport_New(frame, builtins, abs_name, fromlist);
+    res = _PyLazyImport_New(frame, builtins, abs_name, fromlist);
     if (res == NULL) {
-        Py_XDECREF(fromlist);
-        Py_DECREF(abs_name);
-        return NULL;
+        goto done;
     }
 
     // Add the module name to sys.lazy_modules set (PEP 810).
@@ -4633,7 +4361,7 @@ _PyImport_LazyImportModuleLevelObject(PyThreadState 
*tstate,
         goto error;
     }
 
-    if (fromlist && PyTuple_Check(fromlist) && PyTuple_GET_SIZE(fromlist)) {
+    if (PyTuple_Check(fromlist) && PyTuple_GET_SIZE(fromlist)) {
         for (Py_ssize_t i = 0; i < PyTuple_GET_SIZE(fromlist); i++) {
             if (register_from_lazy_on_parent(tstate, abs_name,
                                              PyTuple_GET_ITEM(fromlist, i)) < 
0)
@@ -4646,14 +4374,13 @@ _PyImport_LazyImportModuleLevelObject(PyThreadState 
*tstate,
         goto error;
     }
 
-    Py_XDECREF(fromlist);
-    Py_DECREF(abs_name);
-    return res;
+    goto done;
 error:
+    Py_CLEAR(res);
+done:
     Py_XDECREF(fromlist);
     Py_DECREF(abs_name);
-    Py_DECREF(res);
-    return NULL;
+    return res;
 }
 
 PyObject *
@@ -4865,7 +4592,6 @@ _PyImport_ClearCore(PyInterpreterState *interp)
     Py_CLEAR(LAZY_IMPORT_FUNC(interp));
     Py_CLEAR(interp->imports.lazy_pending_submodules);
     Py_CLEAR(interp->imports.lazy_modules);
-    Py_CLEAR(interp->imports.lazy_importing_modules);
     Py_CLEAR(interp->imports.lazy_imports_filter);
 }
 
@@ -5660,13 +5386,13 @@ _imp._set_lazy_attributes
     modobj: object
     name: unicode
     /
-Sets attributes to lazy submodules on the module, as side effects.
+Remove the resolved module name from sys.lazy_modules.
 [clinic start generated code]*/
 
 static PyObject *
 _imp__set_lazy_attributes_impl(PyObject *module, PyObject *modobj,
                                PyObject *name)
-/*[clinic end generated code: output=3369bb3242b1f043 input=38ea6f30956dd7d6]*/
+/*[clinic end generated code: output=3369bb3242b1f043 input=900339e013ab2b82]*/
 {
     PyInterpreterState *interp = _PyInterpreterState_GET();
     if (PySet_Discard(LAZY_MODULES(interp), name) < 0) {
diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h
index bd3ed9ce99a555d..9cd20c495db4418 100644
--- a/Python/optimizer_cases.c.h
+++ b/Python/optimizer_cases.c.h
@@ -2176,7 +2176,12 @@
             break;
         }
 
-        /* _LOAD_FROM_DICT_OR_GLOBALS is not a viable micro-op for tier 2 */
+        case _LOAD_FROM_DICT_OR_GLOBALS: {
+            JitOptRef v;
+            v = sym_new_not_null(ctx);
+            stack_pointer[-1] = v;
+            break;
+        }
 
         case _LOAD_NAME: {
             JitOptRef v;
diff --git a/Python/pystate.c b/Python/pystate.c
index 76ad958478a3ca9..97323ea2ba2bce1 100644
--- a/Python/pystate.c
+++ b/Python/pystate.c
@@ -1630,6 +1630,7 @@ init_threadstate(_PyThreadStateImpl *_tstate,
 
     _tstate->asyncio_running_loop = NULL;
     _tstate->asyncio_running_task = NULL;
+    _tstate->lazy_imports = NULL;
 
 #ifdef _Py_TIER2
     _tstate->jit_tracer_state = NULL;
@@ -1873,6 +1874,9 @@ PyThreadState_Clear(PyThreadState *tstate)
 
     Py_CLEAR(tstate->context);
 
+    // Finalizers above may resolve imports and create this set.
+    Py_CLEAR(((_PyThreadStateImpl *)tstate)->lazy_imports);
+
 #ifdef Py_GIL_DISABLED
     // Each thread should clear own freelists in free-threading builds.
     struct _Py_freelists *freelists = _Py_freelists_GET();

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to