I use Quixote with Medusa as a front-end, and it can be a pain to debug a PTL file, due to the inevitable edit_source/stop_server/start_server cycle. This is especially true if you're using non-persistent sessions; when you stop your server to reload the PTL file, your session ends, and you need to log your browser in again before you can check out your modifications. Depending on the specifics of your app, this can be a real time drain. Attached is a utility module that lets you "wrap" a PTL module in a proxy that will reload itself automatically if the source file changes. Since reloading is only done on modules that you wrap explicitly, there should be a minimum of side-effects. Example: From my main module, I want to reload the module 'buggy' whenever its source changes: # ---- main.ptl ---- from rtemplate import Reloadable import buggy # load the module once buggy = Reloadable(buggy) # wrap it _q_exports = ['buggy', ... ] ... # ------------------ That's it. Whenever a request is passed to 'buggy', a stat() call will check whether the source has been modified, and if so, it will be recompiled before the request is handed over. A 'reloading' message is written to sys.stderr when this occurs. Note that this also seems to work for Python modules, but that it uses quixote.ptl_compile to do the compilation. If PTL is a true superset of Python (and I think it is...?), then this ought not cause any problems. Hope it helps somebody, -- Graham
""" rtemplate -- support for reloading changed PTL files (to aid debugging) Graham Fawcett2003.12.06 -- first revision. """ from quixote.ptl_compile import compile_template import os import sys import time class Reloadable: """ A module proxy that reloads itself when its source file changes. The constructor takes an already-loaded PTL module, and acts as a proxy for that module. If the module's source changes, this class will recompile the PTL file and replace its copy of the original module with the modified module. Seems to work for normal Python modules as well. """ def __init__(self, module): self.filename = module.__file__ print self.filename self.name = module.__name__ self.lastloaded = time.time() self.mtime = self._get_mtime() self.module = module.__dict__ def _get_mtime(self): x = os.stat(self.filename).st_mtime return x def __getattr__(self, name): mtime = self._get_mtime() if mtime > self.mtime: self.mtime = mtime self._reload() try: return self.module[name] except KeyError, msg: raise AttributeError, msg def _reload(self): print >> sys.stderr, '%s: Reloading %s' % (time.ctime(), self.name) f = open(self.filename) try: codeobj = compile_template(f, self.filename) m = {} m['__name__'] = self.name m['__file__'] = self.filename exec codeobj in m finally: f.close() self.module = m