Guest User

Draft _gcd_import rewrite for PEP 402

a guest
Aug 15th, 2011
47
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. def _gcd_import(name, package=None, level=0):
  2.     """Import and return the module based on its name, the package the call is
  3.    being made from, and the level adjustment.
  4.  
  5.    This function represents the greatest common denominator of functionality
  6.    between import_module and __import__. This includes setting __package__ if
  7.    the loader did not.
  8.    """
  9.     if package:
  10.         if not hasattr(package, 'rindex'):
  11.             raise ValueError("__package__ not set to a string")
  12.         elif package not in sys.modules:
  13.             msg = ("Parent module {0!r} not loaded, cannot perform relative "
  14.                    "import")
  15.             raise SystemError(msg.format(package))
  16.     if not name and level == 0:
  17.         raise ValueError("Empty module name")
  18.     if level > 0:
  19.         dot = len(package)
  20.         for x in range(level, 1, -1):
  21.             try:
  22.                 dot = package.rindex('.', 0, dot)
  23.             except ValueError:
  24.                 raise ValueError("attempted relative import beyond "
  25.                                  "top-level package")
  26.         if name:
  27.             name = "{0}.{1}".format(package[:dot], name)
  28.         else:
  29.             name = package[:dot]
  30.  
  31.     with _ImportLockContext():
  32.         try:
  33.             module = sys.modules[name]
  34.             if module is None:
  35.                 message = ("import of {} halted; "
  36.                             "None in sys.modules".format(name))
  37.                 raise ImportError(message)
  38.             return module
  39.         except KeyError:
  40.             pass
  41.  
  42.         base = parent = ''
  43.         module = None
  44.         path = sys.path
  45.         for part in name.split('.'):
  46.             if parent and not path:
  47.                 msg = (_ERR_MSG + '; {} is not a package').format(name, parent)
  48.                 raise ImportError(msg)
  49.             current = base + part
  50.             module = sys.modules.get(current)
  51.             if module is None:
  52.                 loader = _find_module(current, path)
  53.                 if loader is not None:
  54.                     if parent:
  55.                         _ensure_package(parent)
  56.                     loader.load_module(current)
  57.                     module = _fixup_module(current)
  58.             if current != name:
  59.                 # update search path for the next target
  60.                 if hasattr(module, '__path__'):
  61.                     path = module.__path__
  62.                 else:
  63.                     path = get_module_path(current)
  64.             parent = current
  65.             base = parent + '.'
  66.  
  67.         if module is None:
  68.             raise ImportError(_ERR_MSG.format(name))
  69.         return module
  70.  
  71. def get_module_path(modulename):
  72.     if not modulename:
  73.         return sys.path
  74.     elif modulename in sys.virtual_package_paths:
  75.         return sys.virtual_package_paths[modulename]
  76.     elif modulename in sys.modules:
  77.         path = getattr(sys.modules[modulename], '__path__', None)
  78.         if path is not None:
  79.             return path
  80.     parent = modulename.rpartition('.')[0]
  81.     path = VirtualPath(modulename, get_module_path(parent))
  82.     return sys.virtual_package_paths.setdefault(modulename, path)
  83.  
  84. def _fixup_module(name):
  85.     """Ensure named module has a parent pointing to it, and a __package__"""
  86.     # Backwards-compatibility; be nicer to skip the dict lookup.
  87.     module = sys.modules[name]
  88.     parent, _, child = name.rpartition('.')
  89.     if parent:
  90.         # Set the module as an attribute on its parent.
  91.         setattr(sys.modules[parent], child, module)
  92.     # Set __package__ if the loader did not.
  93.     if not hasattr(module, '__package__') or module.__package__ is None:
  94.         # Watch out for what comes out of sys.modules to not be a module,
  95.         # e.g. an int.
  96.         try:
  97.             module.__package__ = module.__name__
  98.             if not hasattr(module, '__path__'):
  99.                 module.__package__ = module.__package__.rpartition('.')[0]
  100.         except AttributeError:
  101.             pass
  102.     return module
  103.  
  104. def _find_module(name, path):
  105.     meta_path = sys.meta_path + _IMPLICIT_META_PATH
  106.     for finder in meta_path:
  107.         loader = finder.find_module(name, path)
  108.         if loader is not None:
  109.             return loader
  110.     else:
  111.         return None
  112.  
  113. def _ensure_package(name):
  114.     if '.' in name:
  115.         # Ensure parent package first
  116.         _ensure_package(name.rpartition('.')[0])
  117.     pkg = sys.modules.get(name)
  118.     if pkg is None:
  119.         pkg = sys.modules[name] = imp.new_module(name)
  120.     if not hasattr(pkg, '__path__'):
  121.         pkg.__path__ = get_module_path(name)
  122.     return _fixup_module(pkg)
  123.  
  124.  
  125. class VirtualPath:
  126.     __slots__ = ('__name__', '_parent', '_last_seen', '_path')
  127.  
  128.     def __init__(self, name, parent_path):
  129.         self.__name__ = name
  130.         self._parent = parent_path
  131.         self._path = self._last_seen = ()
  132.  
  133.     def _fail(self, *args, **kw):
  134.         raise TypeError(self.__name__+" is a virtual package")
  135.  
  136.     __getitem__ = __setitem__ = __delitem__ = append = extend = insert = _fail
  137.  
  138.     def _calculate(self):
  139.         with _ImportLockContext():
  140.             parent = tuple(self._parent)
  141.             if parent != self._last_seen:
  142.                 items = []
  143.                 name = self.__name__
  144.                 for entry in parent:
  145.                     importer = get_importer(entry)
  146.                     if hasattr(importer, 'get_subpath'):
  147.                         item = importer.get_subpath(name)
  148.                         if item is not None:
  149.                             items.append(item)
  150.                 self._last_seen = parent
  151.                 self._path = tuple(items)
  152.             return self._path
  153.  
  154.     def __iter__(self):
  155.         return iter(self._calculate())
  156.  
  157.     def __len__(self):
  158.         return len(self._calculate())
  159.  
  160.     def __repr__(self):
  161.         return "VirtualPath" + repr((self.__name__, self._parent))
  162.  
  163.     def __contains__(self, item):
  164.         return item in self._calculate()
RAW Paste Data