    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)