|
| 1 | +# From http://code.activestate.com/recipes/160164/ |
| 2 | +# Autoreloader, updates class when reload() is called |
| 3 | +import weakref, inspect |
| 4 | + |
| 5 | +class MetaInstanceTracker(type): |
| 6 | + def __new__(cls, name, bases, ns): |
| 7 | + t = super(MetaInstanceTracker, cls).__new__(cls, name, bases, ns) |
| 8 | + t.__instance_refs__ = [] |
| 9 | + return t |
| 10 | + def __instances__(self): |
| 11 | + instances = [(r, r()) for r in self.__instance_refs__] |
| 12 | + instances = filter(lambda (x,y): y is not None, instances) |
| 13 | + self.__instance_refs__ = [r for (r, o) in instances] |
| 14 | + return [o for (r, o) in instances] |
| 15 | + def __call__(self, *args, **kw): |
| 16 | + instance = super(MetaInstanceTracker, self).__call__(*args, **kw) |
| 17 | + self.__instance_refs__.append(weakref.ref(instance)) |
| 18 | + return instance |
| 19 | + |
| 20 | +class InstanceTracker: |
| 21 | + __metaclass__ = MetaInstanceTracker |
| 22 | + |
| 23 | +class MetaAutoReloader(MetaInstanceTracker): |
| 24 | + def __new__(cls, name, bases, ns): |
| 25 | + new_class = super(MetaAutoReloader, cls).__new__( |
| 26 | + cls, name, bases, ns) |
| 27 | + f = inspect.currentframe().f_back |
| 28 | + for d in [f.f_locals, f.f_globals]: |
| 29 | + if d.has_key(name): |
| 30 | + old_class = d[name] |
| 31 | + for instance in old_class.__instances__(): |
| 32 | + instance.change_class(new_class) |
| 33 | + new_class.__instance_refs__.append( |
| 34 | + weakref.ref(instance)) |
| 35 | + # this section only works in 2.3 |
| 36 | + for subcls in old_class.__subclasses__(): |
| 37 | + newbases = () |
| 38 | + for base in subcls.__bases__: |
| 39 | + if base is old_class: |
| 40 | + newbases += (new_class,) |
| 41 | + else: |
| 42 | + newbases += (base,) |
| 43 | + subcls.__bases__ = newbases |
| 44 | + break |
| 45 | + return new_class |
| 46 | + |
| 47 | +class AutoReloader: |
| 48 | + __metaclass__ = MetaAutoReloader |
| 49 | + def change_class(self, new_class): |
| 50 | + print "updating " + str(new_class) |
| 51 | + self.__class__ = new_class |
0 commit comments