import ihooks
import os
import sys
"""
ImportSpy.py
The purpose of this module is to record the filepath of every module which
is imported. This is used by the AutoReloadingAppServer (see doc strings
for more information) to restart the server if any source files change.
Other than keeping track of the filepaths, the behaviour of this module
loader is identical to Python's default behaviour.
"""
True, False = 1==1, 0==1
class ModuleLoader(ihooks.ModuleLoader):
def __init__(self):
assert modloader is None, \
"ModuleLoader can only be instantiated once"
ihooks.ModuleLoader.__init__(self)
self._fileList = {}
self._notifyHook = None
self._installed = False
def load_module(self,name,stuff):
try:
mod = ihooks.ModuleLoader.load_module(self, name, stuff)
self.recordFileName(stuff, mod)
except:
self.recordFileName(stuff, None)
raise
return mod
def recordModules(self, moduleNames):
for name in moduleNames:
mod = sys.modules[name]
if not hasattr(mod, '__file__'):
# If we can't find it, we can't monitor it
continue
file = mod.__file__
pathname = os.path.dirname(file)
desc = None
self.recordFileName((file, pathname, desc),
sys.modules[name])
def fileList(self):
return self._fileList
def notifyOfNewFiles(self, hook):
""" Called by someone else to register that they'd like to
be know when a new file is imported """
self._notifyHook = hook
def watchFile(self, filepath, getmtime=os.path.getmtime):
modtime = getmtime(filepath)
self._fileList[filepath] = modtime
# send notification that this file was imported
if self._notifyHook:
self._notifyHook(filepath,modtime)
def recordFileName(self, stuff, mod, isfile=os.path.isfile):
file, pathname, desc = stuff
fileList = self._fileList
if mod:
# __orig_file__ is used for cheetah and psp mods; we want
# to record the source filenames, not the auto-generated modules
f2 = getattr(mod, '__orig_file__', 0)
f = getattr(mod, '__file__', 0)
if f2 and f2 not in fileList.keys():
try:
if isfile(f2):
self.watchFile(f2)
except OSError:
pass
elif f and f not in fileList.keys():
# record the .py file corresponding to each '.pyc'
if f[-4:] == '.pyc':
f = f[:-1]
try:
if isfile(f):
self.watchFile(f)
else:
self.watchFile(os.path.join(f, '__init__.py'))
except OSError:
pass
# also record filepaths which weren't successfully
# loaded, which may happen due to a syntax error in a
# servlet, because we also want to know when such a
# file is modified
elif pathname:
if isfile(pathname):
self.watchFile(pathname)
def activate(self):
imp = ihooks.ModuleImporter(loader=modloader)
ihooks.install(imp)
self.recordModules(sys.modules.keys())
self._installed = True
# We do this little double-assignment trick to make sure ModuleLoader
# is only instantiated once.
modloader = None
modloader = ModuleLoader()
""" These two methods are compatible with the 'imp' module (and can
therefore be useds as drop-in replacements), but will use the
above ModuleLoader to record the pathnames of imported modules.
"""
def load_module(name, file, filename, description):
return modloader.load_module(name,(file,filename,description))
def find_module(name,path=None):
return modloader.find_module(name,path)