durusmail: quixote-users: rtemplate: utility for reloading changed PTL files
rtemplate: utility for reloading changed PTL files
2003-12-06
Re: rtemplate: utility for reloading changed PTL files
2003-12-06
2003-12-06
2003-12-06
2003-12-06
Re: rtemplate: utility for reloading changed PTL files
2003-12-07
Re: rtemplate: utility for reloading changed PTL files
2003-12-07
Re: rtemplate: utility for reloading changed PTL files
2003-12-08
2003-12-07
2003-12-08
2003-12-06
Re: rtemplate: utility for reloading changed PTL files
2003-12-08
Re: rtemplate: utility for reloading changed PTLfiles
2003-12-08
2003-12-08
rtemplate: utility for reloading changed PTL files
Graham Fawcett
2003-12-06
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 Fawcett 
2003.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

reply