Dynamically Update Class Definitions?

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • chrisspen@gmail.com

    #1

    Dynamically Update Class Definitions?

    Is there a way to loop through all instantiated objects and update
    their classes when a source file changes? I know about Michael Hudson's
    method
    (http://aspn.activestate.com/ASPN/Coo...Recipe/160164), but
    you have to modify all your classes to subclass AutoReloader. Is there
    something less intrusive (visitor pattern?) that you can use like
    update(old_clas s, new_class) to automagically do the work?

    Chris

  • Alex Martelli

    #2
    Re: Dynamically Update Class Definitions?

    <chrisspen@gmai l.com> wrote:
    [color=blue]
    > Is there a way to loop through all instantiated objects and update
    > their classes when a source file changes? I know about Michael Hudson's
    > method
    > (http://aspn.activestate.com/ASPN/Coo...Recipe/160164), but
    > you have to modify all your classes to subclass AutoReloader. Is there
    > something less intrusive (visitor pattern?) that you can use like
    > update(old_clas s, new_class) to automagically do the work?[/color]

    If you're in no hurry, you COULD loop over all of gc.get_objects( ),
    identify all those which are instances of old_class and "somehow" change
    their classes to new_class -- of course, x.__class__ = new_class may
    well not be sufficient, in which case you'll have to pass to update a
    callable to do the instance-per-instance job.


    Alex

    Comment

    • Chris Spencer

      #3
      Re: Dynamically Update Class Definitions?

      Alex Martelli wrote:[color=blue]
      > <chrisspen@gmai l.com> wrote:
      >
      >[color=green]
      >>Is there a way to loop through all instantiated objects and update
      >>their classes when a source file changes? I know about Michael Hudson's
      >>method
      >>(http://aspn.activestate.com/ASPN/Coo...Recipe/160164), but
      >>you have to modify all your classes to subclass AutoReloader. Is there
      >>something less intrusive (visitor pattern?) that you can use like
      >>update(old_cl ass, new_class) to automagically do the work?[/color]
      >
      >
      > If you're in no hurry, you COULD loop over all of gc.get_objects( ),
      > identify all those which are instances of old_class and "somehow" change
      > their classes to new_class -- of course, x.__class__ = new_class may
      > well not be sufficient, in which case you'll have to pass to update a
      > callable to do the instance-per-instance job.[/color]

      Couldn't I just loop over gc.get_referrer s(cls), checking for instances
      of the class object? Since class instances refer to their class, the gc
      seems to be doing the exact same thing as Hudson's fancy metaclass. Or
      am I missing something?

      Chris

      Comment

      • Chris Spencer

        #4
        Re: Dynamically Update Class Definitions?

        Chris Spencer wrote:[color=blue]
        > Alex Martelli wrote:[/color]
        [color=blue][color=green]
        >> If you're in no hurry, you COULD loop over all of gc.get_objects( ),
        >> identify all those which are instances of old_class and "somehow" change
        >> their classes to new_class -- of course, x.__class__ = new_class may
        >> well not be sufficient, in which case you'll have to pass to update a
        >> callable to do the instance-per-instance job.[/color]
        >
        >
        > Couldn't I just loop over gc.get_referrer s(cls), checking for instances
        > of the class object? Since class instances refer to their class, the gc
        > seems to be doing the exact same thing as Hudson's fancy metaclass. Or
        > am I missing something?
        >
        > Chris[/color]

        In fact, the following code seems to work, and doesn't require any
        modification to new-style class based code:

        import os
        import time
        import threading
        import inspect
        import gc
        import copy

        class ModuleUpdater(o bject):
        '''
        This will constantly check a module's source file for updates, reload
        if any are detected, and update all class instances.
        Only works for new-style classes.

        Use like:
        checker = ModuleUpdater(m odule=mymod)
        checker.start()
        '''
        def __init__(self, module):
        self.module = module
        self.lastloaded = time.time()
        self.running = 0
        self.t = None
        def __call__(self):
        self.running = 1
        while self.running:
        self.check()
        time.sleep(1)
        def check(self):
        lastmodified = os.stat(inspect .getsourcefile( self.module))[8]
        if lastmodified > self.lastloaded :
        print 'update detected for',self.modul e.__name__
        oldmod = copy.copy(self. module.__dict__ )
        newmod = reload(self.mod ule)
        try:
        for name,obj in oldmod.items():
        if isinstance(obj, type) and name in newmod.__dict__ :
        newobj = newmod.__dict__[name]
        referrers = gc.get_referrer s(obj)
        for referrer in referrers:
        if isinstance(refe rrer,obj):
        # update old class instances to use new
        class
        referrer.__clas s__ = newobj
        print 'update loaded for',self.modul e.__name__
        except Exception, e:
        print 'unable to load update for %s: %s' %
        (self.module.__ name__, str(e))
        self.lastloaded = lastmodified
        return 1
        return 0
        def start(self):
        t = threading.Threa d(target=self)
        t.setDaemon(1)
        t.start()
        self.t = t
        return t
        def stop(self, blocking=0):
        self.running = 0
        if blocking:
        self.t.join()

        if __name__ == '__main__':

        import testmod # any module containing class Bar with method meth
        uc = ModuleUpdater(t estmod)

        uc.start()

        b=testmod.Bar(1 )
        while 1: # meanwhile, modify the source to testmod.py
        time.sleep(1)
        print b.meth()

        Comment

        Working...