@@ -1363,19 +1363,38 @@ impl ExecutingFrame<'_> {
13631363 fn import_from ( & mut self , vm : & VirtualMachine , idx : bytecode:: NameIdx ) -> PyResult {
13641364 let module = self . top_value ( ) ;
13651365 let name = self . code . names [ idx as usize ] ;
1366- let err = || vm . new_import_error ( format ! ( "cannot import name '{name}'" ) , name . to_owned ( ) ) ;
1366+
13671367 // Load attribute, and transform any error into import error.
13681368 if let Some ( obj) = vm. get_attribute_opt ( module. to_owned ( ) , name) ? {
13691369 return Ok ( obj) ;
13701370 }
13711371 // fallback to importing '{module.__name__}.{name}' from sys.modules
1372- let mod_name = module
1373- . get_attr ( identifier ! ( vm, __name__) , vm)
1374- . map_err ( |_| err ( ) ) ?;
1375- let mod_name = mod_name. downcast :: < PyStr > ( ) . map_err ( |_| err ( ) ) ?;
1376- let full_mod_name = format ! ( "{mod_name}.{name}" ) ;
1377- let sys_modules = vm. sys_module . get_attr ( "modules" , vm) . map_err ( |_| err ( ) ) ?;
1378- sys_modules. get_item ( & full_mod_name, vm) . map_err ( |_| err ( ) )
1372+ let fallback_module = ( || {
1373+ let mod_name = module. get_attr ( identifier ! ( vm, __name__) , vm) . ok ( ) ?;
1374+ let mod_name = mod_name. downcast_ref :: < PyStr > ( ) ?;
1375+ let full_mod_name = format ! ( "{mod_name}.{name}" ) ;
1376+ let sys_modules = vm. sys_module . get_attr ( "modules" , vm) . ok ( ) ?;
1377+ sys_modules. get_item ( & full_mod_name, vm) . ok ( )
1378+ } ) ( ) ;
1379+
1380+ if let Some ( sub_module) = fallback_module {
1381+ return Ok ( sub_module) ;
1382+ }
1383+
1384+ if is_module_initializing ( module, vm) {
1385+ let module_name = module
1386+ . get_attr ( identifier ! ( vm, __name__) , vm)
1387+ . ok ( )
1388+ . and_then ( |n| n. downcast_ref :: < PyStr > ( ) . map ( |s| s. as_str ( ) . to_owned ( ) ) )
1389+ . unwrap_or_else ( || "<unknown>" . to_owned ( ) ) ;
1390+
1391+ let msg = format ! (
1392+ "cannot import name '{name}' from partially initialized module '{module_name}' (most likely due to a circular import)" ,
1393+ ) ;
1394+ Err ( vm. new_import_error ( msg, name. to_owned ( ) ) )
1395+ } else {
1396+ Err ( vm. new_import_error ( format ! ( "cannot import name '{name}'" ) , name. to_owned ( ) ) )
1397+ }
13791398 }
13801399
13811400 #[ cfg_attr( feature = "flame-it" , flame( "Frame" ) ) ]
@@ -2372,3 +2391,16 @@ impl fmt::Debug for Frame {
23722391 )
23732392 }
23742393}
2394+
2395+ fn is_module_initializing ( module : & PyObject , vm : & VirtualMachine ) -> bool {
2396+ let Ok ( spec) = module. get_attr ( & vm. ctx . new_str ( "__spec__" ) , vm) else {
2397+ return false ;
2398+ } ;
2399+ if vm. is_none ( & spec) {
2400+ return false ;
2401+ }
2402+ let Ok ( initializing_attr) = spec. get_attr ( & vm. ctx . new_str ( "_initializing" ) , vm) else {
2403+ return false ;
2404+ } ;
2405+ initializing_attr. try_to_bool ( vm) . unwrap_or ( false )
2406+ }
0 commit comments