durusmail: quixote-users: Re: 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
Re: rtemplate: utility for reloading changed PTL files
Graham Fawcett
2003-12-08
Neil Schemenauer wrote:
> On Sat, Dec 06, 2003 at 01:18:38AM -0500, Graham Fawcett wrote:
>
>>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.
>
>
> If you use 'from ... import ...' then just reloading the module
> doesn't work too well.  This is what I have been using:


The 'from package import module' form should work fine with my approach;
but it definitely wouldn't handle 'from package.module import
ClassDefinition' forms.

In hindsight, I shouldn't have called my code a "reloader" since it
doesn't actually use the reload() mechanism. It just compiles a source
file into a code object, exec()'s the code object in a mostly-empty
dictionary and returns it as an "anonymous pseudo-module". It's not even
a module instance; it's a dictionary proxied by an object. But Quixote
only needs a namespace, not a module, so it works OK.

It also doesn't try to be global; the reloadable module is only reloaded
from the point of view of any importer which declares it as
reloadable(!). Assume that modules A and B both import module C, but
only A uses "import C; C = ReloadableModule(C)". If the source for C is
modified, then A.C will refer to the new code, but B.C will continue to
refer to the old version. I don't consider this scary or magical, since
the behaviour is explicit. For the kind of development (and debugging)
I'm doing, I find this satisfactory; most of my PTL modules are only
imported from one parent anyway, or I'm only debugging them from one POV
at a time.

I wouldn't use this approach for any module declaring classes of any
objects that persisted beyond a single request. Then again, I probably
wouldn't use reload() in that case, either. ;-) But it seems to work
nicely for PTL modules and UI classes that define throwaway objects.


>
>     def reload_module(fullname):
>         module = sys.modules[fullname]
>         old_items = module.__dict__.items()
>         reload(module)
>         objects = {} # [(old_id, new_object)]
>         for name, value in old_items:
>             if name in module.__dict__:
>                 if name.startswith('_'):
>                     continue
>                 new_value = module.__dict__[name]
>                 if new_value is not value:
>                     objects[id(value)] = new_value
>         for module in sys.modules.values():
>             if not hasattr(module, '__dict__'):
>                 continue
>             for name, value in module.__dict__.items():
>                 if id(value) in objects:
>                     print 'updating', getattr(module, '__name__'), name
>                     setattr(module, name, objects[id(value)])
>         objects.clear()
>
> To use it, I created a form that takes 'fullname' as a query string.
> I have my editor configured to that hitting a key causing the module
> I'm currently editing to be reloaded.  It's not perfect but seems to
> work okay.


Clever approach; certainly more general than mine, since you can reload
any module at any time.

Best wishes,

-- Graham


>   Neil



reply