#! /usr/bin/python # -*- coding: utf-8 -*- """This module provides lazy import functionality to improve the import performance of nitime. For example, some parts of nitime leverage and import matplotlib, which is quite a big package, yet most of the nitime code does not depend on matplotlib. By lazily-loading a module, we defer the overhead of importing it until the first time it is actually used, thereby speeding up nitime imports. A generic :class:`LazyImport` class is implemented which takes the module name as a parameter, and acts as a proxy for that module, importing it only when the module is used, but effectively acting as the module in every other way (including inside IPython with respect to introspection and tab completion) with the *exception* of reload() - reloading a :class:`LazyImport` raises an :class:`ImportError`. Commonly used nitime lazy imports are also defined in :mod:`nitime.lazy`, so they can be reused throughout nitime. """ import os import sys import types class LazyImport(types.ModuleType): """ This class takes the module name as a parameter, and acts as a proxy for that module, importing it only when the module is used, but effectively acting as the module in every other way (including inside IPython with respect to introspection and tab completion) with the *exception* of reload()- reloading a :class:`LazyImport` raises an :class:`ImportError`. >>> mlab = LazyImport('matplotlib.mlab') No import happens on the above line, until we do something like call an ``mlab`` method or try to do tab completion or introspection on ``mlab`` in IPython. >>> mlab Now the :class:`LazyImport` will do an actual import, and call the dist function of the imported module. >>> mlab.dist(1969,2011) 42.0 """ def __getattribute__(self, x): # This method will be called only once, since we'll change # self.__class__ to LoadedLazyImport, and __getattribute__ will point # to module.__getattribute__ name = object.__getattribute__(self, '__name__') __import__(name) # if name above is 'package.foo.bar', package is returned, the docs # recommend that in order to get back the full thing, that we import # and then lookup the full name is sys.modules, see: # http://docs.python.org/library/functions.html#__import__ module = sys.modules[name] # Now that we've done the import, cutout the middleman and make self # act as the imported module class LoadedLazyImport(types.ModuleType): __getattribute__ = module.__getattribute__ __repr__ = module.__repr__ object.__setattr__(self, '__class__', LoadedLazyImport) # The next line will make "reload(l)" a silent no-op return module.__getattribute__(x) def __repr__(self): return "" % object.__getattribute__(self, '__name__') if 'READTHEDOCS' in os.environ: lazy_doc = """ WARNING: To get Sphinx documentation to build we disable LazyImports, which makes Sphinx incorrectly report this class as having a base class of object. In reality, :class:`LazyImport`'s base class is :class:`types.ModuleType`. """ lazy_doc += LazyImport.__doc__ class LazyImport(object): __doc__ = lazy_doc def __init__(self, x): __import__(x) self.module = sys.modules[x] def __getattr__(self, x): return self.module.__getattribute__(x)