From 34d8e41a474f43dabca4096e5f945ca67e69a5b8 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Wed, 22 Feb 2012 18:33:05 -0500 Subject: [PATCH] Refactor importlib to make it easier to re-implement in C. --- Lib/importlib/_bootstrap.py | 76 +++++++++++++++---------------------- 1 file changed, 31 insertions(+), 45 deletions(-) diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py index d10ab2f1f4d..6c4367fde96 100644 --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -918,20 +918,12 @@ def _find_module(name, path): return None -def _set___package__(module): - """Set __package__ on a module.""" - # Watch out for what comes out of sys.modules to not be a module, - # e.g. an int. - try: - module.__package__ = module.__name__ - if not hasattr(module, '__path__'): - module.__package__ = module.__package__.rpartition('.')[0] - except AttributeError: - pass - - def _sanity_check(name, package, level): """Verify arguments are "sane".""" + if not hasattr(name, 'rpartition'): + raise TypeError("module name must be str, not {}".format(type(name))) + if level < 0: + raise ValueError('level must be >= 0') if package: if not hasattr(package, 'rindex'): raise ValueError("__package__ not set to a string") @@ -943,13 +935,12 @@ def _sanity_check(name, package, level): raise ValueError("Empty module name") -def _find_search_path(name, import_): - """Find the search path for a module. +_IMPLICIT_META_PATH = [BuiltinImporter, FrozenImporter, _DefaultPathFinder] - import_ is expected to be a callable which takes the name of a module to - import. It is required to decouple the function from importlib. +_ERR_MSG = 'No module named {!r}' - """ +def _find_and_load(name, import_): + """Find and load the module.""" path = None parent = name.rpartition('.')[0] if parent: @@ -962,14 +953,29 @@ def _find_search_path(name, import_): except AttributeError: msg = (_ERR_MSG + '; {} is not a package').format(name, parent) raise ImportError(msg) - return parent, path + loader = _find_module(name, path) + if loader is None: + raise ImportError(_ERR_MSG.format(name)) + elif name not in sys.modules: + # The parent import may have already imported this module. + loader.load_module(name) + # Backwards-compatibility; be nicer to skip the dict lookup. + module = sys.modules[name] + if parent: + # Set the module as an attribute on its parent. + parent_module = sys.modules[parent] + setattr(parent_module, name.rpartition('.')[2], module) + # Set __package__ if the loader did not. + if not hasattr(module, '__package__') or module.__package__ is None: + try: + module.__package__ = module.__name__ + if not hasattr(module, '__path__'): + module.__package__ = module.__package__.rpartition('.')[0] + except AttributeError: + pass + return module - -_IMPLICIT_META_PATH = [BuiltinImporter, FrozenImporter, _DefaultPathFinder] - -_ERR_MSG = 'No module named {!r}' - 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. @@ -991,24 +997,8 @@ def _gcd_import(name, package=None, level=0): raise ImportError(message) return module except KeyError: - pass - parent, path = _find_search_path(name, _gcd_import) - loader = _find_module(name, path) - if loader is None: - raise ImportError(_ERR_MSG.format(name)) - elif name not in sys.modules: - # The parent import may have already imported this module. - loader.load_module(name) - # Backwards-compatibility; be nicer to skip the dict lookup. - module = sys.modules[name] - if parent: - # Set the module as an attribute on its parent. - parent_module = sys.modules[parent] - setattr(parent_module, name.rpartition('.')[2], module) - # Set __package__ if the loader did not. - if not hasattr(module, '__package__') or module.__package__ is None: - _set___package__(module) - return module + pass # Don't want to chain the exception + return _find_and_load(name, _gcd_import) def _return_module(module, name, fromlist, level, import_): @@ -1071,12 +1061,8 @@ def __import__(name, globals={}, locals={}, fromlist=[], level=0): import (e.g. ``from ..pkg import mod`` would have a 'level' of 2). """ - if not hasattr(name, 'rpartition'): - raise TypeError("module name must be str, not {}".format(type(name))) if level == 0: module = _gcd_import(name) - elif level < 0: - raise ValueError('level must be >= 0') else: package = _calc___package__(globals) module = _gcd_import(name, package, level)