Commits

Martin von Löwis committed 4801c13

Extend importlib to support package portions.

Comments (0)

Files changed (1)

Lib/importlib/_bootstrap.py

     return [suffix[0] for suffix in imp.get_suffixes()
             if suffix[2] == suffix_type]
 
+def _is_package(loader, fullname):
+    '''Determine whether a loader represents a package'''
+    try:
+        return loader.is_package(fullname)
+    except AttributeError:
+        return False
 
 # Loaders #####################################################################
 
         """Return None as extension modules have no source code."""
         return None
 
+class _PathLoader:
+    '''Loader which extends __path__ of a new package.'''
+
+    def __init__(self, subloader, subpath):
+        self.subloader = subloader
+        self.subpath = subpath
+
+    def load_module(self, fullname):
+        if self.subloader:
+            result = self.subloader.load_module(fullname)
+            result.__path__.extend(self.subpath)
+            return result
+        result = imp.new_module(fullname)
+        result.__path__ = self.subpath
+        result.__package__ = fullname
+        return result
+
 
 # Finders #####################################################################
 
         sys.path_importer_cache."""
         if not path:
             path = sys.path
+        result = None
+        subpath = []
         for entry in path:
             try:
                 finder = cls._path_importer_cache(entry)
             except ImportError:
                 continue
             if finder:
-                loader = finder.find_module(fullname)
-                if loader:
-                    return loader
-        else:
-            return None
+                if not result:
+                    loader = finder.find_module(fullname)
+                    if loader:
+                        # If this loader is for a module, but
+                        # we have already committed to creating a
+                        # package, skip it
+                        if _is_package(loader, fullname):
+                            result = loader
+                        elif not subpath:
+                            # Not a package, so there is no point
+                            # in further searching for .pyp directories
+                            return loader
+                        # else: skip this loader
+                try:
+                    pyp = finder.find_package_portion(fullname)
+                except AttributeError:
+                    continue
+                if pyp:
+                    subpath.append(pyp)
+        if subpath:
+            return _PathLoader(result, subpath)
+        return result
 
 
 class _FileFinder:
                 return loader(fullname, full_path)
         return None
 
+    def find_package_portion(self, fullname):
+        """Determine whether a package.pyp directory exists here."""
+        tail_module = fullname.rpartition('.')[2]
+        pyp = _path_join(self.path, tail_module + '.pyp')
+        if _path_isdir(pyp) and _case_ok(self.path, tail_module + '.pyp'):
+            return pyp
+        return None
+
 class _SourceFinderDetails:
 
     loader = _SourceFileLoader