Chris said:
Alex Martelli wrote:
Couldn't I just loop over gc.get_referrers(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
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(object):
'''
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(module=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.module.__name__
oldmod = copy.copy(self.module.__dict__)
newmod = reload(self.module)
try:
for name,obj in oldmod.items():
if isinstance(obj,type) and name in newmod.__dict__:
newobj = newmod.__dict__[name]
referrers = gc.get_referrers(obj)
for referrer in referrers:
if isinstance(referrer,obj):
# update old class instances to use new
class
referrer.__class__ = newobj
print 'update loaded for',self.module.__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.Thread(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(testmod)
uc.start()
b=testmod.Bar(1)
while 1: # meanwhile, modify the source to testmod.py
time.sleep(1)
print b.meth()