Add import_ensure_initialized to import_module_level (#7076)

Wait for module initialization to complete when a module is
already in sys.modules but still being initialized by another
thread. Check __spec__._initializing and call
_lock_unlock_module to block until the import finishes.
This commit is contained in:
Jeong, YunWon authored and GitHub committed 2026-02-11 10:57:10 +09:00
1 parent d567e25ac9
commit 1fa991de09
1 file changed
+25 -1
+25 -1
View File
@@ -153,6 +153,27 @@ pub fn import_source(vm: &VirtualMachine, module_name: &str, content: &str) -> P
import_code_obj(vm, module_name, code, false)
}
/// If `__spec__._initializing` is true, wait for the module to finish
/// initializing by calling `_lock_unlock_module`.
fn import_ensure_initialized(
module: &PyObjectRef,
name: &str,
vm: &VirtualMachine,
) -> PyResult<()> {
let initializing = match vm.get_attribute_opt(module.clone(), vm.ctx.intern_str("__spec__"))? {
Some(spec) => match vm.get_attribute_opt(spec, vm.ctx.intern_str("_initializing"))? {
Some(v) => v.try_to_bool(vm)?,
None => false,
},
None => false,
};
if initializing {
let lock_unlock = vm.importlib.get_attr("_lock_unlock_module", vm)?;
lock_unlock.call((vm.ctx.new_str(name),), vm)?;
}
Ok(())
}
pub fn import_code_obj(
vm: &VirtualMachine,
module_name: &str,
@@ -405,7 +426,10 @@ pub(crate) fn import_module_level(
// import_get_module + import_find_and_load
let sys_modules = vm.sys_module.get_attr("modules", vm)?;
let module = match sys_modules.get_item(&*abs_name, vm) {
Ok(m) if !vm.is_none(&m) => m,
Ok(m) if !vm.is_none(&m) => {
import_ensure_initialized(&m, &abs_name, vm)?;
m
}
_ => {
let find_and_load = vm.importlib.get_attr("_find_and_load", vm)?;
let abs_name_obj = vm.ctx.new_str(&*abs_name);