parent
652bf4981d
commit
da96ab184a
@ -0,0 +1,441 @@
|
||||
#!/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: 922 $
|
||||
$Date: 2004-11-27 14:23:27 -0700 (Sat, 27 Nov 2004) $
|
||||
"""
|
||||
__all__ = ['ppimport','ppimport_attr','ppresolve']
|
||||
|
||||
import os
|
||||
import sys
|
||||
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(object):
|
||||
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 '_ppimport_attr' in self.__dict__:
|
||||
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 '__name__' not in p_frame.f_locals:
|
||||
level = level + 1
|
||||
p_frame = _get_frame(level)
|
||||
|
||||
p_name = p_frame.f_locals['__name__']
|
||||
if p_name=='__main__':
|
||||
p_dir = ''
|
||||
fullname = name
|
||||
elif '__path__' in p_frame.f_locals:
|
||||
# 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(object):
|
||||
# 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 numpy.testing import Tester
|
||||
self.__dict__['test'] = Tester(os.path.dirname(location)).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__.update(module.__dict__)
|
||||
self.__dict__['_ppimport_module'] = module
|
||||
|
||||
# XXX: Should we check the existence of module.test? Warn?
|
||||
from numpy.testing import Tester
|
||||
test = Tester(os.path.dirname(module.__file__)).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 '_ppimport_module' in self.__dict__:
|
||||
status = 'imported'
|
||||
elif '_ppimport_exc_info' in self.__dict__:
|
||||
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 b in sys.modules 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
|
Loading…
Reference in New Issue