Index: stm.py =================================================================== --- stm.py (revision 2599) +++ stm.py (working copy) @@ -278,13 +279,15 @@ +class _Pulse(AbstractSubject): + __slots__ = 'next_listener' + def __init__(self): + self.next_listener = None + def __call__(self, ctrl): + map(ctrl.schedule, self.iter_listeners()) + self.next_listener = None - - - - - class Controller(STMHistory): """STM History with support for subjects, listeners, and queueing""" current_listener = destinations = routes = newcells = None @@ -298,6 +300,7 @@ self.layers = [] # heap of layer numbers self.queues = {} # [layer] -> dict of listeners to be run self.to_retry = {} + self.pulse = _Pulse() def checkpoint(self): self.has_run.clear() @@ -319,13 +322,6 @@ self.to_retry.clear() self.destinations = self.routes = None - def __getattr__(self, name): - if name=='pulse': # lazy init due to circular dependency - from peak.events.trellis import Value - self.pulse = Value(0) - return self.pulse - raise AttributeError(name) - def _unrun(self, listener, notified): destinations = self.destinations if destinations is not None: @@ -341,10 +337,10 @@ old = self.current_listener self.current_listener = listener try: - assert listener not in self.has_run,"Re-run of rule without retry" + assert listener not in self.has_run, "Re-run of rule without retry" assert self.active, "Rules must be run atomically" if old is not None: - assert not initialized,"Only un-initialized rules can be nested" + assert not initialized, "Only un-initialized rules can be nested" old_reads, self.reads = self.reads, {} try: listener.run() @@ -366,7 +362,7 @@ raise finally: self.current_listener = old - + def _process_writes(self, listener): # # Remove changed items from self.writes and notify their listeners, @@ -444,8 +446,8 @@ q = get(new) if q is None: - q = self.queues[new] = {listener:1} - heapq.heappush(self.layers, new) + q = self.queues[new] = {listener:1} + heapq.heappush(self.layers, new) else: q[listener] = 1 @@ -471,7 +473,7 @@ layers = self.layers queues = self.queues while layers or self.at_commit: - self.pulse.value += 1 + self.pulse(self) while layers: if self.to_retry: self._retry() Index: trellis.py =================================================================== --- trellis.py (revision 2599) +++ trellis.py (working copy) @@ -571,7 +597,6 @@ - class _Defaulting(addons.Registry): def __init__(self, subject): self.defaults = {} @@ -667,7 +692,8 @@ if listener is None or not hasattr(listener, '_needs_init'): raise RuntimeError("poll() must be called from a rule") else: - return ctrl.pulse.value + on_undo(stm.Link(ctrl.pulse, listener).unlink) def mark_dirty(): """Force the current rule's return value to be treated as if it changed""" @@ -679,7 +705,6 @@ if hasattr(rule, '__get__'): return rule.__get__(ob, typ) return rule - @@ -833,7 +862,7 @@ if getattr(func, '__name__', None)==self.__name__: frame = frame or sys._getframe(2) if frame.f_locals.get(self.__name__) is self: - return self + return self return func frame = frame or sys._getframe(2) @@ -844,7 +873,6 @@ return func return decorators.decorate_assignment(callback, frame=frame) - @@ -859,6 +887,7 @@ + def attr(initially=NO_VALUE, resetting_to=NO_VALUE): return CellAttribute.mkattr(initially, resetting_to) @@ -1104,7 +1133,7 @@ rule=rule, initially=initially, resetting_to=resetting_to, make=make, __proptype = CacheAttr.mkattr ) - + class Dict(UserDict.IterableUserDict, Component): """Dictionary-like object that recalculates observers when it's changed