python autoreload

autoreloadに関して少し勉強。Cherrypyを参考にしていたんだけど、前と今ではちょっと処理が違うみたい。
前の処理はhttp://d.hatena.ne.jp/Wacky/20060820/1156050077に書いてあるように、子プロセスが実行プロセスで、親プロセスが管理プロセスの役割を果たしているみたい。
だけど、CherryPy3.0.3からはautoreload.pyがなくなって_cpengine.pyにautoreload関数がある。これがファイル数ごとに
reexec()を行っている感じ。

    def autoreload(self):
        """Reload the process if registered files have been modified."""
        sysfiles = []
        for k, m in sys.modules.items():
            if re.match(self.autoreload_match, k):
                if hasattr(m, "__loader__"):
                    if hasattr(m.__loader__, "archive"):
                        k = m.__loader__.archive
                k = getattr(m, "__file__", None)
                sysfiles.append(k)
        
        for filename in sysfiles + self.reload_files:
            if filename:
                if filename.endswith(".pyc"):
                    filename = filename[:-1]
                
                oldtime = self.mtimes.get(filename, 0)
                if oldtime is None:
                    # Module with no .py file. Skip it.
                    continue
                
                try:
                    mtime = os.stat(filename).st_mtime
                except OSError:
                    # Either a module with no .py file, or it's been deleted.
                    mtime = None
                
                if filename not in self.mtimes:
                    # If a module has no .py file, this will be None.
                    self.mtimes[filename] = mtime
                else:
                    if mtime is None or mtime > oldtime:
                        # The file has been deleted or modified.
                        self.reexec()

reexecは一度サーバーを停止させて、諸設定をした後にexecvを行ってる。そっか、新しい方では一つのプロセスで自動リロードをすませているのか。

def reexec(self):
        """Re-execute the current process."""
        cherrypy.server.stop()
        self.stop()
        
        args = sys.argv[:]
        cherrypy.log("Re-spawning %s" % " ".join(args), "ENGINE")
        args.insert(0, sys.executable)
        
        if sys.platform == "win32":
            args = ['"%s"' % arg for arg in args]
        
        # Some platforms (OS X) will error if all threads are not
        # ABSOLUTELY terminated. See http://www.cherrypy.org/ticket/581.
        for trial in xrange(self.reexec_retry * 10):
            try:
                os.execv(sys.executable, args)
                return
            except OSError, x:
                if x.errno != 45:
                    raise
                time.sleep(0.1)
        else:
            raise