summaryrefslogtreecommitdiffstats
path: root/Lib/importlib/util.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/importlib/util.py')
-rw-r--r--Lib/importlib/util.py72
1 files changed, 72 insertions, 0 deletions
diff --git a/Lib/importlib/util.py b/Lib/importlib/util.py
index 42fc9ea..6d73b1d 100644
--- a/Lib/importlib/util.py
+++ b/Lib/importlib/util.py
@@ -7,6 +7,7 @@ from ._bootstrap import source_from_cache
from ._bootstrap import spec_from_loader
from ._bootstrap import spec_from_file_location
from ._bootstrap import _resolve_name
+from ._bootstrap import _find_spec
from contextlib import contextmanager
import functools
@@ -29,6 +30,77 @@ def resolve_name(name, package):
return _resolve_name(name[level:], package, level)
+def _find_spec_from_path(name, path=None):
+ """Return the spec for the specified module.
+
+ First, sys.modules is checked to see if the module was already imported. If
+ so, then sys.modules[name].__spec__ is returned. If that happens to be
+ set to None, then ValueError is raised. If the module is not in
+ sys.modules, then sys.meta_path is searched for a suitable spec with the
+ value of 'path' given to the finders. None is returned if no spec could
+ be found.
+
+ Dotted names do not have their parent packages implicitly imported. You will
+ most likely need to explicitly import all parent packages in the proper
+ order for a submodule to get the correct spec.
+
+ """
+ if name not in sys.modules:
+ return _find_spec(name, path)
+ else:
+ module = sys.modules[name]
+ if module is None:
+ return None
+ try:
+ spec = module.__spec__
+ except AttributeError:
+ raise ValueError('{}.__spec__ is not set'.format(name))
+ else:
+ if spec is None:
+ raise ValueError('{}.__spec__ is None'.format(name))
+ return spec
+
+
+def find_spec(name, package=None):
+ """Return the spec for the specified module.
+
+ First, sys.modules is checked to see if the module was already imported. If
+ so, then sys.modules[name].__spec__ is returned. If that happens to be
+ set to None, then ValueError is raised. If the module is not in
+ sys.modules, then sys.meta_path is searched for a suitable spec with the
+ value of 'path' given to the finders. None is returned if no spec could
+ be found.
+
+ If the name is for submodule (contains a dot), the parent module is
+ automatically imported.
+
+ The name and package arguments work the same as importlib.import_module().
+ In other words, relative module names (with leading dots) work.
+
+ """
+ fullname = resolve_name(name, package) if name.startswith('.') else name
+ if fullname not in sys.modules:
+ parent_name = fullname.rpartition('.')[0]
+ if parent_name:
+ # Use builtins.__import__() in case someone replaced it.
+ parent = __import__(parent_name, fromlist=['__path__'])
+ return _find_spec(fullname, parent.__path__)
+ else:
+ return _find_spec(fullname, None)
+ else:
+ module = sys.modules[fullname]
+ if module is None:
+ return None
+ try:
+ spec = module.__spec__
+ except AttributeError:
+ raise ValueError('{}.__spec__ is not set'.format(name))
+ else:
+ if spec is None:
+ raise ValueError('{}.__spec__ is None'.format(name))
+ return spec
+
+
@contextmanager
def _module_to_load(name):
is_reload = name in sys.modules