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)