@@ -4101,7 +4101,7 @@ _PyImport_LoadLazyImportTstate(PyThreadState *tstate, PyObject *lazy_import)
41014101 }
41024102 else if (obj != NULL ) {
41034103 // Cache the result and update the original global before releasing
4104- // the import lock, so competing reification cannot import again .
4104+ // the import lock, so later reification through this proxy reuses it .
41054105 if (_PyLazyImport_FinishResolve (lazy_import , obj ) < 0 ) {
41064106 Py_CLEAR (obj );
41074107 }
@@ -4455,8 +4455,10 @@ register_from_lazy_on_parent(PyThreadState *tstate, PyObject *abs_name,
44554455static int
44564456is_module_not_found_for_name (PyThreadState * tstate , PyObject * name )
44574457{
4458- // Return true only for "name itself was not found", consuming the current
4459- // exception so callers can continue normal attribute fallback.
4458+ // Return true only for the importlib._handle_fromlist() compatibility
4459+ // case where "name itself was not found" and sys.modules[name] is not the
4460+ // None sentinel. Consume the current exception so callers can continue
4461+ // normal attribute fallback.
44604462 if (!_PyErr_ExceptionMatches (tstate , PyExc_ModuleNotFoundError )) {
44614463 return 0 ;
44624464 }
@@ -4479,6 +4481,18 @@ is_module_not_found_for_name(PyThreadState *tstate, PyObject *name)
44794481 return 0 ;
44804482 }
44814483
4484+ PyObject * mod = import_get_module (tstate , name );
4485+ if (mod == Py_None ) {
4486+ Py_DECREF (mod );
4487+ _PyErr_SetRaisedException (tstate , exc );
4488+ return 0 ;
4489+ }
4490+ if (mod == NULL && _PyErr_Occurred (tstate )) {
4491+ PyErr_Clear ();
4492+ _PyErr_SetRaisedException (tstate , exc );
4493+ return 0 ;
4494+ }
4495+ Py_XDECREF (mod );
44824496 Py_DECREF (exc );
44834497 return 1 ;
44844498}
@@ -4554,7 +4568,12 @@ _PyImport_TryLoadLazySubmodule(PyObject *mod_name, PyObject *attr_name,
45544568 return -1 ;
45554569 }
45564570
4557- if (PySet_Discard (pending_set , attr_name ) < 0 ) {
4571+ // This completes the successful lazy-submodule publish. pending_set is an
4572+ // internal set and attr_name is a Unicode attribute name, so discard is not
4573+ // expected to fail after the parent dict has been updated.
4574+ int discard_rc = PySet_Discard (pending_set , attr_name );
4575+ assert (discard_rc >= 0 );
4576+ if (discard_rc < 0 ) {
45584577 Py_DECREF (pending_set );
45594578 Py_DECREF (submod );
45604579 return -1 ;
0 commit comments