Home | History | Annotate | Download | only in Lib
      1 """Utilities to support packages."""
      2 
      3 # NOTE: This module must remain compatible with Python 2.3, as it is shared

      4 # by setuptools for distribution with Python 2.3 and up.

      5 
      6 import os
      7 import sys
      8 import imp
      9 import os.path
     10 from types import ModuleType
     11 
     12 __all__ = [
     13     'get_importer', 'iter_importers', 'get_loader', 'find_loader',
     14     'walk_packages', 'iter_modules', 'get_data',
     15     'ImpImporter', 'ImpLoader', 'read_code', 'extend_path',
     16 ]
     17 
     18 def read_code(stream):
     19     # This helper is needed in order for the PEP 302 emulation to

     20     # correctly handle compiled files

     21     import marshal
     22 
     23     magic = stream.read(4)
     24     if magic != imp.get_magic():
     25         return None
     26 
     27     stream.read(4) # Skip timestamp

     28     return marshal.load(stream)
     29 
     30 
     31 def simplegeneric(func):
     32     """Make a trivial single-dispatch generic function"""
     33     registry = {}
     34     def wrapper(*args, **kw):
     35         ob = args[0]
     36         try:
     37             cls = ob.__class__
     38         except AttributeError:
     39             cls = type(ob)
     40         try:
     41             mro = cls.__mro__
     42         except AttributeError:
     43             try:
     44                 class cls(cls, object):
     45                     pass
     46                 mro = cls.__mro__[1:]
     47             except TypeError:
     48                 mro = object,   # must be an ExtensionClass or some such  :(

     49         for t in mro:
     50             if t in registry:
     51                 return registry[t](*args, **kw)
     52         else:
     53             return func(*args, **kw)
     54     try:
     55         wrapper.__name__ = func.__name__
     56     except (TypeError, AttributeError):
     57         pass    # Python 2.3 doesn't allow functions to be renamed

     58 
     59     def register(typ, func=None):
     60         if func is None:
     61             return lambda f: register(typ, f)
     62         registry[typ] = func
     63         return func
     64 
     65     wrapper.__dict__ = func.__dict__
     66     wrapper.__doc__ = func.__doc__
     67     wrapper.register = register
     68     return wrapper
     69 
     70 
     71 def walk_packages(path=None, prefix='', onerror=None):
     72     """Yields (module_loader, name, ispkg) for all modules recursively
     73     on path, or, if path is None, all accessible modules.
     74 
     75     'path' should be either None or a list of paths to look for
     76     modules in.
     77 
     78     'prefix' is a string to output on the front of every module name
     79     on output.
     80 
     81     Note that this function must import all *packages* (NOT all
     82     modules!) on the given path, in order to access the __path__
     83     attribute to find submodules.
     84 
     85     'onerror' is a function which gets called with one argument (the
     86     name of the package which was being imported) if any exception
     87     occurs while trying to import a package.  If no onerror function is
     88     supplied, ImportErrors are caught and ignored, while all other
     89     exceptions are propagated, terminating the search.
     90 
     91     Examples:
     92 
     93     # list all modules python can access
     94     walk_packages()
     95 
     96     # list all submodules of ctypes
     97     walk_packages(ctypes.__path__, ctypes.__name__+'.')
     98     """
     99 
    100     def seen(p, m={}):
    101         if p in m:
    102             return True
    103         m[p] = True
    104 
    105     for importer, name, ispkg in iter_modules(path, prefix):
    106         yield importer, name, ispkg
    107 
    108         if ispkg:
    109             try:
    110                 __import__(name)
    111             except ImportError:
    112                 if onerror is not None:
    113                     onerror(name)
    114             except Exception:
    115                 if onerror is not None:
    116                     onerror(name)
    117                 else:
    118                     raise
    119             else:
    120                 path = getattr(sys.modules[name], '__path__', None) or []
    121 
    122                 # don't traverse path items we've seen before

    123                 path = [p for p in path if not seen(p)]
    124 
    125                 for item in walk_packages(path, name+'.', onerror):
    126                     yield item
    127 
    128 
    129 def iter_modules(path=None, prefix=''):
    130     """Yields (module_loader, name, ispkg) for all submodules on path,
    131     or, if path is None, all top-level modules on sys.path.
    132 
    133     'path' should be either None or a list of paths to look for
    134     modules in.
    135 
    136     'prefix' is a string to output on the front of every module name
    137     on output.
    138     """
    139 
    140     if path is None:
    141         importers = iter_importers()
    142     else:
    143         importers = map(get_importer, path)
    144 
    145     yielded = {}
    146     for i in importers:
    147         for name, ispkg in iter_importer_modules(i, prefix):
    148             if name not in yielded:
    149                 yielded[name] = 1
    150                 yield i, name, ispkg
    151 
    152 
    153 #@simplegeneric

    154 def iter_importer_modules(importer, prefix=''):
    155     if not hasattr(importer, 'iter_modules'):
    156         return []
    157     return importer.iter_modules(prefix)
    158 
    159 iter_importer_modules = simplegeneric(iter_importer_modules)
    160 
    161 
    162 class ImpImporter:
    163     """PEP 302 Importer that wraps Python's "classic" import algorithm
    164 
    165     ImpImporter(dirname) produces a PEP 302 importer that searches that
    166     directory.  ImpImporter(None) produces a PEP 302 importer that searches
    167     the current sys.path, plus any modules that are frozen or built-in.
    168 
    169     Note that ImpImporter does not currently support being used by placement
    170     on sys.meta_path.
    171     """
    172 
    173     def __init__(self, path=None):
    174         self.path = path
    175 
    176     def find_module(self, fullname, path=None):
    177         # Note: we ignore 'path' argument since it is only used via meta_path

    178         subname = fullname.split(".")[-1]
    179         if subname != fullname and self.path is None:
    180             return None
    181         if self.path is None:
    182             path = None
    183         else:
    184             path = [os.path.realpath(self.path)]
    185         try:
    186             file, filename, etc = imp.find_module(subname, path)
    187         except ImportError:
    188             return None
    189         return ImpLoader(fullname, file, filename, etc)
    190 
    191     def iter_modules(self, prefix=''):
    192         if self.path is None or not os.path.isdir(self.path):
    193             return
    194 
    195         yielded = {}
    196         import inspect
    197 
    198         filenames = os.listdir(self.path)
    199         filenames.sort()  # handle packages before same-named modules

    200 
    201         for fn in filenames:
    202             modname = inspect.getmodulename(fn)
    203             if modname=='__init__' or modname in yielded:
    204                 continue
    205 
    206             path = os.path.join(self.path, fn)
    207             ispkg = False
    208 
    209             if not modname and os.path.isdir(path) and '.' not in fn:
    210                 modname = fn
    211                 for fn in os.listdir(path):
    212                     subname = inspect.getmodulename(fn)
    213                     if subname=='__init__':
    214                         ispkg = True
    215                         break
    216                 else:
    217                     continue    # not a package

    218 
    219             if modname and '.' not in modname:
    220                 yielded[modname] = 1
    221                 yield prefix + modname, ispkg
    222 
    223 
    224 class ImpLoader:
    225     """PEP 302 Loader that wraps Python's "classic" import algorithm
    226     """
    227     code = source = None
    228 
    229     def __init__(self, fullname, file, filename, etc):
    230         self.file = file
    231         self.filename = filename
    232         self.fullname = fullname
    233         self.etc = etc
    234 
    235     def load_module(self, fullname):
    236         self._reopen()
    237         try:
    238             mod = imp.load_module(fullname, self.file, self.filename, self.etc)
    239         finally:
    240             if self.file:
    241                 self.file.close()
    242         # Note: we don't set __loader__ because we want the module to look

    243         # normal; i.e. this is just a wrapper for standard import machinery

    244         return mod
    245 
    246     def get_data(self, pathname):
    247         return open(pathname, "rb").read()
    248 
    249     def _reopen(self):
    250         if self.file and self.file.closed:
    251             mod_type = self.etc[2]
    252             if mod_type==imp.PY_SOURCE:
    253                 self.file = open(self.filename, 'rU')
    254             elif mod_type in (imp.PY_COMPILED, imp.C_EXTENSION):
    255                 self.file = open(self.filename, 'rb')
    256 
    257     def _fix_name(self, fullname):
    258         if fullname is None:
    259             fullname = self.fullname
    260         elif fullname != self.fullname:
    261             raise ImportError("Loader for module %s cannot handle "
    262                               "module %s" % (self.fullname, fullname))
    263         return fullname
    264 
    265     def is_package(self, fullname):
    266         fullname = self._fix_name(fullname)
    267         return self.etc[2]==imp.PKG_DIRECTORY
    268 
    269     def get_code(self, fullname=None):
    270         fullname = self._fix_name(fullname)
    271         if self.code is None:
    272             mod_type = self.etc[2]
    273             if mod_type==imp.PY_SOURCE:
    274                 source = self.get_source(fullname)
    275                 self.code = compile(source, self.filename, 'exec')
    276             elif mod_type==imp.PY_COMPILED:
    277                 self._reopen()
    278                 try:
    279                     self.code = read_code(self.file)
    280                 finally:
    281                     self.file.close()
    282             elif mod_type==imp.PKG_DIRECTORY:
    283                 self.code = self._get_delegate().get_code()
    284         return self.code
    285 
    286     def get_source(self, fullname=None):
    287         fullname = self._fix_name(fullname)
    288         if self.source is None:
    289             mod_type = self.etc[2]
    290             if mod_type==imp.PY_SOURCE:
    291                 self._reopen()
    292                 try:
    293                     self.source = self.file.read()
    294                 finally:
    295                     self.file.close()
    296             elif mod_type==imp.PY_COMPILED:
    297                 if os.path.exists(self.filename[:-1]):
    298                     f = open(self.filename[:-1], 'rU')
    299                     self.source = f.read()
    300                     f.close()
    301             elif mod_type==imp.PKG_DIRECTORY:
    302                 self.source = self._get_delegate().get_source()
    303         return self.source
    304 
    305 
    306     def _get_delegate(self):
    307         return ImpImporter(self.filename).find_module('__init__')
    308 
    309     def get_filename(self, fullname=None):
    310         fullname = self._fix_name(fullname)
    311         mod_type = self.etc[2]
    312         if self.etc[2]==imp.PKG_DIRECTORY:
    313             return self._get_delegate().get_filename()
    314         elif self.etc[2] in (imp.PY_SOURCE, imp.PY_COMPILED, imp.C_EXTENSION):
    315             return self.filename
    316         return None
    317 
    318 
    319 try:
    320     import zipimport
    321     from zipimport import zipimporter
    322 
    323     def iter_zipimport_modules(importer, prefix=''):
    324         dirlist = zipimport._zip_directory_cache[importer.archive].keys()
    325         dirlist.sort()
    326         _prefix = importer.prefix
    327         plen = len(_prefix)
    328         yielded = {}
    329         import inspect
    330         for fn in dirlist:
    331             if not fn.startswith(_prefix):
    332                 continue
    333 
    334             fn = fn[plen:].split(os.sep)
    335 
    336             if len(fn)==2 and fn[1].startswith('__init__.py'):
    337                 if fn[0] not in yielded:
    338                     yielded[fn[0]] = 1
    339                     yield fn[0], True
    340 
    341             if len(fn)!=1:
    342                 continue
    343 
    344             modname = inspect.getmodulename(fn[0])
    345             if modname=='__init__':
    346                 continue
    347 
    348             if modname and '.' not in modname and modname not in yielded:
    349                 yielded[modname] = 1
    350                 yield prefix + modname, False
    351 
    352     iter_importer_modules.register(zipimporter, iter_zipimport_modules)
    353 
    354 except ImportError:
    355     pass
    356 
    357 
    358 def get_importer(path_item):
    359     """Retrieve a PEP 302 importer for the given path item
    360 
    361     The returned importer is cached in sys.path_importer_cache
    362     if it was newly created by a path hook.
    363 
    364     If there is no importer, a wrapper around the basic import
    365     machinery is returned. This wrapper is never inserted into
    366     the importer cache (None is inserted instead).
    367 
    368     The cache (or part of it) can be cleared manually if a
    369     rescan of sys.path_hooks is necessary.
    370     """
    371     try:
    372         importer = sys.path_importer_cache[path_item]
    373     except KeyError:
    374         for path_hook in sys.path_hooks:
    375             try:
    376                 importer = path_hook(path_item)
    377                 break
    378             except ImportError:
    379                 pass
    380         else:
    381             importer = None
    382         sys.path_importer_cache.setdefault(path_item, importer)
    383 
    384     if importer is None:
    385         try:
    386             importer = ImpImporter(path_item)
    387         except ImportError:
    388             importer = None
    389     return importer
    390 
    391 
    392 def iter_importers(fullname=""):
    393     """Yield PEP 302 importers for the given module name
    394 
    395     If fullname contains a '.', the importers will be for the package
    396     containing fullname, otherwise they will be importers for sys.meta_path,
    397     sys.path, and Python's "classic" import machinery, in that order.  If
    398     the named module is in a package, that package is imported as a side
    399     effect of invoking this function.
    400 
    401     Non PEP 302 mechanisms (e.g. the Windows registry) used by the
    402     standard import machinery to find files in alternative locations
    403     are partially supported, but are searched AFTER sys.path. Normally,
    404     these locations are searched BEFORE sys.path, preventing sys.path
    405     entries from shadowing them.
    406 
    407     For this to cause a visible difference in behaviour, there must
    408     be a module or package name that is accessible via both sys.path
    409     and one of the non PEP 302 file system mechanisms. In this case,
    410     the emulation will find the former version, while the builtin
    411     import mechanism will find the latter.
    412 
    413     Items of the following types can be affected by this discrepancy:
    414         imp.C_EXTENSION, imp.PY_SOURCE, imp.PY_COMPILED, imp.PKG_DIRECTORY
    415     """
    416     if fullname.startswith('.'):
    417         raise ImportError("Relative module names not supported")
    418     if '.' in fullname:
    419         # Get the containing package's __path__

    420         pkg = '.'.join(fullname.split('.')[:-1])
    421         if pkg not in sys.modules:
    422             __import__(pkg)
    423         path = getattr(sys.modules[pkg], '__path__', None) or []
    424     else:
    425         for importer in sys.meta_path:
    426             yield importer
    427         path = sys.path
    428     for item in path:
    429         yield get_importer(item)
    430     if '.' not in fullname:
    431         yield ImpImporter()
    432 
    433 def get_loader(module_or_name):
    434     """Get a PEP 302 "loader" object for module_or_name
    435 
    436     If the module or package is accessible via the normal import
    437     mechanism, a wrapper around the relevant part of that machinery
    438     is returned.  Returns None if the module cannot be found or imported.
    439     If the named module is not already imported, its containing package
    440     (if any) is imported, in order to establish the package __path__.
    441 
    442     This function uses iter_importers(), and is thus subject to the same
    443     limitations regarding platform-specific special import locations such
    444     as the Windows registry.
    445     """
    446     if module_or_name in sys.modules:
    447         module_or_name = sys.modules[module_or_name]
    448     if isinstance(module_or_name, ModuleType):
    449         module = module_or_name
    450         loader = getattr(module, '__loader__', None)
    451         if loader is not None:
    452             return loader
    453         fullname = module.__name__
    454     else:
    455         fullname = module_or_name
    456     return find_loader(fullname)
    457 
    458 def find_loader(fullname):
    459     """Find a PEP 302 "loader" object for fullname
    460 
    461     If fullname contains dots, path must be the containing package's __path__.
    462     Returns None if the module cannot be found or imported. This function uses
    463     iter_importers(), and is thus subject to the same limitations regarding
    464     platform-specific special import locations such as the Windows registry.
    465     """
    466     for importer in iter_importers(fullname):
    467         loader = importer.find_module(fullname)
    468         if loader is not None:
    469             return loader
    470 
    471     return None
    472 
    473 
    474 def extend_path(path, name):
    475     """Extend a package's path.
    476 
    477     Intended use is to place the following code in a package's __init__.py:
    478 
    479         from pkgutil import extend_path
    480         __path__ = extend_path(__path__, __name__)
    481 
    482     This will add to the package's __path__ all subdirectories of
    483     directories on sys.path named after the package.  This is useful
    484     if one wants to distribute different parts of a single logical
    485     package as multiple directories.
    486 
    487     It also looks for *.pkg files beginning where * matches the name
    488     argument.  This feature is similar to *.pth files (see site.py),
    489     except that it doesn't special-case lines starting with 'import'.
    490     A *.pkg file is trusted at face value: apart from checking for
    491     duplicates, all entries found in a *.pkg file are added to the
    492     path, regardless of whether they are exist the filesystem.  (This
    493     is a feature.)
    494 
    495     If the input path is not a list (as is the case for frozen
    496     packages) it is returned unchanged.  The input path is not
    497     modified; an extended copy is returned.  Items are only appended
    498     to the copy at the end.
    499 
    500     It is assumed that sys.path is a sequence.  Items of sys.path that
    501     are not (unicode or 8-bit) strings referring to existing
    502     directories are ignored.  Unicode items of sys.path that cause
    503     errors when used as filenames may cause this function to raise an
    504     exception (in line with os.path.isdir() behavior).
    505     """
    506 
    507     if not isinstance(path, list):
    508         # This could happen e.g. when this is called from inside a

    509         # frozen package.  Return the path unchanged in that case.

    510         return path
    511 
    512     pname = os.path.join(*name.split('.')) # Reconstitute as relative path

    513     # Just in case os.extsep != '.'

    514     sname = os.extsep.join(name.split('.'))
    515     sname_pkg = sname + os.extsep + "pkg"
    516     init_py = "__init__" + os.extsep + "py"
    517 
    518     path = path[:] # Start with a copy of the existing path

    519 
    520     for dir in sys.path:
    521         if not isinstance(dir, basestring) or not os.path.isdir(dir):
    522             continue
    523         subdir = os.path.join(dir, pname)
    524         # XXX This may still add duplicate entries to path on

    525         # case-insensitive filesystems

    526         initfile = os.path.join(subdir, init_py)
    527         if subdir not in path and os.path.isfile(initfile):
    528             path.append(subdir)
    529         # XXX Is this the right thing for subpackages like zope.app?

    530         # It looks for a file named "zope.app.pkg"

    531         pkgfile = os.path.join(dir, sname_pkg)
    532         if os.path.isfile(pkgfile):
    533             try:
    534                 f = open(pkgfile)
    535             except IOError, msg:
    536                 sys.stderr.write("Can't open %s: %s\n" %
    537                                  (pkgfile, msg))
    538             else:
    539                 for line in f:
    540                     line = line.rstrip('\n')
    541                     if not line or line.startswith('#'):
    542                         continue
    543                     path.append(line) # Don't check for existence!

    544                 f.close()
    545 
    546     return path
    547 
    548 def get_data(package, resource):
    549     """Get a resource from a package.
    550 
    551     This is a wrapper round the PEP 302 loader get_data API. The package
    552     argument should be the name of a package, in standard module format
    553     (foo.bar). The resource argument should be in the form of a relative
    554     filename, using '/' as the path separator. The parent directory name '..'
    555     is not allowed, and nor is a rooted name (starting with a '/').
    556 
    557     The function returns a binary string, which is the contents of the
    558     specified resource.
    559 
    560     For packages located in the filesystem, which have already been imported,
    561     this is the rough equivalent of
    562 
    563         d = os.path.dirname(sys.modules[package].__file__)
    564         data = open(os.path.join(d, resource), 'rb').read()
    565 
    566     If the package cannot be located or loaded, or it uses a PEP 302 loader
    567     which does not support get_data(), then None is returned.
    568     """
    569 
    570     loader = get_loader(package)
    571     if loader is None or not hasattr(loader, 'get_data'):
    572         return None
    573     mod = sys.modules.get(package) or loader.load_module(package)
    574     if mod is None or not hasattr(mod, '__file__'):
    575         return None
    576 
    577     # Modify the resource name to be compatible with the loader.get_data

    578     # signature - an os.path format "filename" starting with the dirname of

    579     # the package's __file__

    580     parts = resource.split('/')
    581     parts.insert(0, os.path.dirname(mod.__file__))
    582     resource_name = os.path.join(*parts)
    583     return loader.get_data(resource_name)
    584