pass |
pass |
|
|
path.append(part) |
path.append(part) |
item = __import__('.'.join(path), globalDict, globalDict, [part]) |
item = __import__('.'.join(path), globalDict, globalDict, ['__name__']) |
|
|
return item |
return item |
|
|
(Note: 'relativePath' can also be an absolute path (starting with '/'); |
(Note: 'relativePath' can also be an absolute path (starting with '/'); |
this is mainly useful for module '__bases__' lists.)""" |
this is mainly useful for module '__bases__' lists.)""" |
|
|
class LazyModule(ModuleType): |
def _loadModule(module): |
|
|
__slots__=() |
|
|
|
def __init__(self, name): |
|
self.__name__ = name # Fixes 2.2 not setting __name__ on create |
|
|
|
def __getattribute__(self,attr): |
|
if '.' in modname: |
|
# ensure parent is in sys.modules and parent.modname=self |
|
splitpos = modname.rindex('.') |
|
mod = importString(modname[:splitpos]) |
|
setattr(mod,modname[splitpos+1:],self) |
|
|
|
oldGA = LazyModule.__getattribute__ |
oldGA = LazyModule.__getattribute__ |
|
oldSA = LazyModule.__setattr__ |
|
|
modGA = ModuleType.__getattribute__ |
modGA = ModuleType.__getattribute__ |
|
modSA = ModuleType.__setattr__ |
|
|
LazyModule.__getattribute__ = modGA |
LazyModule.__getattribute__ = modGA |
|
LazyModule.__setattr__ = modSA |
|
|
try: |
try: |
# Get Python (or supplied 'reload') to do the real import! |
# Get Python (or supplied 'reload') to do the real import! |
_loadAndRunHooks(self) |
_loadAndRunHooks(module) |
except: |
except: |
# Reset our state so that we can retry later |
# Reset our state so that we can retry later |
LazyModule.__getattribute__ = oldGA |
if '__file__' not in module.__dict__: |
|
LazyModule.__getattribute__ = oldGA.im_func |
|
LazyModule.__setattr__ = oldSA.im_func |
raise |
raise |
|
|
try: |
try: |
# Convert to a real module (if under 2.2) |
# Convert to a real module (if under 2.2) |
self.__class__ = ModuleType |
module.__class__ = ModuleType |
except TypeError: |
except TypeError: |
pass # 2.3 will fail, but no big deal |
pass # 2.3 will fail, but no big deal |
|
|
# Finish off by returning what was asked for |
|
return modGA(self,attr) |
|
|
|
|
class LazyModule(ModuleType): |
|
__slots__ = () |
|
def __init__(self, name): |
|
ModuleType.__setattr__(self,'__name__',name) |
|
#super(LazyModule,self).__init__(name) |
|
|
if relativePath: |
def __getattribute__(self,attr): |
modname = joinPath(modname, relativePath) |
_loadModule(self) |
|
return ModuleType.__getattribute__(self,attr) |
|
|
|
def __setattr__(self,attr,value): |
|
_loadModule(self) |
|
return ModuleType.__setattr__(self,attr,value) |
|
|
|
if relativePath: |
|
modname = joinPath(modname, relativePath) |
|
|
if modname not in modules: |
if modname not in modules: |
modules[modname] = LazyModule(modname) |
modules[modname] = LazyModule(modname) |
|
|
|
if '.' in modname: |
|
# ensure parent module/package is in sys.modules |
|
# and parent.modname=module, as soon as the parent is imported |
|
|
|
splitpos = modname.rindex('.') |
|
whenImported( |
|
modname[:splitpos], |
|
lambda m: setattr(m,modname[splitpos+1:],modules[modname]) |
|
) |
|
|
return modules[modname] |
return modules[modname] |
|
|
|
|
# if this fails, we haven't called the hooks, so leave them in place |
# if this fails, we haven't called the hooks, so leave them in place |
# for possible retry of import |
# for possible retry of import |
|
|
|
if module.__dict__.keys()==['__name__']: # don't reload if already loaded! |
reload(module) |
reload(module) |
|
|
try: |
try: |
postLoadHooks[module.__name__] = None |
postLoadHooks[module.__name__] = None |
|
|
|
|
|
|
def getModuleHooks(moduleName): |
def getModuleHooks(moduleName): |
|
|
"""Get list of hooks for 'moduleName'; error if module already loaded""" |
"""Get list of hooks for 'moduleName'; error if module already loaded""" |
return hooks |
return hooks |
|
|
|
|
|
def _setModuleHook(moduleName, hook): |
|
|
def whenImported(moduleName, hook): |
if moduleName in modules and postLoadHooks.get(moduleName) is None: |
|
# Module is already imported/loaded, just call the hook |
|
module = modules[moduleName] |
|
hook(module) |
|
return module |
|
|
|
getModuleHooks(moduleName).append(hook) |
|
return lazyModule(moduleName) |
|
|
"""Call 'hook(module)' when module named 'moduleName' is first used |
|
|
|
The module must not have been previously imported, or 'AlreadyRead' |
|
is raised. 'moduleName' is a string containing a fully qualified |
|
module name. 'hook' must accept one argument: the imported module |
|
object. |
|
|
|
This function's name is a slight misnomer... hooks are called when |
|
a module is first *used*, not when it is imported. |
|
|
|
This function returns 'lazyModule(moduleName)', in case you need |
|
the module object for future use.""" |
|
|
|
if name in sys.modules and not name in postLoadHooks: |
|
raise AlreadyRead("Module already imported", name) |
|
|
|
getModuleHooks(moduleName).append(hook) |
|
return lazyModule(moduleName, reloader=_runHooks) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def whenImported(moduleName, hook): |
|
|
|
"""Call 'hook(module)' when module named 'moduleName' is first used |
|
|
|
'hook' must accept one argument: the module object named by 'moduleName', |
|
which must be a fully qualified (i.e. absolute) module name. The hook |
|
should not raise any exceptions, or it may prevent later hooks from |
|
running. |
|
|
|
If the module has already been imported normally, 'hook(module)' is |
|
called immediately, and the module object is returned from this function. |
|
If the module has not been imported, or has only been imported lazily, |
|
then the hook is called when the module is first used, and a lazy import |
|
of the module is returned from this function. If the module was imported |
|
lazily and used before calling this function, the hook is called |
|
immediately, and the loaded module is returned from this function. |
|
|
|
Note that using this function implies a possible lazy import of the |
|
specified module, and lazy importing means that any 'ImportError' will be |
|
deferred until the module is used. |
|
""" |
|
|
|
if '.' in moduleName: |
|
# If parent is not yet imported, delay hook installation until the |
|
# parent is imported. |
|
splitpos = moduleName.rindex('.') |
|
whenImported( |
|
moduleName[:splitpos], lambda m: _setModuleHook(moduleName,hook) |
|
) |
|
else: |
|
return _setModuleHook(moduleName,hook) |
|
|
|
|
|
|
|
|
|
|
return [importString(x.strip(),globalDict) for x in specs.split(',')] |
return [importString(x.strip(),globalDict) for x in specs.split(',')] |
else: |
else: |
return [importObject(s,globalDict) for s in specs] |
return [importObject(s,globalDict) for s in specs] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|