summaryrefslogtreecommitdiff
path: root/base/ppimport.py
diff options
context:
space:
mode:
Diffstat (limited to 'base/ppimport.py')
-rw-r--r--base/ppimport.py442
1 files changed, 442 insertions, 0 deletions
diff --git a/base/ppimport.py b/base/ppimport.py
new file mode 100644
index 000000000..154b76fe7
--- /dev/null
+++ b/base/ppimport.py
@@ -0,0 +1,442 @@
+#!/usr/bin/env python
+"""
+Postpone module import to future.
+
+Python versions: 1.5.2 - 2.3.x
+Author: Pearu Peterson <pearu@cens.ioc.ee>
+Created: March 2003
+$Revision$
+$Date$
+"""
+__all__ = ['ppimport','ppimport_attr','ppresolve']
+
+import os
+import sys
+import string
+import types
+import traceback
+
+DEBUG=0
+
+_ppimport_is_enabled = 1
+def enable():
+ """ Enable postponed importing."""
+ global _ppimport_is_enabled
+ _ppimport_is_enabled = 1
+
+def disable():
+ """ Disable postponed importing."""
+ global _ppimport_is_enabled
+ _ppimport_is_enabled = 0
+
+class PPImportError(ImportError):
+ pass
+
+def _get_so_ext(_cache={}):
+ so_ext = _cache.get('so_ext')
+ if so_ext is None:
+ if sys.platform[:5]=='linux':
+ so_ext = '.so'
+ else:
+ try:
+ # if possible, avoid expensive get_config_vars call
+ from distutils.sysconfig import get_config_vars
+ so_ext = get_config_vars('SO')[0] or ''
+ except ImportError:
+ #XXX: implement hooks for .sl, .dll to fully support
+ # Python 1.5.x
+ so_ext = '.so'
+ _cache['so_ext'] = so_ext
+ return so_ext
+
+def _get_frame(level=0):
+ try:
+ return sys._getframe(level+1)
+ except AttributeError:
+ # Python<=2.0 support
+ frame = sys.exc_info()[2].tb_frame
+ for i in range(level+1):
+ frame = frame.f_back
+ return frame
+
+def ppimport_attr(module, name):
+ """ ppimport(module, name) is 'postponed' getattr(module, name)
+ """
+ global _ppimport_is_enabled
+ if _ppimport_is_enabled and isinstance(module, _ModuleLoader):
+ return _AttrLoader(module, name)
+ return getattr(module, name)
+
+class _AttrLoader:
+ def __init__(self, module, name):
+ self.__dict__['_ppimport_attr_module'] = module
+ self.__dict__['_ppimport_attr_name'] = name
+
+ def _ppimport_attr_getter(self):
+ module = self.__dict__['_ppimport_attr_module']
+ if isinstance(module, _ModuleLoader):
+ # in case pp module was loaded by other means
+ module = sys.modules[module.__name__]
+ attr = getattr(module,
+ self.__dict__['_ppimport_attr_name'])
+ try:
+ d = attr.__dict__
+ if d is not None:
+ self.__dict__ = d
+ except AttributeError:
+ pass
+ self.__dict__['_ppimport_attr'] = attr
+
+ return attr
+
+ def __nonzero__(self):
+ return 1
+
+ def __getattr__(self, name):
+ try:
+ attr = self.__dict__['_ppimport_attr']
+ except KeyError:
+ attr = self._ppimport_attr_getter()
+ if name=='_ppimport_attr':
+ return attr
+ return getattr(attr, name)
+
+ def __repr__(self):
+ if self.__dict__.has_key('_ppimport_attr'):
+ return repr(self._ppimport_attr)
+ module = self.__dict__['_ppimport_attr_module']
+ name = self.__dict__['_ppimport_attr_name']
+ return "<attribute %s of %s>" % (`name`,`module`)
+
+ __str__ = __repr__
+
+ # For function and class attributes.
+ def __call__(self, *args, **kwds):
+ return self._ppimport_attr(*args,**kwds)
+
+
+
+def _is_local_module(p_dir,name,suffices):
+ base = os.path.join(p_dir,name)
+ for suffix in suffices:
+ if os.path.isfile(base+suffix):
+ if p_dir:
+ return base+suffix
+ return name+suffix
+
+def ppimport(name):
+ """ ppimport(name) -> module or module wrapper
+
+ If name has been imported before, return module. Otherwise
+ return ModuleLoader instance that transparently postpones
+ module import until the first attempt to access module name
+ attributes.
+ """
+ global _ppimport_is_enabled
+
+ level = 1
+ parent_frame = p_frame = _get_frame(level)
+ while not p_frame.f_locals.has_key('__name__'):
+ level = level + 1
+ p_frame = _get_frame(level)
+
+ p_name = p_frame.f_locals['__name__']
+ if p_name=='__main__':
+ p_dir = ''
+ fullname = name
+ elif p_frame.f_locals.has_key('__path__'):
+ # python package
+ p_path = p_frame.f_locals['__path__']
+ p_dir = p_path[0]
+ fullname = p_name + '.' + name
+ else:
+ # python module
+ p_file = p_frame.f_locals['__file__']
+ p_dir = os.path.dirname(p_file)
+ fullname = p_name + '.' + name
+
+ # module may be imported already
+ module = sys.modules.get(fullname)
+ if module is not None:
+ if _ppimport_is_enabled or isinstance(module, types.ModuleType):
+ return module
+ return module._ppimport_importer()
+
+ so_ext = _get_so_ext()
+ py_exts = ('.py','.pyc','.pyo')
+ so_exts = (so_ext,'module'+so_ext)
+
+ for d,n,fn,e in [\
+ # name is local python module or local extension module
+ (p_dir, name, fullname, py_exts+so_exts),
+ # name is local package
+ (os.path.join(p_dir, name), '__init__', fullname, py_exts),
+ # name is package in parent directory (scipy specific)
+ (os.path.join(os.path.dirname(p_dir), name), '__init__', name, py_exts),
+ ]:
+ location = _is_local_module(d, n, e)
+ if location is not None:
+ fullname = fn
+ break
+
+ if location is None:
+ # name is to be looked in python sys.path.
+ fullname = name
+ location = 'sys.path'
+
+ # Try once more if module is imported.
+ # This covers the case when importing from python module
+ module = sys.modules.get(fullname)
+
+ if module is not None:
+ if _ppimport_is_enabled or isinstance(module,types.ModuleType):
+ return module
+ return module._ppimport_importer()
+ # It is OK if name does not exists. The ImportError is
+ # postponed until trying to use the module.
+
+ loader = _ModuleLoader(fullname,location,p_frame=parent_frame)
+ if _ppimport_is_enabled:
+ return loader
+
+ return loader._ppimport_importer()
+
+def _get_frame_code(frame):
+ filename = frame.f_code.co_filename
+ lineno = frame.f_lineno
+ result = '%s in %s:\n' % (filename,frame.f_code.co_name)
+ if not os.path.isfile(filename):
+ return result
+ f = open(filename)
+ i = 1
+ line = f.readline()
+ while line:
+ line = f.readline()
+ i = i + 1
+ if (abs(i-lineno)<2):
+ result += '#%d: %s\n' % (i,line.rstrip())
+ if i>lineno+3:
+ break
+ f.close()
+ return result
+
+def frame_traceback(frame):
+ if not frame:
+ return
+ blocks = []
+ f = frame
+ while f:
+ blocks.insert(0,_get_frame_code(f))
+ f = f.f_back
+ print '='*50
+ print '\n'.join(blocks)
+ print '='*50
+
+class _ModuleLoader:
+ # Don't use it directly. Use ppimport instead.
+
+ def __init__(self,name,location,p_frame=None):
+
+ # set attributes, avoid calling __setattr__
+ self.__dict__['__name__'] = name
+ self.__dict__['__file__'] = location
+ self.__dict__['_ppimport_p_frame'] = p_frame
+
+ if location != 'sys.path':
+ from scipy_test.testing import ScipyTest
+ self.__dict__['test'] = ScipyTest(self).test
+
+ # install loader
+ sys.modules[name] = self
+
+ def _ppimport_importer(self):
+ name = self.__name__
+
+ try:
+ module = sys.modules[name]
+ except KeyError:
+ raise ImportError,self.__dict__.get('_ppimport_exc_info')[1]
+ if module is not self:
+ exc_info = self.__dict__.get('_ppimport_exc_info')
+ if exc_info is not None:
+ raise PPImportError,\
+ ''.join(traceback.format_exception(*exc_info))
+ else:
+ assert module is self,`(module, self)`
+
+ # uninstall loader
+ del sys.modules[name]
+
+ if DEBUG:
+ print 'Executing postponed import for %s' %(name)
+ try:
+ module = __import__(name,None,None,['*'])
+ except Exception,msg: # ImportError:
+ if DEBUG:
+ p_frame = self.__dict__.get('_ppimport_p_frame',None)
+ frame_traceback(p_frame)
+ self.__dict__['_ppimport_exc_info'] = sys.exc_info()
+ raise
+
+ assert isinstance(module,types.ModuleType),`module`
+
+ self.__dict__ = module.__dict__
+ self.__dict__['_ppimport_module'] = module
+
+ # XXX: Should we check the existence of module.test? Warn?
+ from scipy_test.testing import ScipyTest
+ module.test = ScipyTest(module).test
+
+ return module
+
+ def __setattr__(self, name, value):
+ try:
+ module = self.__dict__['_ppimport_module']
+ except KeyError:
+ module = self._ppimport_importer()
+ return setattr(module, name, value)
+
+ def __getattr__(self, name):
+ try:
+ module = self.__dict__['_ppimport_module']
+ except KeyError:
+ module = self._ppimport_importer()
+ return getattr(module, name)
+
+ def __repr__(self):
+ global _ppimport_is_enabled
+ if not _ppimport_is_enabled:
+ try:
+ module = self.__dict__['_ppimport_module']
+ except KeyError:
+ module = self._ppimport_importer()
+ return module.__repr__()
+ if self.__dict__.has_key('_ppimport_module'):
+ status = 'imported'
+ elif self.__dict__.has_key('_ppimport_exc_info'):
+ status = 'import error'
+ else:
+ status = 'import postponed'
+ return '<module %s from %s [%s]>' \
+ % (`self.__name__`,`self.__file__`, status)
+
+ __str__ = __repr__
+
+def ppresolve(a,ignore_failure=None):
+ """ Return resolved object a.
+
+ a can be module name, postponed module, postponed modules
+ attribute, string representing module attribute, or any
+ Python object.
+ """
+ global _ppimport_is_enabled
+ if _ppimport_is_enabled:
+ disable()
+ a = ppresolve(a,ignore_failure=ignore_failure)
+ enable()
+ return a
+ if type(a) is type(''):
+ ns = a.split('.')
+ if ignore_failure:
+ try:
+ a = ppimport(ns[0])
+ except:
+ return a
+ else:
+ a = ppimport(ns[0])
+ b = [ns[0]]
+ del ns[0]
+ while ns:
+ if hasattr(a,'_ppimport_importer') or \
+ hasattr(a,'_ppimport_module'):
+ a = getattr(a,'_ppimport_module',a)
+ if hasattr(a,'_ppimport_attr'):
+ a = a._ppimport_attr
+ b.append(ns[0])
+ del ns[0]
+ if ignore_failure and not hasattr(a, b[-1]):
+ a = '.'.join(ns+b)
+ b = '.'.join(b)
+ if sys.modules.has_key(b) and sys.modules[b] is None:
+ del sys.modules[b]
+ return a
+ a = getattr(a,b[-1])
+ if hasattr(a,'_ppimport_importer') or \
+ hasattr(a,'_ppimport_module'):
+ a = getattr(a,'_ppimport_module',a)
+ if hasattr(a,'_ppimport_attr'):
+ a = a._ppimport_attr
+ return a
+
+def _ppresolve_ignore_failure(a):
+ return ppresolve(a,ignore_failure=1)
+
+try:
+ import pydoc as _pydoc
+except ImportError:
+ _pydoc = None
+
+if _pydoc is not None:
+ # Redefine __call__ method of help.__class__ to
+ # support ppimport.
+ import new as _new
+
+ _old_pydoc_help_call = _pydoc.help.__class__.__call__
+ def _ppimport_pydoc_help_call(self,*args,**kwds):
+ return _old_pydoc_help_call(self, *map(_ppresolve_ignore_failure,args),
+ **kwds)
+ _ppimport_pydoc_help_call.__doc__ = _old_pydoc_help_call.__doc__
+ _pydoc.help.__class__.__call__ = _new.instancemethod(_ppimport_pydoc_help_call,
+ None,
+ _pydoc.help.__class__)
+
+ _old_pydoc_Doc_document = _pydoc.Doc.document
+ def _ppimport_pydoc_Doc_document(self,*args,**kwds):
+ args = (_ppresolve_ignore_failure(args[0]),) + args[1:]
+ return _old_pydoc_Doc_document(self,*args,**kwds)
+ _ppimport_pydoc_Doc_document.__doc__ = _old_pydoc_Doc_document.__doc__
+ _pydoc.Doc.document = _new.instancemethod(_ppimport_pydoc_Doc_document,
+ None,
+ _pydoc.Doc)
+
+ _old_pydoc_describe = _pydoc.describe
+ def _ppimport_pydoc_describe(object):
+ return _old_pydoc_describe(_ppresolve_ignore_failure(object))
+ _ppimport_pydoc_describe.__doc__ = _old_pydoc_describe.__doc__
+ _pydoc.describe = _ppimport_pydoc_describe
+
+import inspect as _inspect
+_old_inspect_getfile = _inspect.getfile
+def _ppimport_inspect_getfile(object):
+ if isinstance(object,_ModuleLoader):
+ return object.__dict__['__file__']
+ return _old_inspect_getfile(_ppresolve_ignore_failure(object))
+_ppimport_inspect_getfile.__doc__ = _old_inspect_getfile.__doc__
+_inspect.getfile = _ppimport_inspect_getfile
+
+_old_inspect_getdoc = _inspect.getdoc
+def _ppimport_inspect_getdoc(object):
+ return _old_inspect_getdoc(_ppresolve_ignore_failure(object))
+_ppimport_inspect_getdoc.__doc__ = _old_inspect_getdoc.__doc__
+_inspect.getdoc = _ppimport_inspect_getdoc
+
+_old_inspect_getsource = _inspect.getsource
+def _ppimport_inspect_getsource(object):
+ return _old_inspect_getsource(_ppresolve_ignore_failure(object))
+_ppimport_inspect_getsource.__doc__ = _old_inspect_getsource.__doc__
+_inspect.getsource = _ppimport_inspect_getsource
+
+import __builtin__ as _builtin
+_old_builtin_dir = _builtin.dir
+def _ppimport_builtin_dir(*arg):
+ if not arg:
+ p_frame = _get_frame(1)
+ g = p_frame.f_globals
+ l = p_frame.f_locals
+ l['_ppimport_old_builtin_dir'] = _old_builtin_dir
+ r = eval('_ppimport_old_builtin_dir()',g,l)
+ del r[r.index('_ppimport_old_builtin_dir')]
+ return r
+ return _old_builtin_dir(*map(_ppresolve_ignore_failure,arg))
+_ppimport_builtin_dir.__doc__ = _old_builtin_dir.__doc__
+_builtin.dir = _ppimport_builtin_dir