Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # Performance note: this slows import of all builtin/frozen modules, and adds
- # an isdir() check for each directory on sys.path that precedes the target. If
- # you have a lot of (directory) path entries and import a lot of stuff from
- # far down the path, this may be very slow if (e.g.) those paths are over a
- # network. So, we operate in an "explicit only" mode by default, where only
- # registered namespace packages get the extra processing this way.
- import sys, new, zipimport, os
- try:
- _make_set = set
- except NameError:
- _make_set = dict.fromkeys
- if not hasattr(sys, 'namespace_packages'):
- sys.namespace_packages = _make_set([])
- def is_namespace(pkgname):
- return pkgname in sys.namespace_packages
- def register_namespace(pkgname):
- if not is_namespace(pkgname):
- sys.namespace_packages.update(_make_set([pkgname]))
- # Make sure we can process at least the registered namespace(s)
- meta_importer.install(True)
- def get_importer(entry):
- global ImpImporter, get_importer
- try:
- from pkgutil import get_importer, ImpImporter
- except ImportError:
- from pkg_resources import get_importer, ImpWrapper as ImpImporter
- ImpImporter.namespace_subpath = _fs_namespace_subpath
- return get_importer(entry)
- def namespace_subpath(finder, fullname):
- if hasattr(finder, 'namespace_subpath'):
- return finder.namespace_subpath(fullname)
- elif isinstance(finder, zipimport.zipimporter):
- return _zip_namespace_subpath(finder, fullname)
- class NamespaceMetaImporter:
- """Implement PEP 382 namespace protocol for Python 2.x"""
- registration_required = True
- def find_module(self, name, path):
- if self.registration_required and not is_namespace(name):
- # We're only running for explicitly-registered packages, fall back
- # to normal import
- return None
- loader = None
- nspth = []
- parents = []
- for entry in path:
- finder = get_importer(entry)
- subpath = namespace_subpath(finder, name)
- if subpath is not None:
- parents.append(entry)
- nspth.append(subpath)
- elif not nspth: # only search normal modules before first ns found!
- loader = finder.find_module(name)
- if not nspth and loader is not None:
- # Found regular module or package first, return it now
- return loader
- if not nspth:
- # Nothing found, fall through to normal import process
- return loader
- register_namespace(name) # make sure we're in sys.namespace_packages
- nspkg = sys.modules.setdefault(name, new.module(name))
- nspkg.__path__ = nspth
- for entry, subpath in zip(parents, nspth):
- finder = get_importer(entry)
- loader = self._wrap_loader(finder.find_module(subname), subpath, name)
- if loader is not None:
- return loader
- # Namespace package with no __init__ - return dummy loader
- return self
- def load_module(self, name):
- # We already initialized an empty namespace package, so just return it
- return sys.modules[name]
- def wrap_loader(self, loader, subpath, name):
- if hasattr(loader, 'is_package') and not loader.is_package(name):
- # It's a module, not a package: ignore it
- return None
- finder = get_importer(subpath)
- subloader = finder.find_module(name+'.__init__')
- if subloader is None:
- # Guess it must be a module after all; skip it
- return None
- # Ok, now we have a parent loader (which we want to set as the
- # __loader__, if we set one), and a subloader, which we'll use to fetch
- # the __init__ code from, assuming it has a get_code() method:
- if isinstance(finder, ImpImporter) or not hasattr(subloader, 'get_code'):
- # Use as-is. This should work for pkgutil and pkg_resources'
- # ImpLoader classes, or anything else that wraps imp in similar
- # fashion, but could have weird consequences for specialized
- # importers. (OTOH, they probably don't support checking namespace
- # existence, so we probably won't get here for them anyway!)
- return subloader
- # This should works for zipimport and most other things with a get_code
- return CodeLoader(loader, subloader, name+'.__init__')
- def install(self, require_registration=False):
- """Put this meta-importer on sys.meta_path"""
- if self not in sys.meta_path:
- # We install at the end, so other meta-hooks take precedence
- sys.meta_path.append(self)
- if not require_registration:
- self.require_registration = False
- meta_importer = NamespaceMetaImporter()
- class CodeLoader(object):
- """Run __init__ code in package, without erasing __path__"""
- def __init__(self, loader, subloader, subname):
- self.loader = loader
- self.subloader = subloader
- self.subname = subname
- def load_module(self, fullname):
- pkg = sys.modules[fullname]
- pkg.__loader__ = self.loader
- code = self.subloader.get_code(self.subname)
- fn = getattr(code, 'co_filename', None)
- if fn:
- pkg.__file__ = fn
- exec code in pkg.__dict__
- return pkg
- def _zip_namespace_subpath(zipimporter, fullname):
- subname = fullname.split('.')[-1]
- prefix = zipimporter.prefix + subname
- for filename in zipimport._zip_directory_cache[zipimporter.archive]:
- if filename.endswith('.ns') and os.path.dirname(filename)==prefix:
- return zipimporter.archive + os.sep + prefix
- def _fs_namespace_subpath(imp_importer, fullname):
- subname = fullname.split('.')[-1]
- prefix = os.path.join(imp_importer.path, subname)
- if os.path.isdir(prefix):
- for filename in listdir(prefix):
- if filename.endswith('.ns'):
- return prefix
- return None # not a namespace
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement