@@ -361,6 +361,7 @@ def __init__(self, name, loader, *, origin=None, loader_state=None,
361361 self .origin = origin
362362 self .loader_state = loader_state
363363 self .submodule_search_locations = [] if is_package else None
364+ self ._uninitialized_submodules = []
364365
365366 # file-location attributes
366367 self ._set_fileattr = False
@@ -987,6 +988,7 @@ def _sanity_check(name, package, level):
987988def _find_and_load_unlocked (name , import_ ):
988989 path = None
989990 parent = name .rpartition ('.' )[0 ]
991+ parent_spec = None
990992 if parent :
991993 if parent not in sys .modules :
992994 _call_with_frames_removed (import_ , parent )
@@ -999,15 +1001,24 @@ def _find_and_load_unlocked(name, import_):
9991001 except AttributeError :
10001002 msg = (_ERR_MSG + '; {!r} is not a package' ).format (name , parent )
10011003 raise ModuleNotFoundError (msg , name = name ) from None
1004+ parent_spec = parent_module .__spec__
1005+ child = name .rpartition ('.' )[2 ]
10021006 spec = _find_spec (name , path )
10031007 if spec is None :
10041008 raise ModuleNotFoundError (_ERR_MSG .format (name ), name = name )
10051009 else :
1006- module = _load_unlocked (spec )
1010+ if parent_spec :
1011+ # Temporarily add child we are currently importing to parent's
1012+ # _uninitialized_submodules for circular import tracking.
1013+ parent_spec ._uninitialized_submodules .append (child )
1014+ try :
1015+ module = _load_unlocked (spec )
1016+ finally :
1017+ if parent_spec :
1018+ parent_spec ._uninitialized_submodules .pop ()
10071019 if parent :
10081020 # Set the module as an attribute on its parent.
10091021 parent_module = sys .modules [parent ]
1010- child = name .rpartition ('.' )[2 ]
10111022 try :
10121023 setattr (parent_module , child , module )
10131024 except AttributeError :
0 commit comments