aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Lib/importlib/_bootstrap.py
diff options
context:
space:
mode:
authorFilipe Laíns <lains@riseup.net>2021-07-24 10:50:17 +0100
committerGitHub <noreply@github.com>2021-07-24 11:50:17 +0200
commit8072a1181dd64135f700b44372fbf7bf91e68072 (patch)
tree23ba5f22841e1f5a739d6d6d54ee0f29e094f997 /Lib/importlib/_bootstrap.py
parent5370f0a82aaa4ba617070d5c71d2b18236096ac0 (diff)
downloadcpython-8072a1181dd64135f700b44372fbf7bf91e68072.tar.gz
cpython-8072a1181dd64135f700b44372fbf7bf91e68072.zip
bpo-44717: improve AttributeError on circular imports of submodules (GH-27299)
Signed-off-by: Filipe Laíns <lains@riseup.net> Co-authored-by: Łukasz Langa <lukasz@langa.pl>
Diffstat (limited to 'Lib/importlib/_bootstrap.py')
-rw-r--r--Lib/importlib/_bootstrap.py15
1 files changed, 13 insertions, 2 deletions
diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py
index 527bc9c63c9..f8b77e3b59d 100644
--- a/Lib/importlib/_bootstrap.py
+++ b/Lib/importlib/_bootstrap.py
@@ -361,6 +361,7 @@ class ModuleSpec:
self.origin = origin
self.loader_state = loader_state
self.submodule_search_locations = [] if is_package else None
+ self._uninitialized_submodules = []
# file-location attributes
self._set_fileattr = False
@@ -987,6 +988,7 @@ _ERR_MSG = _ERR_MSG_PREFIX + '{!r}'
def _find_and_load_unlocked(name, import_):
path = None
parent = name.rpartition('.')[0]
+ parent_spec = None
if parent:
if parent not in sys.modules:
_call_with_frames_removed(import_, parent)
@@ -999,15 +1001,24 @@ def _find_and_load_unlocked(name, import_):
except AttributeError:
msg = (_ERR_MSG + '; {!r} is not a package').format(name, parent)
raise ModuleNotFoundError(msg, name=name) from None
+ parent_spec = parent_module.__spec__
+ child = name.rpartition('.')[2]
spec = _find_spec(name, path)
if spec is None:
raise ModuleNotFoundError(_ERR_MSG.format(name), name=name)
else:
- module = _load_unlocked(spec)
+ if parent_spec:
+ # Temporarily add child we are currently importing to parent's
+ # _uninitialized_submodules for circular import tracking.
+ parent_spec._uninitialized_submodules.append(child)
+ try:
+ module = _load_unlocked(spec)
+ finally:
+ if parent_spec:
+ parent_spec._uninitialized_submodules.pop()
if parent:
# Set the module as an attribute on its parent.
parent_module = sys.modules[parent]
- child = name.rpartition('.')[2]
try:
setattr(parent_module, child, module)
except AttributeError: