diff options
author | Brett Cannon <bcannon@gmail.com> | 2009-02-06 02:47:33 (GMT) |
---|---|---|
committer | Brett Cannon <bcannon@gmail.com> | 2009-02-06 02:47:33 (GMT) |
commit | 7f9876c0daf73b1da3a7bc3ab62add0d1b10706a (patch) | |
tree | 65c2e0a352b057d075cb21fc70af5e0b0194a123 | |
parent | 5c6d7877c58cfe348b2a302d3bd924cd096a7ba2 (diff) | |
download | cpython-7f9876c0daf73b1da3a7bc3ab62add0d1b10706a.zip cpython-7f9876c0daf73b1da3a7bc3ab62add0d1b10706a.tar.gz cpython-7f9876c0daf73b1da3a7bc3ab62add0d1b10706a.tar.bz2 |
Initial, untested stab at writing a common denominator function for __import__
and import_module.
-rw-r--r-- | Lib/importlib/NOTES | 13 | ||||
-rw-r--r-- | Lib/importlib/_bootstrap.py | 43 |
2 files changed, 56 insertions, 0 deletions
diff --git a/Lib/importlib/NOTES b/Lib/importlib/NOTES index 538e874..3b000ff 100644 --- a/Lib/importlib/NOTES +++ b/Lib/importlib/NOTES @@ -15,6 +15,19 @@ to do + Create a greatest common denominator function for __import__/import_module that takes in an absolute module name and performs the import. + + - Needs of __import__ + + * Figure out caller's package. + * Import module. + * Set __package__. + * Figure out what module to return. + + - Needs of import_module + + * Resolve name/level. + * Import module. + + Use GCD import for __import__. + Use GCD import for import_module. diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py index 8eff65c..2107e9e 100644 --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -676,6 +676,48 @@ class ImportLockContext(object): imp.release_lock() +def _gcd_import(name, package=None, level=0): + """Import and return the module based on its name, the package the call is + being made from, and the level adjustment. + + This function represents the greatest common denominator of functionality + between import_module and __import__. + """ + if package and package not in sys.modules: + msg = "Parent module {0!r} not loaded, cannot perform relative import" + raise SystemError(msg.format(package)) + dot = len(package) + if level > 0: + for x in range(level, 1, -1): + try: + dot = package.rindex('.', 0, dot) + except AttributeError: + raise ValueError("__package__ not set to a string") + except ValueError: + raise ValueError("attempted relative import beyond top-level " + "package") + name = "{0}.{1}".format(package[:dot], name) + with ImportLockContext(): + try: + return sys.modules[name] + except KeyError: + pass + parent = name.rpartition('.')[0] + path = None + if parent: + if parent not in sys.modules: + parent_module = _gcd_import(parent) + else: + parent_module = sys.modules[parent] + path = parent_module.__path__ + for finder in sys.meta_path + [PathFinder]: + loader = finder.find_module(name, path) + if loader: # XXX Worth checking for None explicitly? + return loader.load_module(name) + else: + raise ImportError("No module named {0}".format(name)) + + class Import(object): """Class that implements the __import__ interface. @@ -950,6 +992,7 @@ class Import(object): (e.g. has a value of 2 for ``from .. import foo``). """ + # TODO(brett.cannon) outdated check; just care that level >= 0 if not name and level < 1: raise ValueError("Empty module name") is_pkg = True if '__path__' in globals else False |