PKpi•7þJÎ""_threading_local.py"""Thread-local objects. (Note that this module provides a Python version of the threading.local class. Depending on the version of Python you're using, there may be a faster one available. You should always import the `local` class from `threading`.) Thread-local objects support the management of thread-local data. If you have data that you want to be local to a thread, simply create a thread-local object and use its attributes: >>> mydata = local() >>> mydata.number = 42 >>> mydata.number 42 You can also access the local-object's dictionary: >>> mydata.__dict__ {'number': 42} >>> mydata.__dict__.setdefault('widgets', []) [] >>> mydata.widgets [] What's important about thread-local objects is that their data are local to a thread. If we access the data in a different thread: >>> log = [] >>> def f(): ... items = mydata.__dict__.items() ... items.sort() ... log.append(items) ... mydata.number = 11 ... log.append(mydata.number) >>> import threading >>> thread = threading.Thread(target=f) >>> thread.start() >>> thread.join() >>> log [[], 11] we get different data. Furthermore, changes made in the other thread don't affect data seen in this thread: >>> mydata.number 42 Of course, values you get from a local object, including a __dict__ attribute, are for whatever thread was current at the time the attribute was read. For that reason, you generally don't want to save these values across threads, as they apply only to the thread they came from. You can create custom local objects by subclassing the local class: >>> class MyLocal(local): ... number = 2 ... initialized = False ... def __init__(self, **kw): ... if self.initialized: ... raise SystemError('__init__ called too many times') ... self.initialized = True ... self.__dict__.update(kw) ... def squared(self): ... return self.number ** 2 This can be useful to support default values, methods and initialization. Note that if you define an __init__ method, it will be called each time the local object is used in a separate thread. This is necessary to initialize each thread's dictionary. Now if we create a local object: >>> mydata = MyLocal(color='red') Now we have a default number: >>> mydata.number 2 an initial color: >>> mydata.color 'red' >>> del mydata.color And a method that operates on the data: >>> mydata.squared() 4 As before, we can access the data in a separate thread: >>> log = [] >>> thread = threading.Thread(target=f) >>> thread.start() >>> thread.join() >>> log [[('color', 'red'), ('initialized', True)], 11] without affecting this thread's data: >>> mydata.number 2 >>> mydata.color Traceback (most recent call last): ... AttributeError: 'MyLocal' object has no attribute 'color' Note that subclasses can define slots, but they are not thread local. They are shared across threads: >>> class MyLocal(local): ... __slots__ = 'number' >>> mydata = MyLocal() >>> mydata.number = 42 >>> mydata.color = 'red' So, the separate thread: >>> thread = threading.Thread(target=f) >>> thread.start() >>> thread.join() affects what we see: >>> mydata.number 11 >>> del mydata """ __all__ = ["local"] # We need to use objects from the threading module, but the threading # module may also want to use our `local` class, if support for locals # isn't compiled in to the `thread` module. This creates potential problems # with circular imports. For that reason, we don't import `threading` # until the bottom of this file (a hack sufficient to worm around the # potential problems). Note that almost all platforms do have support for # locals in the `thread` module, and there is no circular import problem # then, so problems introduced by fiddling the order of imports here won't # manifest on most boxes. class _localbase(object): __slots__ = '_local__key', '_local__args', '_local__lock' def __new__(cls, *args, **kw): self = object.__new__(cls) key = '_local__key', 'thread.local.' + str(id(self)) object.__setattr__(self, '_local__key', key) object.__setattr__(self, '_local__args', (args, kw)) object.__setattr__(self, '_local__lock', RLock()) if args or kw and (cls.__init__ is object.__init__): raise TypeError("Initialization arguments are not supported") # We need to create the thread dict in anticipation of # __init__ being called, to make sure we don't call it # again ourselves. dict = object.__getattribute__(self, '__dict__') currentThread().__dict__[key] = dict return self def _patch(self): key = object.__getattribute__(self, '_local__key') d = currentThread().__dict__.get(key) if d is None: d = {} currentThread().__dict__[key] = d object.__setattr__(self, '__dict__', d) # we have a new instance dict, so call out __init__ if we have # one cls = type(self) if cls.__init__ is not object.__init__: args, kw = object.__getattribute__(self, '_local__args') cls.__init__(self, *args, **kw) else: object.__setattr__(self, '__dict__', d) class local(_localbase): def __getattribute__(self, name): lock = object.__getattribute__(self, '_local__lock') lock.acquire() try: _patch(self) return object.__getattribute__(self, name) finally: lock.release() def __setattr__(self, name, value): lock = object.__getattribute__(self, '_local__lock') lock.acquire() try: _patch(self) return object.__setattr__(self, name, value) finally: lock.release() def __delattr__(self, name): lock = object.__getattribute__(self, '_local__lock') lock.acquire() try: _patch(self) return object.__delattr__(self, name) finally: lock.release() def __del__(self): import threading key = object.__getattribute__(self, '_local__key') try: threads = list(threading.enumerate()) except: # If enumerate fails, as it seems to do during # shutdown, we'll skip cleanup under the assumption # that there is nothing to clean up. return for thread in threads: try: __dict__ = thread.__dict__ except AttributeError: # Thread is dying, rest in peace. continue if key in __dict__: try: del __dict__[key] except KeyError: pass # didn't have anything in this thread from threading import currentThread, RLock PKÆ¢œ8MsB___threading_local.pyc;ò ÔlGc@s[dZdgZdefd„ƒYZd„Zdefd„ƒYZdklZlZdS(sø Thread-local objects. (Note that this module provides a Python version of the threading.local class. Depending on the version of Python you're using, there may be a faster one available. You should always import the `local` class from `threading`.) Thread-local objects support the management of thread-local data. If you have data that you want to be local to a thread, simply create a thread-local object and use its attributes: >>> mydata = local() >>> mydata.number = 42 >>> mydata.number 42 You can also access the local-object's dictionary: >>> mydata.__dict__ {'number': 42} >>> mydata.__dict__.setdefault('widgets', []) [] >>> mydata.widgets [] What's important about thread-local objects is that their data are local to a thread. If we access the data in a different thread: >>> log = [] >>> def f(): ... items = mydata.__dict__.items() ... items.sort() ... log.append(items) ... mydata.number = 11 ... log.append(mydata.number) >>> import threading >>> thread = threading.Thread(target=f) >>> thread.start() >>> thread.join() >>> log [[], 11] we get different data. Furthermore, changes made in the other thread don't affect data seen in this thread: >>> mydata.number 42 Of course, values you get from a local object, including a __dict__ attribute, are for whatever thread was current at the time the attribute was read. For that reason, you generally don't want to save these values across threads, as they apply only to the thread they came from. You can create custom local objects by subclassing the local class: >>> class MyLocal(local): ... number = 2 ... initialized = False ... def __init__(self, **kw): ... if self.initialized: ... raise SystemError('__init__ called too many times') ... self.initialized = True ... self.__dict__.update(kw) ... def squared(self): ... return self.number ** 2 This can be useful to support default values, methods and initialization. Note that if you define an __init__ method, it will be called each time the local object is used in a separate thread. This is necessary to initialize each thread's dictionary. Now if we create a local object: >>> mydata = MyLocal(color='red') Now we have a default number: >>> mydata.number 2 an initial color: >>> mydata.color 'red' >>> del mydata.color And a method that operates on the data: >>> mydata.squared() 4 As before, we can access the data in a separate thread: >>> log = [] >>> thread = threading.Thread(target=f) >>> thread.start() >>> thread.join() >>> log [[('color', 'red'), ('initialized', True)], 11] without affecting this thread's data: >>> mydata.number 2 >>> mydata.color Traceback (most recent call last): ... AttributeError: 'MyLocal' object has no attribute 'color' Note that subclasses can define slots, but they are not thread local. They are shared across threads: >>> class MyLocal(local): ... __slots__ = 'number' >>> mydata = MyLocal() >>> mydata.number = 42 >>> mydata.color = 'red' So, the separate thread: >>> thread = threading.Thread(target=f) >>> thread.start() >>> thread.join() affects what we see: >>> mydata.number 11 >>> del mydata slocals _localbasecBs tZdddfZd„ZRS(Ns _local__keys _local__argss _local__lockcOsÈti|ƒ}ddtt|ƒƒf}ti|d|ƒti|d||fƒti|dt ƒƒ|p|o|i ti jot dƒ‚nti |dƒ}|tƒi|<|SdS(Ns _local__keys thread.local.s _local__argss _local__locks*Initialization arguments are not supporteds__dict__(sobjects__new__sclssselfsstrsidskeys __setattr__sargsskwsRLocks__init__s TypeErrors__getattribute__sdicts currentThreads__dict__(sclssargsskwsselfskeysdict((s)build\bdist.win32\egg\_threading_local.pys__new__—s!(s__name__s __module__s __slots__s__new__(((s)build\bdist.win32\egg\_threading_local.pys _localbase”scCsÆti|dƒ}tƒii|ƒ}|tjo{h}|tƒi|>> mydata = local() >>> mydata.number = 42 >>> mydata.number 42 You can also access the local-object's dictionary: >>> mydata.__dict__ {'number': 42} >>> mydata.__dict__.setdefault('widgets', []) [] >>> mydata.widgets [] What's important about thread-local objects is that their data are local to a thread. If we access the data in a different thread: >>> log = [] >>> def f(): ... items = mydata.__dict__.items() ... items.sort() ... log.append(items) ... mydata.number = 11 ... log.append(mydata.number) >>> import threading >>> thread = threading.Thread(target=f) >>> thread.start() >>> thread.join() >>> log [[], 11] we get different data. Furthermore, changes made in the other thread don't affect data seen in this thread: >>> mydata.number 42 Of course, values you get from a local object, including a __dict__ attribute, are for whatever thread was current at the time the attribute was read. For that reason, you generally don't want to save these values across threads, as they apply only to the thread they came from. You can create custom local objects by subclassing the local class: >>> class MyLocal(local): ... number = 2 ... initialized = False ... def __init__(self, **kw): ... if self.initialized: ... raise SystemError('__init__ called too many times') ... self.initialized = True ... self.__dict__.update(kw) ... def squared(self): ... return self.number ** 2 This can be useful to support default values, methods and initialization. Note that if you define an __init__ method, it will be called each time the local object is used in a separate thread. This is necessary to initialize each thread's dictionary. Now if we create a local object: >>> mydata = MyLocal(color='red') Now we have a default number: >>> mydata.number 2 an initial color: >>> mydata.color 'red' >>> del mydata.color And a method that operates on the data: >>> mydata.squared() 4 As before, we can access the data in a separate thread: >>> log = [] >>> thread = threading.Thread(target=f) >>> thread.start() >>> thread.join() >>> log [[('color', 'red'), ('initialized', True)], 11] without affecting this thread's data: >>> mydata.number 2 >>> mydata.color Traceback (most recent call last): ... AttributeError: 'MyLocal' object has no attribute 'color' Note that subclasses can define slots, but they are not thread local. They are shared across threads: >>> class MyLocal(local): ... __slots__ = 'number' >>> mydata = MyLocal() >>> mydata.number = 42 >>> mydata.color = 'red' So, the separate thread: >>> thread = threading.Thread(target=f) >>> thread.start() >>> thread.join() affects what we see: >>> mydata.number 11 >>> del mydata slocals _localbasecBs tZdddfZd„ZRS(Ns _local__keys _local__argss _local__lockcOsÈti|ƒ}ddtt|ƒƒf}ti|d|ƒti|d||fƒti|dt ƒƒ|p|o|i ti jot dƒ‚nti |dƒ}|tƒi|<|SdS(Ns _local__keys thread.local.s _local__argss _local__locks*Initialization arguments are not supporteds__dict__(sobjects__new__sclssselfsstrsidskeys __setattr__sargsskwsRLocks__init__s TypeErrors__getattribute__sdicts currentThreads__dict__(sclssargsskwsselfskeysdict((s)build\bdist.win32\egg\_threading_local.pys__new__—s!(s__name__s __module__s __slots__s__new__(((s)build\bdist.win32\egg\_threading_local.pys _localbase”scCsÆti|dƒ}tƒii|ƒ}|tjo{h}|tƒi|>> from peak.events import trellis >>> class TempConverter(trellis.Component): ... F = trellis.maintain( ... lambda self: self.C * 1.8 + 32, ... initially = 32 ... ) ... C = trellis.maintain( ... lambda self: (self.F - 32)/1.8, ... initially = 0 ... ) ... @trellis.perform ... def show_values(self): ... print "Celsius......", self.C ... print "Fahrenheit...", self.F >>> tc = TempConverter(C=100) Celsius...... 100 Fahrenheit... 212.0 >>> tc.F = 32 Celsius...... 0.0 Fahrenheit... 32 >>> tc.C = -40 Celsius...... -40 Fahrenheit... -40.0 As you can see, each attribute is updated if the other one changes, and the ``show_values`` action is invoked any time the dependent values change... but not if they don't:: >>> tc.C = -40 Since the value didn't change, none of the rules based on it were recalculated. Now, imagine all this, but scaled up to include rules that can depend on things like how long it's been since something happened... whether a mouse button was clicked... whether a socket is readable... or whether a Twisted "deferred" object has fired. With automatic dependency tracking that spans function calls, so you don't even need to *know* what values your rule depends on, let alone having to explicitly code any dependencies in! Imagine painless MVC, where you simply write rules like the above to update GUI widgets with application values... and vice versa. And then, you'll have the tiny beginning of a mere glimpse... of what the Trellis can do for you. Other Python libraries exist which attempt to do similar things, of course; PyCells and Cellulose are two. However, only the Trellis supports fully circular rules (like the temperature conversion example above), and intra-pulse write conflict detection. The Trellis also uses less memory for each cell (rule/value object), and offers many other features that either PyCells or Cellulose lack. The Trellis package can can be `downloaded from the Python Package Index`_ or installed using `Easy Install`_, and it has a fair amount of documentation, including the following manuals: * `Developer's Guide and Tutorial`_ (Extensively revised for 0.6a1) * `Time, Event Loops, and Tasks`_ (NEW for 0.6a1) * `Event-Driven Collections with the Trellis`_ (NEW for 0.6a1) * `Software Transactional Memory (STM) And Observers`_ (NEW for 0.6a1) * `Porting Code from Older Trellis Versions`_ (NEW for 0.7a1) Questions, discussion, and bug reports for the Trellis should be directed to the `PEAK mailing list`_. .. _downloaded from the Python Package Index: http://pypi.python.org/pypi/Trellis#toc .. _Easy Install: http://peak.telecommunity.com/DevCenter/EasyInstall .. _PEAK mailing list: http://www.eby-sarna.com/mailman/listinfo/PEAK/ .. _Developer's Guide and Tutorial: http://peak.telecommunity.com/DevCenter/Trellis#toc .. _Time, Event Loops, and Tasks: http://peak.telecommunity.com/DevCenter/TrellisActivity .. _Event-Driven Collections with the Trellis: http://peak.telecommunity.com/DevCenter/TrellisCollections .. _Software Transactional Memory (STM) And Observers: http://peak.telecommunity.com/DevCenter/TrellisSTM .. _Porting Code from Older Trellis Versions: http://peak.telecommunity.com/DevCenter/TrellisPorting .. _porting guide: http://peak.telecommunity.com/DevCenter/TrellisPorting .. _toc: Platform: UNKNOWN PKÆ¢œ8]‚Ä^^EGG-INFO/requires.txtSymbolType>=1.0 AddOns>=0.6 DecoratorTools>=1.6 Contextual>=0.7a1dev-r2410,==dev Extremes>=1.1PKÆ¢œ8³¢â??EGG-INFO/SOURCES.txtActivity.txt Collections.txt Internals.txt Porting.txt README.txt SQLAlchemy.txt STM-Observer.txt _threading_local.py setup.cfg setup.py test_sets.py test_trellis.py testreactor.py Trellis.egg-info/PKG-INFO Trellis.egg-info/SOURCES.txt Trellis.egg-info/dependency_links.txt Trellis.egg-info/namespace_packages.txt Trellis.egg-info/requires.txt Trellis.egg-info/top_level.txt ez_setup/README.txt ez_setup/__init__.py peak/__init__.py peak/events/__init__.py peak/events/activity.py peak/events/collections.py peak/events/sa_support.py peak/events/stm.py peak/events/trellis.pyPKÆ¢œ8¾óEGG-INFO/top_level.txt_threading_local peak PKÆ¢œ8“×2EGG-INFO/zip-safe PKăÔ4‰kÔ<99peak/__init__.py__import__('pkg_resources').declare_namespace(__name__) PKÆ¢œ85K ÍÍpeak/__init__.pyc;ò ÑZ˜Dc@sedƒieƒdS(s pkg_resourcesN(s __import__sdeclare_namespaces__name__(((s&build\bdist.win32\egg\peak\__init__.pys?sPKÆ¢œ85K ÍÍpeak/__init__.pyo;ò ÑZ˜Dc@sedƒieƒdS(s pkg_resourcesN(s __import__sdeclare_namespaces__name__(((s&build\bdist.win32\egg\peak\__init__.pys?sPKóY•8¬$.á6á6peak/events/activity.pyfrom peak import context from peak.events import trellis, stm from peak.util import addons, decorators, symbols from peak.util.extremes import Min, Max import heapq, weakref, time, sys __all__ = [ 'Time', 'EPOCH', 'NOT_YET', 'EventLoop', 'WXEventLoop', 'TwistedEventLoop', 'task', 'resume', 'Pause', 'Return', 'TaskCell', ] try: set except NameError: from sets import Set as set class _Timer(object): """Value representing a moment in time""" __slots__ = '_when' def __init__(self, _when): self._when = _when def __getitem__(self, interval): """Get a timer that's offset from this one by `interval` seconds""" if self is NOT_YET: return self return _Timer(self._when + interval) def __sub__(self, other): """Get the interval in seconds between two timers""" if not isinstance(other, _Timer): raise TypeError("Can't subtract %r from timer" % (other,)) return self._when - other._when def __eq__(self, other): if not isinstance(other, _Timer): return False return self._when == other._when def __ne__(self, other): return not self==other def __ge__(self, other): return not self < other def __nonzero__(self): return Time.reached(self) def __lt__(self, other): if not isinstance(other, _Timer): raise TypeError # for now return self._when < other._when def __hash__(self): return hash(self._when) def begins_with(self, flag): """Keep track of the moment when `flag` first becomes true""" if flag: return min(self, Time[0]) return NOT_YET EPOCH = _Timer(0) NOT_YET = _Timer(Max) class EventLoop(trellis.Component, context.Service): """Run an application event loop""" trellis.attrs( running = False, stop_requested = False, ) _call_queue = trellis.make(list, writable=True) _next_time = trellis.compute(lambda self: Time.next_event_time(True)) _callback_active = initialized = False def run(self): """Loop updating the time and invoking requested calls""" assert not self.running, "EventLoop is already running" assert not trellis.ctrl.active, "Event loop can't be run atomically" self.call(lambda:None) self.stop_requested = False self.running = True try: Time.tick() self._loop() self.stop() finally: self._tearDown() def stop(self): """Stop the event loop at the next opportunity""" assert self.running, "EventLoop isn't running" self.stop_requested = True decorators.decorate(trellis.modifier) def call(self, func, *args, **kw): """Call `func(*args, **kw)` at the next opportunity""" self._call_queue.append((func, args, kw)) if not self.initialized: self._setup() self.initialized = True trellis.on_undo(self._call_queue.pop) self._callback_if_needed() def poll(self): """Execute up to a single pending call""" self.flush(1) def flush(self, count=0): """Execute the specified number of pending calls (0 for all)""" assert not trellis.ctrl.active, "Event loop can't be run atomically" queue = self._split_queue(count) for (f, args, kw) in queue: f(*args, **kw) self._callback_if_needed() if Time.auto_update: Time.tick() else: Time.advance(self._next_time or 0) decorators.decorate(trellis.modifier) def _callback_if_needed(self): if self._call_queue and not self._callback_active: self._arrange_callback(self._callback) self._callback_active = True decorators.decorate(trellis.modifier) def _split_queue(self, count): queue = self._call_queue count = count or len(queue) if queue: head, self._call_queue = queue[:count], queue[count:] return head return () decorators.decorate(trellis.modifier) def _tearDown(self): self.running = False self.stop_requested = False def _callback(self): self._callback_active = False self.flush(1) def _loop(self): """Subclasses should invoke their external loop here""" queue = self._call_queue while (queue or self._next_time) and not self.stop_requested: self.flush(1) def _setup(self): """Subclasses should import/setup their external loop here Note: must be inherently thread-safe, or else use a cell attribute in order to benefit from locking. This method is called atomically, but you should not log any undo actions.""" def _arrange_callback(self, func): """Subclasses should register `func` to be called by external loop Note: Must be safe to call this from a 'foreign' thread.""" class TwistedEventLoop(EventLoop): """Twisted version of the event loop""" context.replaces(EventLoop) reactor = _delayed_call = None trellis.perform() def _ticker(self): if self.running: if Time.auto_update: if self._next_time is not None: if self._delayed_call and self._delayed_call.active(): self._delayed_call.reset(self._next_time) else: self._delayed_call = self.reactor.callLater( self._next_time, Time.tick ) if self.stop_requested: self.reactor.stop() def _loop(self): """Loop updating the time and invoking requested calls""" self.reactor.run() def _arrange_callback(self, func): self.reactor.callLater(0, func) def _setup(self): from twisted.internet import reactor self.reactor = reactor class WXEventLoop(EventLoop): """wxPython version of the event loop This isn't adequately tested; the wx event loop is completely hosed when it comes to running without any windows, so it's basically impossible to unit test without mocking 'wx' (which I haven't tried to do. Use at your own risk. :( """ context.replaces(EventLoop) wx = None trellis.perform() def _ticker(self): if self.running: if Time.auto_update: if self._next_time is not None: self.wx.FutureCall(self._next_time*1000, Time.tick) if self.stop_requested: self.wx.GetApp().ExitMainLoop() def _loop(self): """Loop updating the time and invoking requested calls""" app = self.wx.GetApp() assert app is not None, "wx.App not created" while not self.stop_requested: app.MainLoop() if app.ExitOnFrameDelete: # handle case where windows exist self.stop() else: app.ProcessPendingEvents() # ugh def _arrange_callback(self, func): """Call `func(*args, **kw)` at the next opportunity""" self.wx.CallAfter(func) def _setup(self): import wx self.wx = wx class Time(trellis.Component, context.Service): """Manage current time and intervals""" _now = EPOCH._when auto_update = trellis.attr(True) _schedule = trellis.make(lambda self: [Max], writable=True) _events = trellis.make(weakref.WeakValueDictionary) trellis.maintain() def _updated(self): schedule = self._schedule while self._tick >= schedule[0]: key = heapq.heappop(schedule) trellis.on_undo(heapq.heappush, schedule, key) if key in self._events: self._events[key].value = True def reached(self, timer): when = timer._when return self._now >= when or ( trellis.ctrl.current_listener is not None and self._event_for(when).value ) decorators.decorate(trellis.modifier) def _event_for(self, when): e = self._events.get(when) if e is None: # heappush doesn't need undo, since _update ignores extras heapq.heappush(self._schedule, when) self._events[when] = e = trellis.Value(False) trellis.on_undo(self._events.pop, when, None) trellis.changed(trellis.Cells(self)['_schedule']) return e def __getitem__(self, interval): """Return a timer that's the given offset from the current time""" return _Timer(self._now + interval) def advance(self, interval): """Advance the current time by the given interval""" self._set(self._now + interval) def tick(self): """Update current time to match ``time.time()``""" self._set(self.time()) def _set(self, when): trellis.change_attr(self, '_now', when) self._tick = when _set = trellis.modifier(_set) trellis.maintain(initially=EPOCH._when) def _tick(self): if self.auto_update: tick = self._now = self.time() trellis.poll() return tick return self._tick def next_event_time(self, relative=False): """The time of the next event to occur, or ``None`` if none scheduled If `relative` is True, returns the number of seconds until the event; otherwise, returns the absolute ``time.time()`` of the event. """ now = self._tick # ensure recalc whenever time moves forward when = self._schedule[0] if when is Max: return None if relative: return when - now return when def time(self): return time.time() class TaskCell(trellis.AbstractCell, stm.AbstractListener): """Cell that manages a generator-based task""" __slots__ = ( '_result', '_error', '_step', 'next_subject', 'layer', '_loop', '_scheduled', '__weakref__', ) def __init__(self, func): self._step = self._stepper(func) self.layer = 0 self.next_subject = None self._loop = EventLoop.get() self._scheduled = False trellis.atomically(self.dirty) def dirty(self): if not self._scheduled: trellis.change_attr(self, '_scheduled', True) trellis.on_commit(self._loop.call, trellis.atomically, self.do_run) trellis.on_commit(trellis.change_attr, self, '_scheduled', False) return False decorators.decorate(classmethod) def from_attr(cls, rule, value, discrete): return cls(rule) def _stepper(self, func): VALUE = self._result = [] ERROR = self._error = [] STACK = [func()] CALL = STACK.append RETURN = STACK.pop ctrl = trellis.ctrl def _step(): while STACK: try: it = STACK[-1] if VALUE and hasattr(it, 'send'): rv = it.send(VALUE[0]) elif ERROR and hasattr(it, 'throw'): rv = it.throw(*ERROR.pop()) else: rv = it.next() except: del VALUE[:] ERROR.append(sys.exc_info()) if ERROR[-1][0] is StopIteration: ERROR.pop() # not really an error RETURN() else: del VALUE[:] if rv is Pause: break elif hasattr(rv, 'next'): CALL(rv); continue elif isinstance(rv, Return): rv = rv.value VALUE.append(rv) if len(STACK)==1: break RETURN() if STACK and not ERROR and not ctrl.reads: ctrl.current_listener.dirty() # re-run if still running return resume() return _step def do_run(self): ctrl = trellis.ctrl ctrl.current_listener = self try: try: self._step() # process writes as if from a non-rule perspective writes = ctrl.writes has_run = ctrl.has_run.get while writes: subject, writer = writes.popitem() for dependent in subject.iter_listeners(): if has_run(dependent) is not self: if dependent.dirty(): ctrl.schedule(dependent) # process reads in normal fashion ctrl._process_reads(self) except: ctrl.reads.clear() ctrl.writes.clear() raise finally: ctrl.current_listener = None Pause = symbols.Symbol('Pause', __name__) decorators.struct() def Return(value): """Wrapper for yielding a value from a task""" return value, def resume(): """Get the result of a nested task invocation (needed for Python<2.5)""" c = trellis.ctrl.current_listener if not isinstance(c, TaskCell): raise RuntimeError("resume() must be called from an @activity.task") elif c._result: return c._result[0] elif c._error: e = c._error.pop() try: raise e[0], e[1], e[2] finally: del e def task(rule=None, optional=False): """Define a task cell attribute""" return trellis._build_descriptor( rule=rule, factory=TaskCell.from_attr, optional=optional ) PKÆ¢œ8Ü(àWXWXpeak/events/activity.pyc;ò š¯ Hc @sºdklZdklZlZdklZlZlZdk l Z l Z dk Z dk Z dkZdkZddddd d d d d ddg ZyeWn ej odklZnXdefd„ƒYZedƒZee ƒZdeieifd„ƒYZd efd„ƒYZd efd„ƒYZdeieifd„ƒYZdeiei fd„ƒYZ!ei"d e#ƒZ$ei%ƒd„Z&d„Z'e(e)d„Z*dS((scontext(strellissstm(saddonss decoratorsssymbols(sMinsMaxNsTimesEPOCHsNOT_YETs EventLoops WXEventLoopsTwistedEventLoopstasksresumesPausesReturnsTaskCell(sSets_TimercBsntZdZdZd„Zd„Zd„Zd„Zd„Zd„Z d„Z d „Z d „Z d „Z RS( s#Value representing a moment in times_whencCs ||_dS(N(s_whensself(sselfs_when((s-build\bdist.win32\egg\peak\events\activity.pys__init__/scCs*|tjo|Snt|i|ƒSdS(s=Get a timer that's offset from this one by `interval` secondsN(sselfsNOT_YETs_Timers_whensinterval(sselfsinterval((s-build\bdist.win32\egg\peak\events\activity.pys __getitem__2s cCs:t|tƒ otd|fƒ‚n|i|iSdS(s.Get the interval in seconds between two timerssCan't subtract %r from timerN(s isinstancesothers_Timers TypeErrorsselfs_when(sselfsother((s-build\bdist.win32\egg\peak\events\activity.pys__sub__7scCs-t|tƒ otSn|i|ijSdS(N(s isinstancesothers_TimersFalsesselfs_when(sselfsother((s-build\bdist.win32\egg\peak\events\activity.pys__eq__=scCs||j SdS(N(sselfsother(sselfsother((s-build\bdist.win32\egg\peak\events\activity.pys__ne__BscCs||j SdS(N(sselfsother(sselfsother((s-build\bdist.win32\egg\peak\events\activity.pys__ge__EscCsti|ƒSdS(N(sTimesreachedsself(sself((s-build\bdist.win32\egg\peak\events\activity.pys __nonzero__HscCs/t|tƒ o t‚n|i|ijSdS(N(s isinstancesothers_Timers TypeErrorsselfs_when(sselfsother((s-build\bdist.win32\egg\peak\events\activity.pys__lt__Ks cCst|iƒSdS(N(shashsselfs_when(sself((s-build\bdist.win32\egg\peak\events\activity.pys__hash__PscCs$|ot|tdƒSntSdS(s7Keep track of the moment when `flag` first becomes trueiN(sflagsminsselfsTimesNOT_YET(sselfsflag((s-build\bdist.win32\egg\peak\events\activity.pys begins_withSs(s__name__s __module__s__doc__s __slots__s__init__s __getitem__s__sub__s__eq__s__ne__s__ge__s __nonzero__s__lt__s__hash__s begins_with(((s-build\bdist.win32\egg\peak\events\activity.pys_Timer*s          icBstZdZeidedeƒeiedeƒZ ei d„ƒZ eZ Z d„Zd„Zeieiƒd„Zd„Zd d „Zeieiƒd „Zeieiƒd „Zeieiƒd „Zd„Zd„Zd„Zd„ZRS(sRun an application event loopsrunningsstop_requestedswritablecCs titƒS(N(sTimesnext_event_timesTrue(sself((s-build\bdist.win32\egg\peak\events\activity.pys„scCsƒ|i p td‚tii p td‚|id„ƒt|_t |_z"t i ƒ|i ƒ|i ƒWd|iƒXdS(s3Loop updating the time and invoking requested callssEventLoop is already runnings"Event loop can't be run atomicallycCstS(N(sNone(((s-build\bdist.win32\egg\peak\events\activity.pysŒsN(sselfsrunningsAssertionErrorstrellissctrlsactivescallsFalsesstop_requestedsTruesTimesticks_loopsstops _tearDown(sself((s-build\bdist.win32\egg\peak\events\activity.pysrunˆs    cCs!|ip td‚t|_dS(s+Stop the event loop at the next opportunitysEventLoop isn't runningN(sselfsrunningsAssertionErrorsTruesstop_requested(sself((s-build\bdist.win32\egg\peak\events\activity.pysstop–scOs\|ii|||fƒ|i o|iƒt|_nt i |ii ƒ|i ƒdS(s0Call `func(*args, **kw)` at the next opportunityN( sselfs _call_queuesappendsfuncsargsskws initializeds_setupsTruestrellisson_undospops_callback_if_needed(sselfsfuncsargsskw((s-build\bdist.win32\egg\peak\events\activity.pyscallœs   cCs|idƒdS(s#Execute up to a single pending calliN(sselfsflush(sself((s-build\bdist.win32\egg\peak\events\activity.pyspoll¥sicCs‹tii p td‚|i|ƒ}x$|D]\}}}|||Žq.W|i ƒt i ot iƒnt i|ipdƒdS(s9Execute the specified number of pending calls (0 for all)s"Event loop can't be run atomicallyiN(strellissctrlsactivesAssertionErrorsselfs _split_queuescountsqueuesfsargsskws_callback_if_neededsTimes auto_updatesticksadvances _next_time(sselfscountsfsargssqueueskw((s-build\bdist.win32\egg\peak\events\activity.pysflush©s  cCs6|io|i o|i|iƒt|_ndS(N(sselfs _call_queues_callback_actives_arrange_callbacks _callbacksTrue(sself((s-build\bdist.win32\egg\peak\events\activity.pys_callback_if_needed¶scCsP|i}|p t|ƒ}|o%|| ||f\}|_|SnfSdS(N(sselfs _call_queuesqueuescountslenshead(sselfscountsqueueshead((s-build\bdist.win32\egg\peak\events\activity.pys _split_queue¼s  cCst|_t|_dS(N(sFalsesselfsrunningsstop_requested(sself((s-build\bdist.win32\egg\peak\events\activity.pys _tearDownÅs cCst|_|idƒdS(Ni(sFalsesselfs_callback_activesflush(sself((s-build\bdist.win32\egg\peak\events\activity.pys _callbackÉs cCs>|i}x.|p|io|i o|idƒq WdS(s1Subclasses should invoke their external loop hereiN(sselfs _call_queuesqueues _next_timesstop_requestedsflush(sselfsqueue((s-build\bdist.win32\egg\peak\events\activity.pys_loopÎs  cCsdS(sSubclasses should import/setup their external loop here Note: must be inherently thread-safe, or else use a cell attribute in order to benefit from locking. This method is called atomically, but you should not log any undo actions.N((sself((s-build\bdist.win32\egg\peak\events\activity.pys_setupÔscCsdS(sSubclasses should register `func` to be called by external loop Note: Must be safe to call this from a 'foreign' thread.N((sselfsfunc((s-build\bdist.win32\egg\peak\events\activity.pys_arrange_callbackÛs(s__name__s __module__s__doc__strellissattrssFalsesmakeslistsTrues _call_queuescomputes _next_times_callback_actives initializedsrunsstops decoratorssdecoratesmodifierscallspollsflushs_callback_if_neededs _split_queues _tearDowns _callbacks_loops_setups_arrange_callback(((s-build\bdist.win32\egg\peak\events\activity.pys EventLoop|s,              cBsStZdZeieƒeZZe i ƒd„Z d„Z d„Z d„ZRS(s!Twisted version of the event loopcCsž|iotiog|itj oS|io |iiƒo|ii|iƒqw|i i |iti ƒ|_q{n|i o|i i ƒqšndS(N(sselfsrunningsTimes auto_updates _next_timesNones _delayed_callsactivesresetsreactors callLatersticksstop_requestedsstop(sself((s-build\bdist.win32\egg\peak\events\activity.pys_tickerþs  & cCs|iiƒdS(s3Loop updating the time and invoking requested callsN(sselfsreactorsrun(sself((s-build\bdist.win32\egg\peak\events\activity.pys_loop scCs|iid|ƒdS(Ni(sselfsreactors callLatersfunc(sselfsfunc((s-build\bdist.win32\egg\peak\events\activity.pys_arrange_callbackscCsdkl}||_dS(N(sreactor(stwisted.internetsreactorsself(sselfsreactor((s-build\bdist.win32\egg\peak\events\activity.pys_setups (s__name__s __module__s__doc__scontextsreplacess EventLoopsNonesreactors _delayed_callstrellissperforms_tickers_loops_arrange_callbacks_setup(((s-build\bdist.win32\egg\peak\events\activity.pysTwistedEventLoop÷s      cBsOtZdZeieƒeZei ƒd„Z d„Z d„Z d„Z RS(s"wxPython version of the event loop This isn't adequately tested; the wx event loop is completely hosed when it comes to running without any windows, so it's basically impossible to unit test without mocking 'wx' (which I haven't tried to do. Use at your own risk. :( cCsr|iodtio5|itj o!|ii|idtiƒqIn|i o|ii ƒi ƒqnndS(Niè( sselfsrunningsTimes auto_updates _next_timesNoneswxs FutureCallsticksstop_requestedsGetApps ExitMainLoop(sself((s-build\bdist.win32\egg\peak\events\activity.pys_ticker,s   % cCsi|iiƒ}|tj p td‚x<|i o0|iƒ|io|i ƒq)|i ƒq)WdS(s3Loop updating the time and invoking requested callsswx.App not createdN( sselfswxsGetAppsappsNonesAssertionErrorsstop_requestedsMainLoopsExitOnFrameDeletesstopsProcessPendingEvents(sselfsapp((s-build\bdist.win32\egg\peak\events\activity.pys_loop4s   cCs|ii|ƒdS(s0Call `func(*args, **kw)` at the next opportunityN(sselfswxs CallAftersfunc(sselfsfunc((s-build\bdist.win32\egg\peak\events\activity.pys_arrange_callback?scCsdk}||_dS(N(swxsself(sselfswx((s-build\bdist.win32\egg\peak\events\activity.pys_setupCs (s__name__s __module__s__doc__scontextsreplacess EventLoopsNoneswxstrellissperforms_tickers_loops_arrange_callbacks_setup(((s-build\bdist.win32\egg\peak\events\activity.pys WXEventLoop s     cBsétZdZeiZeieƒZ ei d„deƒZ ei e i ƒZeiƒd„Zd„Zeieiƒd„Zd„Zd„Zd„Zd „ZeieƒZeid eiƒd „Zed „Zd „ZRS(s!Manage current time and intervalscCstgS(N(sMax(sself((s-build\bdist.win32\egg\peak\events\activity.pysNsswritablecCsr|i}xb|i|djoMti|ƒ}titi ||ƒ||i jot |i |_ q q WdS(Ni( sselfs _schedulesschedules_ticksheapqsheappopskeystrellisson_undosheappushs_eventssTruesvalue(sselfsscheduleskey((s-build\bdist.win32\egg\peak\events\activity.pys_updatedRs cCs@|i}|i|jp#tiitj o|i |ƒi SdS(N( stimers_whenswhensselfs_nowstrellissctrlscurrent_listenersNones _event_forsvalue(sselfstimerswhen((s-build\bdist.win32\egg\peak\events\activity.pysreachedZs cCs‹|ii|ƒ}|tjodti|i|ƒt i t ƒ|i|<}t i |ii |tƒt it i|ƒdƒn|SdS(Ns _schedule(sselfs_eventssgetswhensesNonesheapqsheappushs _schedulestrellissValuesFalseson_undospopschangedsCells(sselfswhense((s-build\bdist.win32\egg\peak\events\activity.pys _event_forbs cCst|i|ƒSdS(s<Return a timer that's the given offset from the current timeN(s_Timersselfs_nowsinterval(sselfsinterval((s-build\bdist.win32\egg\peak\events\activity.pys __getitem__lscCs|i|i|ƒdS(s.Advance the current time by the given intervalN(sselfs_sets_nowsinterval(sselfsinterval((s-build\bdist.win32\egg\peak\events\activity.pysadvancerscCs|i|iƒƒdS(s,Update current time to match ``time.time()``N(sselfs_setstime(sself((s-build\bdist.win32\egg\peak\events\activity.pystickvscCs ti|d|ƒ||_dS(Ns_now(strelliss change_attrsselfswhens_tick(sselfswhen((s-build\bdist.win32\egg\peak\events\activity.pys_setzss initiallycCs:|io%|iƒ}|_tiƒ|Sn|iSdS(N(sselfs auto_updatestimesticks_nowstrellisspolls_tick(sselfstick((s-build\bdist.win32\egg\peak\events\activity.pys_tick€s   cCsF|i}|id}|tjotSn|o ||Sn|SdS(sàThe time of the next event to occur, or ``None`` if none scheduled If `relative` is True, returns the number of seconds until the event; otherwise, returns the absolute ``time.time()`` of the event. iN(sselfs_ticksnows _scheduleswhensMaxsNonesrelative(sselfsrelativeswhensnow((s-build\bdist.win32\egg\peak\events\activity.pysnext_event_time‡s    cCstiƒSdS(N(stime(sself((s-build\bdist.win32\egg\peak\events\activity.pystime•s(s__name__s __module__s__doc__sEPOCHs_whens_nowstrellissattrsTrues auto_updatesmakes _schedulesweakrefsWeakValueDictionarys_eventssmaintains_updatedsreacheds decoratorssdecoratesmodifiers _event_fors __getitem__sadvancesticks_sets_ticksFalsesnext_event_timestime(((s-build\bdist.win32\egg\peak\events\activity.pysTimeIs&           cBsftZdZddddddddfZd „Zd „Zeieƒd „Z d „Z d „Z RS(s(Cell that manages a generator-based tasks_results_errors_steps next_subjectslayers_loops _scheduleds __weakref__cCsP|i|ƒ|_d|_t|_tiƒ|_ t |_ t i |iƒdS(Ni(sselfs_steppersfuncs_stepslayersNones next_subjects EventLoopsgets_loopsFalses _scheduledstrelliss atomicallysdirty(sselfsfunc((s-build\bdist.win32\egg\peak\events\activity.pys__init__£s    cCsb|i oOti|dtƒti|iiti|i ƒtiti|dt ƒnt SdS(Ns _scheduled( sselfs _scheduledstrelliss change_attrsTrues on_commits_loopscalls atomicallysdo_runsFalse(sself((s-build\bdist.win32\egg\peak\events\activity.pysdirty«s  cCs||ƒSdS(N(sclssrule(sclssrulesvaluesdiscrete((s-build\bdist.win32\egg\peak\events\activity.pys from_attr³sc sdg‰|_g‰|_|ƒg‰ˆi‰ˆi ‰t i ‰‡‡‡‡‡‡d†}|SdS(NcsˆxOˆoGyxˆd}ˆo t|dƒo|iˆdƒ}n=ˆo t|dƒo|iˆiƒŒ}n |i ƒ}WnHˆ2ˆi t i ƒƒˆddt joˆiƒnˆƒqXˆ2|tjoPn?t|dƒoˆ|ƒqnt|tƒo |i}nˆi |ƒtˆƒdjoPnˆƒqWˆoˆ oˆi oˆiiƒntƒSdS(Niÿÿÿÿssendisthrowsnexti(sSTACKsitsVALUEshasattrssendsrvsERRORsthrowspopsnextsappendssyssexc_infos StopIterationsRETURNsPausesCALLs isinstancesReturnsvalueslensctrlsreadsscurrent_listenersdirtysresume(srvsit(sRETURNsctrlsVALUEsCALLsERRORsSTACK(s-build\bdist.win32\egg\peak\events\activity.pys_stepËs:      (sVALUEsselfs_resultsERRORs_errorsfuncsSTACKsappendsCALLspopsRETURNstrellissctrls_step( sselfsfuncsRETURNsctrls_stepsVALUEsCALLsERRORsSTACK((sRETURNsctrlsVALUEsCALLsERRORsSTACKs-build\bdist.win32\egg\peak\events\activity.pys_stepperÄs      cCsëti}||_zÈy|iƒ|i}|ii}xj|ob|iƒ\}}xI|i ƒD];}||ƒ|j o"|i ƒo|i|ƒq›q`q`Wq:W|i|ƒWn$|iiƒ|iiƒ‚nXWdt|_XdS(N(strellissctrlsselfscurrent_listeners_stepswritesshas_runsgetspopitemssubjectswritersiter_listenerss dependentsdirtysschedules_process_readssreadssclearsNone(sselfsctrls dependentswritershas_runswritesssubject((s-build\bdist.win32\egg\peak\events\activity.pysdo_runís,          ( s__name__s __module__s__doc__s __slots__s__init__sdirtys decoratorssdecorates classmethods from_attrs_steppersdo_run(((s-build\bdist.win32\egg\peak\events\activity.pysTaskCell›s      )cCs |fSdS(s(Wrapper for yielding a value from a taskN(svalue(svalue((s-build\bdist.win32\egg\peak\events\activity.pysReturn scCsŠtii}t|tƒ otdƒ‚nZ|io|idSnA|io6|ii ƒ}z|d|d|d‚Wd~XndS(sBGet the result of a nested task invocation (needed for Python<2.5)s.resume() must be called from an @activity.taskiiiN( strellissctrlscurrent_listenerscs isinstancesTaskCells RuntimeErrors_results_errorspopse(scse((s-build\bdist.win32\egg\peak\events\activity.pysresumes   cCs#tid|dtid|ƒSdS(sDefine a task cell attributesrulesfactorysoptionalN(strelliss_build_descriptorsrulesTaskCells from_attrsoptional(srulesoptional((s-build\bdist.win32\egg\peak\events\activity.pystask$s(+speakscontexts peak.eventsstrellissstms peak.utilsaddonss decoratorsssymbolsspeak.util.extremessMinsMaxsheapqsweakrefstimessyss__all__ssets NameErrorssetssSetsobjects_TimersEPOCHsNOT_YETs ComponentsServices EventLoopsTwistedEventLoops WXEventLoopsTimes AbstractCellsAbstractListenersTaskCellsSymbols__name__sPausesstructsReturnsresumesNonesFalsestask(sheapqssetsMins_Timers EventLoops WXEventLoopssymbolssPausesReturns__all__sTwistedEventLoopsMaxs decoratorssresumessyssEPOCHsTimestasksNOT_YETsstmsTaskCellsweakrefscontextstimestrellissaddons((s-build\bdist.win32\egg\peak\events\activity.pys?s, $'/  "{))Rl  PKÆ¢œ8@fTФV¤Vpeak/events/activity.pyo;ò š¯ Hc @sºdklZdklZlZdklZlZlZdk l Z l Z dk Z dk Z dkZdkZddddd d d d d ddg ZyeWn ej odklZnXdefd„ƒYZedƒZee ƒZdeieifd„ƒYZd efd„ƒYZd efd„ƒYZdeieifd„ƒYZdeiei fd„ƒYZ!ei"d e#ƒZ$ei%ƒd„Z&d„Z'e(e)d„Z*dS((scontext(strellissstm(saddonss decoratorsssymbols(sMinsMaxNsTimesEPOCHsNOT_YETs EventLoops WXEventLoopsTwistedEventLoopstasksresumesPausesReturnsTaskCell(sSets_TimercBsntZdZdZd„Zd„Zd„Zd„Zd„Zd„Z d„Z d „Z d „Z d „Z RS( s#Value representing a moment in times_whencCs ||_dS(N(s_whensself(sselfs_when((s-build\bdist.win32\egg\peak\events\activity.pys__init__/scCs*|tjo|Snt|i|ƒSdS(s=Get a timer that's offset from this one by `interval` secondsN(sselfsNOT_YETs_Timers_whensinterval(sselfsinterval((s-build\bdist.win32\egg\peak\events\activity.pys __getitem__2s cCs:t|tƒ otd|fƒ‚n|i|iSdS(s.Get the interval in seconds between two timerssCan't subtract %r from timerN(s isinstancesothers_Timers TypeErrorsselfs_when(sselfsother((s-build\bdist.win32\egg\peak\events\activity.pys__sub__7scCs-t|tƒ otSn|i|ijSdS(N(s isinstancesothers_TimersFalsesselfs_when(sselfsother((s-build\bdist.win32\egg\peak\events\activity.pys__eq__=scCs||j SdS(N(sselfsother(sselfsother((s-build\bdist.win32\egg\peak\events\activity.pys__ne__BscCs||j SdS(N(sselfsother(sselfsother((s-build\bdist.win32\egg\peak\events\activity.pys__ge__EscCsti|ƒSdS(N(sTimesreachedsself(sself((s-build\bdist.win32\egg\peak\events\activity.pys __nonzero__HscCs/t|tƒ o t‚n|i|ijSdS(N(s isinstancesothers_Timers TypeErrorsselfs_when(sselfsother((s-build\bdist.win32\egg\peak\events\activity.pys__lt__Ks cCst|iƒSdS(N(shashsselfs_when(sself((s-build\bdist.win32\egg\peak\events\activity.pys__hash__PscCs$|ot|tdƒSntSdS(s7Keep track of the moment when `flag` first becomes trueiN(sflagsminsselfsTimesNOT_YET(sselfsflag((s-build\bdist.win32\egg\peak\events\activity.pys begins_withSs(s__name__s __module__s__doc__s __slots__s__init__s __getitem__s__sub__s__eq__s__ne__s__ge__s __nonzero__s__lt__s__hash__s begins_with(((s-build\bdist.win32\egg\peak\events\activity.pys_Timer*s          icBstZdZeidedeƒeiedeƒZ ei d„ƒZ eZ Z d„Zd„Zeieiƒd„Zd„Zd d „Zeieiƒd „Zeieiƒd „Zeieiƒd „Zd„Zd„Zd„Zd„ZRS(sRun an application event loopsrunningsstop_requestedswritablecCs titƒS(N(sTimesnext_event_timesTrue(sself((s-build\bdist.win32\egg\peak\events\activity.pys„scCsV|id„ƒt|_t|_z"tiƒ|iƒ|i ƒWd|i ƒXdS(s3Loop updating the time and invoking requested callscCstS(N(sNone(((s-build\bdist.win32\egg\peak\events\activity.pysŒsN( sselfscallsFalsesstop_requestedsTruesrunningsTimesticks_loopsstops _tearDown(sself((s-build\bdist.win32\egg\peak\events\activity.pysrunˆs    cCs t|_dS(s+Stop the event loop at the next opportunityN(sTruesselfsstop_requested(sself((s-build\bdist.win32\egg\peak\events\activity.pysstop–scOs\|ii|||fƒ|i o|iƒt|_nt i |ii ƒ|i ƒdS(s0Call `func(*args, **kw)` at the next opportunityN( sselfs _call_queuesappendsfuncsargsskws initializeds_setupsTruestrellisson_undospops_callback_if_needed(sselfsfuncsargsskw((s-build\bdist.win32\egg\peak\events\activity.pyscallœs   cCs|idƒdS(s#Execute up to a single pending calliN(sselfsflush(sself((s-build\bdist.win32\egg\peak\events\activity.pyspoll¥sicCss|i|ƒ}x$|D]\}}}|||ŽqW|iƒti oti ƒnti |i pdƒdS(s9Execute the specified number of pending calls (0 for all)iN( sselfs _split_queuescountsqueuesfsargsskws_callback_if_neededsTimes auto_updatesticksadvances _next_time(sselfscountsfsargssqueueskw((s-build\bdist.win32\egg\peak\events\activity.pysflush©s  cCs6|io|i o|i|iƒt|_ndS(N(sselfs _call_queues_callback_actives_arrange_callbacks _callbacksTrue(sself((s-build\bdist.win32\egg\peak\events\activity.pys_callback_if_needed¶scCsP|i}|p t|ƒ}|o%|| ||f\}|_|SnfSdS(N(sselfs _call_queuesqueuescountslenshead(sselfscountsqueueshead((s-build\bdist.win32\egg\peak\events\activity.pys _split_queue¼s  cCst|_t|_dS(N(sFalsesselfsrunningsstop_requested(sself((s-build\bdist.win32\egg\peak\events\activity.pys _tearDownÅs cCst|_|idƒdS(Ni(sFalsesselfs_callback_activesflush(sself((s-build\bdist.win32\egg\peak\events\activity.pys _callbackÉs cCs>|i}x.|p|io|i o|idƒq WdS(s1Subclasses should invoke their external loop hereiN(sselfs _call_queuesqueues _next_timesstop_requestedsflush(sselfsqueue((s-build\bdist.win32\egg\peak\events\activity.pys_loopÎs  cCsdS(sSubclasses should import/setup their external loop here Note: must be inherently thread-safe, or else use a cell attribute in order to benefit from locking. This method is called atomically, but you should not log any undo actions.N((sself((s-build\bdist.win32\egg\peak\events\activity.pys_setupÔscCsdS(sSubclasses should register `func` to be called by external loop Note: Must be safe to call this from a 'foreign' thread.N((sselfsfunc((s-build\bdist.win32\egg\peak\events\activity.pys_arrange_callbackÛs(s__name__s __module__s__doc__strellissattrssFalsesmakeslistsTrues _call_queuescomputes _next_times_callback_actives initializedsrunsstops decoratorssdecoratesmodifierscallspollsflushs_callback_if_neededs _split_queues _tearDowns _callbacks_loops_setups_arrange_callback(((s-build\bdist.win32\egg\peak\events\activity.pys EventLoop|s,              cBsStZdZeieƒeZZe i ƒd„Z d„Z d„Z d„ZRS(s!Twisted version of the event loopcCsž|iotiog|itj oS|io |iiƒo|ii|iƒqw|i i |iti ƒ|_q{n|i o|i i ƒqšndS(N(sselfsrunningsTimes auto_updates _next_timesNones _delayed_callsactivesresetsreactors callLatersticksstop_requestedsstop(sself((s-build\bdist.win32\egg\peak\events\activity.pys_tickerþs  & cCs|iiƒdS(s3Loop updating the time and invoking requested callsN(sselfsreactorsrun(sself((s-build\bdist.win32\egg\peak\events\activity.pys_loop scCs|iid|ƒdS(Ni(sselfsreactors callLatersfunc(sselfsfunc((s-build\bdist.win32\egg\peak\events\activity.pys_arrange_callbackscCsdkl}||_dS(N(sreactor(stwisted.internetsreactorsself(sselfsreactor((s-build\bdist.win32\egg\peak\events\activity.pys_setups (s__name__s __module__s__doc__scontextsreplacess EventLoopsNonesreactors _delayed_callstrellissperforms_tickers_loops_arrange_callbacks_setup(((s-build\bdist.win32\egg\peak\events\activity.pysTwistedEventLoop÷s      cBsOtZdZeieƒeZei ƒd„Z d„Z d„Z d„Z RS(s"wxPython version of the event loop This isn't adequately tested; the wx event loop is completely hosed when it comes to running without any windows, so it's basically impossible to unit test without mocking 'wx' (which I haven't tried to do. Use at your own risk. :( cCsr|iodtio5|itj o!|ii|idtiƒqIn|i o|ii ƒi ƒqnndS(Niè( sselfsrunningsTimes auto_updates _next_timesNoneswxs FutureCallsticksstop_requestedsGetApps ExitMainLoop(sself((s-build\bdist.win32\egg\peak\events\activity.pys_ticker,s   % cCsR|iiƒ}x<|i o0|iƒ|io|iƒq|iƒqWdS(s3Loop updating the time and invoking requested callsN( sselfswxsGetAppsappsstop_requestedsMainLoopsExitOnFrameDeletesstopsProcessPendingEvents(sselfsapp((s-build\bdist.win32\egg\peak\events\activity.pys_loop4s   cCs|ii|ƒdS(s0Call `func(*args, **kw)` at the next opportunityN(sselfswxs CallAftersfunc(sselfsfunc((s-build\bdist.win32\egg\peak\events\activity.pys_arrange_callback?scCsdk}||_dS(N(swxsself(sselfswx((s-build\bdist.win32\egg\peak\events\activity.pys_setupCs (s__name__s __module__s__doc__scontextsreplacess EventLoopsNoneswxstrellissperforms_tickers_loops_arrange_callbacks_setup(((s-build\bdist.win32\egg\peak\events\activity.pys WXEventLoop s     cBsétZdZeiZeieƒZ ei d„deƒZ ei e i ƒZeiƒd„Zd„Zeieiƒd„Zd„Zd„Zd„Zd „ZeieƒZeid eiƒd „Zed „Zd „ZRS(s!Manage current time and intervalscCstgS(N(sMax(sself((s-build\bdist.win32\egg\peak\events\activity.pysNsswritablecCsr|i}xb|i|djoMti|ƒ}titi ||ƒ||i jot |i |_ q q WdS(Ni( sselfs _schedulesschedules_ticksheapqsheappopskeystrellisson_undosheappushs_eventssTruesvalue(sselfsscheduleskey((s-build\bdist.win32\egg\peak\events\activity.pys_updatedRs cCs@|i}|i|jp#tiitj o|i |ƒi SdS(N( stimers_whenswhensselfs_nowstrellissctrlscurrent_listenersNones _event_forsvalue(sselfstimerswhen((s-build\bdist.win32\egg\peak\events\activity.pysreachedZs cCs‹|ii|ƒ}|tjodti|i|ƒt i t ƒ|i|<}t i |ii |tƒt it i|ƒdƒn|SdS(Ns _schedule(sselfs_eventssgetswhensesNonesheapqsheappushs _schedulestrellissValuesFalseson_undospopschangedsCells(sselfswhense((s-build\bdist.win32\egg\peak\events\activity.pys _event_forbs cCst|i|ƒSdS(s<Return a timer that's the given offset from the current timeN(s_Timersselfs_nowsinterval(sselfsinterval((s-build\bdist.win32\egg\peak\events\activity.pys __getitem__lscCs|i|i|ƒdS(s.Advance the current time by the given intervalN(sselfs_sets_nowsinterval(sselfsinterval((s-build\bdist.win32\egg\peak\events\activity.pysadvancerscCs|i|iƒƒdS(s,Update current time to match ``time.time()``N(sselfs_setstime(sself((s-build\bdist.win32\egg\peak\events\activity.pystickvscCs ti|d|ƒ||_dS(Ns_now(strelliss change_attrsselfswhens_tick(sselfswhen((s-build\bdist.win32\egg\peak\events\activity.pys_setzss initiallycCs:|io%|iƒ}|_tiƒ|Sn|iSdS(N(sselfs auto_updatestimesticks_nowstrellisspolls_tick(sselfstick((s-build\bdist.win32\egg\peak\events\activity.pys_tick€s   cCsF|i}|id}|tjotSn|o ||Sn|SdS(sàThe time of the next event to occur, or ``None`` if none scheduled If `relative` is True, returns the number of seconds until the event; otherwise, returns the absolute ``time.time()`` of the event. iN(sselfs_ticksnows _scheduleswhensMaxsNonesrelative(sselfsrelativeswhensnow((s-build\bdist.win32\egg\peak\events\activity.pysnext_event_time‡s    cCstiƒSdS(N(stime(sself((s-build\bdist.win32\egg\peak\events\activity.pystime•s(s__name__s __module__s__doc__sEPOCHs_whens_nowstrellissattrsTrues auto_updatesmakes _schedulesweakrefsWeakValueDictionarys_eventssmaintains_updatedsreacheds decoratorssdecoratesmodifiers _event_fors __getitem__sadvancesticks_sets_ticksFalsesnext_event_timestime(((s-build\bdist.win32\egg\peak\events\activity.pysTimeIs&           cBsftZdZddddddddfZd „Zd „Zeieƒd „Z d „Z d „Z RS(s(Cell that manages a generator-based tasks_results_errors_steps next_subjectslayers_loops _scheduleds __weakref__cCsP|i|ƒ|_d|_t|_tiƒ|_ t |_ t i |iƒdS(Ni(sselfs_steppersfuncs_stepslayersNones next_subjects EventLoopsgets_loopsFalses _scheduledstrelliss atomicallysdirty(sselfsfunc((s-build\bdist.win32\egg\peak\events\activity.pys__init__£s    cCsb|i oOti|dtƒti|iiti|i ƒtiti|dt ƒnt SdS(Ns _scheduled( sselfs _scheduledstrelliss change_attrsTrues on_commits_loopscalls atomicallysdo_runsFalse(sself((s-build\bdist.win32\egg\peak\events\activity.pysdirty«s  cCs||ƒSdS(N(sclssrule(sclssrulesvaluesdiscrete((s-build\bdist.win32\egg\peak\events\activity.pys from_attr³sc sdg‰|_g‰|_|ƒg‰ˆi‰ˆi ‰t i ‰‡‡‡‡‡‡d†}|SdS(NcsˆxOˆoGyxˆd}ˆo t|dƒo|iˆdƒ}n=ˆo t|dƒo|iˆiƒŒ}n |i ƒ}WnHˆ2ˆi t i ƒƒˆddt joˆiƒnˆƒqXˆ2|tjoPn?t|dƒoˆ|ƒqnt|tƒo |i}nˆi |ƒtˆƒdjoPnˆƒqWˆoˆ oˆi oˆiiƒntƒSdS(Niÿÿÿÿssendisthrowsnexti(sSTACKsitsVALUEshasattrssendsrvsERRORsthrowspopsnextsappendssyssexc_infos StopIterationsRETURNsPausesCALLs isinstancesReturnsvalueslensctrlsreadsscurrent_listenersdirtysresume(srvsit(sRETURNsctrlsVALUEsCALLsERRORsSTACK(s-build\bdist.win32\egg\peak\events\activity.pys_stepËs:      (sVALUEsselfs_resultsERRORs_errorsfuncsSTACKsappendsCALLspopsRETURNstrellissctrls_step( sselfsfuncsRETURNsctrls_stepsVALUEsCALLsERRORsSTACK((sRETURNsctrlsVALUEsCALLsERRORsSTACKs-build\bdist.win32\egg\peak\events\activity.pys_stepperÄs      cCsëti}||_zÈy|iƒ|i}|ii}xj|ob|iƒ\}}xI|i ƒD];}||ƒ|j o"|i ƒo|i|ƒq›q`q`Wq:W|i|ƒWn$|iiƒ|iiƒ‚nXWdt|_XdS(N(strellissctrlsselfscurrent_listeners_stepswritesshas_runsgetspopitemssubjectswritersiter_listenerss dependentsdirtysschedules_process_readssreadssclearsNone(sselfsctrls dependentswritershas_runswritesssubject((s-build\bdist.win32\egg\peak\events\activity.pysdo_runís,          ( s__name__s __module__s__doc__s __slots__s__init__sdirtys decoratorssdecorates classmethods from_attrs_steppersdo_run(((s-build\bdist.win32\egg\peak\events\activity.pysTaskCell›s      )cCs |fSdS(s(Wrapper for yielding a value from a taskN(svalue(svalue((s-build\bdist.win32\egg\peak\events\activity.pysReturn scCsŠtii}t|tƒ otdƒ‚nZ|io|idSnA|io6|ii ƒ}z|d|d|d‚Wd~XndS(sBGet the result of a nested task invocation (needed for Python<2.5)s.resume() must be called from an @activity.taskiiiN( strellissctrlscurrent_listenerscs isinstancesTaskCells RuntimeErrors_results_errorspopse(scse((s-build\bdist.win32\egg\peak\events\activity.pysresumes   cCs#tid|dtid|ƒSdS(sDefine a task cell attributesrulesfactorysoptionalN(strelliss_build_descriptorsrulesTaskCells from_attrsoptional(srulesoptional((s-build\bdist.win32\egg\peak\events\activity.pystask$s(+speakscontexts peak.eventsstrellissstms peak.utilsaddonss decoratorsssymbolsspeak.util.extremessMinsMaxsheapqsweakrefstimessyss__all__ssets NameErrorssetssSetsobjects_TimersEPOCHsNOT_YETs ComponentsServices EventLoopsTwistedEventLoops WXEventLoopsTimes AbstractCellsAbstractListenersTaskCellsSymbols__name__sPausesstructsReturnsresumesNonesFalsestask(sheapqssetsMins_Timers EventLoops WXEventLoopssymbolssPausesReturns__all__sTwistedEventLoopsMaxs decoratorssresumessyssEPOCHsTimestasksNOT_YETsstmsTaskCellsweakrefscontextstimestrellissaddons((s-build\bdist.win32\egg\peak\events\activity.pys?s, $'/  "{))Rl  PK3Z•8º?peak/events/collections.pyimport trellis, bisect from peak.util import decorators from trellis import set from new import instancemethod __all__ = [ 'SortedSet', 'SubSet', 'Observing', ] class SubSet(trellis.Set): """Set that's constrained to be a subset of another set""" base = trellis.make(trellis.Set, writable=True) trellis.compute() def added(self): base = self.base return set([item for item in self._added if item in base]) trellis.compute() def removed(self): base = self.base if self.base.removed: # XXX need to filter this by self._data somehow return set(self._removed) | set(self.base.removed) else: return self._removed class Observing(trellis.Component): """Monitor a set of keys for changes""" lookup_func = trellis.attr(lambda x:x) keys = trellis.make(trellis.Set) trellis.maintain() def _watching(self): cells = self._watching or {} for k in self.keys.removed: if k in cells: trellis.on_undo(cells.__setitem__, k, cells[k]) del cells[k] trellis.mark_dirty() lookup = self.lookup_func for k in self.keys.added: trellis.on_undo(cells.pop, k, None) cells[k] = trellis.Cell(instancemethod(lookup, k, type(k))) trellis.mark_dirty() return cells trellis.maintain(initially=({}, {})) def watched_values(self): forget, old = self.watched_values lookup = self.lookup_func return old, dict([(k, v.value) for k,v in self._watching.iteritems()]) trellis.maintain(resetting_to={}) def changes(self): old, current = self.watched_values changes = {} if old!=current: for k,v in current.iteritems(): if k not in old or v!=old[k]: changes[k] = v, old.get(k, v) return changes class SortedSet(trellis.Component): """Represent a set as a list sorted by a key""" trellis.attrs( sort_key = lambda x:x, # sort on the object reverse = False, items = None, old_key = None, old_reverse = None ) data = trellis.make(trellis.Set, writable=True) changes = trellis.attr(resetting_to=[]) def __getitem__(self, key): if self.reverse: key = -(key+1) return self.items[int(key)][1] def __len__(self): return len(self.items) trellis.maintain() def state(self): key, reverse = self.sort_key, self.reverse data = self.items if key != self.old_key or reverse != self.old_reverse: if data is None or key != self.old_key: data = [(key(ob),ob) for ob in self.data] data.sort() self.items = data size = len(self.data) self.changes = [(0, size, size)] self.old_key = key self.old_reverse = reverse else: self.changes = self.compute_changes(key, data, reverse) def __repr__(self): return repr(list(self)) def compute_changes(self, key, items, reverse): changes = [ (key(ob), "+", ob) for ob in self.data.added] + [ (key(ob), "-", ob) for ob in self.data.removed ] changes.sort() changes.reverse() lo = 0 hi = old_size = len(items) regions = [] for k, op, ob in changes: ind = (k, ob) if lo=ind: pos = hi-1 # shortcut else: pos = bisect.bisect_left(items, ind, lo, hi) if op=='-': del items[pos] if regions and regions[-1][0]==pos+1: regions[-1] = (pos, regions[-1][1], regions[-1][2]) else: regions.append((pos, pos+1, 0)) else: items.insert(pos, ind) if regions and regions[-1][0]==pos: regions[-1] = (pos, regions[-1][1], regions[-1][2]+1) else: regions.append((pos, pos, 1)) hi=pos if reverse: return [(old_size-e, old_size-s, sz) for (s,e,sz) in regions[::-1]] return regions PKÆ¢œ8n]‡sttpeak/events/collections.pyc;ò ° Hc@s—dkZdkZdklZdklZdklZdddgZdeifd„ƒYZ dei fd„ƒYZ dei fd „ƒYZ dS( N(s decorators(sset(sinstancemethods SortedSetsSubSets ObservingcBsLtZdZeieideƒZeiƒd„Z eiƒd„Z RS(s4Set that's constrained to be a subset of another setswritablecCsL|i}tgi}|iD]!}||jo||ƒqq~ƒSdS(N(sselfsbasessetsappends_[1]s_addedsitem(sselfs_[1]sitemsbase((s0build\bdist.win32\egg\peak\events\collections.pysaddeds cCsB|i}|iio!t|iƒt|iiƒBSn|iSdS(N(sselfsbasesremovedssets_removed(sselfsbase((s0build\bdist.win32\egg\peak\events\collections.pysremoveds  !( s__name__s __module__s__doc__strellissmakesSetsTruesbasescomputesaddedsremoved(((s0build\bdist.win32\egg\peak\events\collections.pysSubSet s    cBs}tZdZeid„ƒZeieiƒZei ƒd„Z ei dhhfƒd„Z ei dhƒd„Z RS(s!Monitor a set of keys for changescCs|S(N(sx(sx((s0build\bdist.win32\egg\peak\events\collections.pys-scCsÐ|iph}xP|iiD]B}||jo/ti|i|||ƒ||=ti ƒqqW|i }xY|ii D]K}ti|i |tƒtit||t|ƒƒƒ||Wssreversesitemssold_keys old_reverseswritables resetting_tocCs2|io|d }n|it|ƒdSdS(Ni(sselfsreverseskeysitemssint(sselfskey((s0build\bdist.win32\egg\peak\events\collections.pys __getitem__`s cCst|iƒSdS(N(slensselfsitems(sself((s0build\bdist.win32\egg\peak\events\collections.pys__len__escCs|i|if\}}|i}||ijp ||ijo¤|tjp ||ijoMgi }|iD]}|||ƒ|fƒqo~}|i ƒ||_nt |iƒ}d||fg|_||_||_n|i|||ƒ|_dS(Ni(sselfssort_keysreverseskeysitemssdatasold_keys old_reversesNonesappends_[1]sobssortslenssizeschangesscompute_changes(sselfsreversesobs_[1]skeysdatassize((s0build\bdist.win32\egg\peak\events\collections.pysstateis  6    cCstt|ƒƒSdS(N(sreprslistsself(sself((s0build\bdist.win32\egg\peak\events\collections.pys__repr__xscCscgi} |iiD]}| ||ƒd|fƒq~ gi} |iiD]}| ||ƒd|fƒqM~ }|i ƒ|i ƒd} t |ƒ} }g}x[|D]S\}}}||f} | | jo|| dd| jo| d}nti|| | | ƒ}|djol||=|o|dd|djo'||dd|ddf|d-scCsÐ|iph}xP|iiD]B}||jo/ti|i|||ƒ||=ti ƒqqW|i }xY|ii D]K}ti|i |tƒtit||t|ƒƒƒ||Wssreversesitemssold_keys old_reverseswritables resetting_tocCs2|io|d }n|it|ƒdSdS(Ni(sselfsreverseskeysitemssint(sselfskey((s0build\bdist.win32\egg\peak\events\collections.pys __getitem__`s cCst|iƒSdS(N(slensselfsitems(sself((s0build\bdist.win32\egg\peak\events\collections.pys__len__escCs|i|if\}}|i}||ijp ||ijo¤|tjp ||ijoMgi }|iD]}|||ƒ|fƒqo~}|i ƒ||_nt |iƒ}d||fg|_||_||_n|i|||ƒ|_dS(Ni(sselfssort_keysreverseskeysitemssdatasold_keys old_reversesNonesappends_[1]sobssortslenssizeschangesscompute_changes(sselfsreversesobs_[1]skeysdatassize((s0build\bdist.win32\egg\peak\events\collections.pysstateis  6    cCstt|ƒƒSdS(N(sreprslistsself(sself((s0build\bdist.win32\egg\peak\events\collections.pys__repr__xscCscgi} |iiD]}| ||ƒd|fƒq~ gi} |iiD]}| ||ƒd|fƒqM~ }|i ƒ|i ƒd} t |ƒ} }g}x[|D]S\}}}||f} | | jo|| dd| jo| d}nti|| | | ƒ}|djol||=|o|dd|djo'||dd|ddf|dkK K peak/events/sa_support.pyc;ò bSHc@srdklZlZlZdklZlZlZlZl Z dkl Z dk l Z defd„ƒYZ dS((s get_attributes set_attributes ClassManager(sCellssEffectorsNO_VALUEs CellValuess CellFactories(s Performer(sinstancemethods SAInstrumentcBs)tZdZd„Zd„Zd„ZRS(s4Adapter for SQLAlchemy to talk to Trellis componentscCs1|t|iƒjot|i||ƒndS(N(skeys CellFactoriessselfsclass_ssetattrsinst(sselfskeysinst((s/build\bdist.win32\egg\peak\events\sa_support.pysinstall_descriptor scCs.|t|iƒjot|i|ƒndS(N(skeys CellFactoriessselfsclass_sdelattr(sselfskey((s/build\bdist.win32\egg\peak\events\sa_support.pysuninstall_descriptor sc sætˆƒ‰ˆ oµˆi} t| ƒi}t| ƒ} t t ˆƒ}g‰xT|D]L}|| joqTnˆi|ƒtt ||ƒ||tƒƒˆ|x7ˆD]/}ˆ|iotˆ|ˆ|iƒqqWdS(N(sattrssattrscellsswas_sets set_attributesinstancesvalue(sattr(sinstancescellssattrs(s/build\bdist.win32\egg\peak\events\sa_support.pyssetter s(sCellssinstancescellss __class__sclss CellValuessgets get_values CellFactoriess factoriessinstancemethods get_attributesgettersattrssselfsattrsappendsEffectorsNO_VALUEssetters Performers _observerssupers SAInstruments install_statesstate( sselfsinstancesstatesattrssetterscellss get_valuesattrssgetters factoriesscls((sinstancescellssattrss/build\bdist.win32\egg\peak\events\sa_support.pys install_states      )(s__name__s __module__s__doc__sinstall_descriptorsuninstall_descriptors install_state(((s/build\bdist.win32\egg\peak\events\sa_support.pys SAInstruments   N(ssqlalchemy.orm.attributess get_attributes set_attributes ClassManagerstrellissCellssEffectorsNO_VALUEs CellValuess CellFactoriess Performersnewsinstancemethods SAInstrument( sEffectors Performers CellFactoriessCellss get_attributesinstancemethods set_attributes ClassManagersNO_VALUEs CellValuess SAInstrument((s/build\bdist.win32\egg\peak\events\sa_support.pys?s%  PKÆ¢œ8Œ>kK K peak/events/sa_support.pyo;ò bSHc@srdklZlZlZdklZlZlZlZl Z dkl Z dk l Z defd„ƒYZ dS((s get_attributes set_attributes ClassManager(sCellssEffectorsNO_VALUEs CellValuess CellFactories(s Performer(sinstancemethods SAInstrumentcBs)tZdZd„Zd„Zd„ZRS(s4Adapter for SQLAlchemy to talk to Trellis componentscCs1|t|iƒjot|i||ƒndS(N(skeys CellFactoriessselfsclass_ssetattrsinst(sselfskeysinst((s/build\bdist.win32\egg\peak\events\sa_support.pysinstall_descriptor scCs.|t|iƒjot|i|ƒndS(N(skeys CellFactoriessselfsclass_sdelattr(sselfskey((s/build\bdist.win32\egg\peak\events\sa_support.pysuninstall_descriptor sc sætˆƒ‰ˆ oµˆi} t| ƒi}t| ƒ} t t ˆƒ}g‰xT|D]L}|| joqTnˆi|ƒtt ||ƒ||tƒƒˆ|x7ˆD]/}ˆ|iotˆ|ˆ|iƒqqWdS(N(sattrssattrscellsswas_sets set_attributesinstancesvalue(sattr(sinstancescellssattrs(s/build\bdist.win32\egg\peak\events\sa_support.pyssetter s(sCellssinstancescellss __class__sclss CellValuessgets get_values CellFactoriess factoriessinstancemethods get_attributesgettersattrssselfsattrsappendsEffectorsNO_VALUEssetters Performers _observerssupers SAInstruments install_statesstate( sselfsinstancesstatesattrssetterscellss get_valuesattrssgetters factoriesscls((sinstancescellssattrss/build\bdist.win32\egg\peak\events\sa_support.pys install_states      )(s__name__s __module__s__doc__sinstall_descriptorsuninstall_descriptors install_state(((s/build\bdist.win32\egg\peak\events\sa_support.pys SAInstruments   N(ssqlalchemy.orm.attributess get_attributes set_attributes ClassManagerstrellissCellssEffectorsNO_VALUEs CellValuess CellFactoriess Performersnewsinstancemethods SAInstrument( sEffectors Performers CellFactoriessCellss get_attributesinstancemethods set_attributes ClassManagersNO_VALUEs CellValuess SAInstrument((s/build\bdist.win32\egg\peak\events\sa_support.pys?s%  PKå“‹8}¥ÌJ²?²?peak/events/stm.py"""Software Transactional Memory and Observers""" import weakref, sys, heapq, UserList, UserDict, sets from peak.util.extremes import Max from peak.util import decorators try: import threading except ImportError: import dummy_threading as threading __all__ = [ 'STMHistory', 'AbstractSubject', 'Link', 'AbstractListener', 'Controller', 'CircularityError', 'LocalController', ] class CircularityError(Exception): """Rules arranged in an infinite loop""" class AbstractSubject(object): """Abstract base for objects that can be linked via ``Link`` objects""" __slots__ = () manager = None layer = 0 def __init__(self): self.next_listener = None def iter_listeners(self): """Yield the listeners of this subject""" link = self.next_listener while link is not None: nxt = link.next_listener # avoid unlinks breaking iteration ob = link() if ob is not None: yield ob link = nxt class AbstractListener(object): """Abstract base for objects that can be linked via ``Link`` objects""" __slots__ = () layer = 0 def __init__(self): self.next_subject = None def iter_subjects(self): """Yield the listeners of this subject""" link = self.next_subject while link is not None: nxt = link.next_subject # avoid unlinks breaking iteration if link.subject is not None: yield link.subject link = nxt def dirty(self): """Mark the listener dirty and query whether it should be scheduled If a true value is returned, the listener should be scheduled. Note that this method is allowed to have side-effects, but must be idempotent. """ return True def run(self): """Take whatever action the listener is supposed to take""" raise NotImplementedError # Python 2.3 Compatibility try: class Link(weakref.ref): pass except TypeError: class link_base(object): __slots__ = 'weakref' def __new__(cls, ob, callback): self = object.__new__(cls) self.weakref = weakref.ref(ob, lambda r: callback(self)) return self def __call__(self): return self.weakref() else: link_base = weakref.ref try: from threading import local except ImportError: from _threading_local import local threading.local = local try: set except NameError: from sets import Set as set class Link(link_base): """Dependency link""" __slots__ = [ 'subject','next_subject','prev_subject','next_listener','prev_listener' ] def __new__(cls, subject, listener): self = link_base.__new__(Link, listener, _unlink_fn) self.subject = self.prev_listener = subject self.prev_subject = None # listener link is via weak ref nxt = self.next_subject = listener.next_subject if nxt is not None: nxt.prev_subject = self nxt = self.next_listener = subject.next_listener if nxt is not None: nxt.prev_listener = self listener.next_subject = self subject.next_listener = self return self def unlink(self): """Deactivate the link and remove it from its lists""" nxt = self.next_listener prev = self.prev_listener if nxt is not None: nxt.prev_listener = prev if prev is not None and prev.next_listener is self: prev.next_listener = nxt prev = self.prev_subject nxt = self.next_subject if nxt is not None: nxt.prev_subject = prev if prev is None: prev = self() # get head of list if prev is not None and prev.next_subject is self: prev.next_subject = nxt self.subject = self.next_subject = self.prev_subject = None self.next_listener = self.prev_listener = None _unlink_fn = Link.unlink class STMHistory(object): """Simple STM implementation using undo logging and context managers""" active = in_cleanup = undoing = False def __init__(self): self.undo = [] # [(func,args), ...] self.at_commit =[] # [(func,args), ...] self.managers = {} # [mgr]->seq # (context managers to __exit__ with) def atomically(self, func=lambda:None, *args, **kw): """Invoke ``func(*args,**kw)`` atomically""" if self.active: return func(*args, **kw) self.active = True try: try: retval = func(*args, **kw) self.cleanup() return retval except: self.cleanup(*sys.exc_info()) finally: self.active = False def manage(self, mgr): assert self.active, "Can't manage without active history" if mgr not in self.managers: mgr.__enter__() self.managers[mgr] = len(self.managers) def on_undo(self, func, *args): """Call `func(*args)` if atomic operation is undone""" assert self.active, "Can't record undo without active history" if not self.undoing: self.undo.append((func, args)) def savepoint(self): """Get a savepoint suitable for calling ``rollback_to()``""" return len(self.undo) def cleanup(self, typ=None, val=None, tb=None): # Exit the processing loop, unwinding managers assert self.active, "Can't exit when inactive" assert not self.in_cleanup, "Can't invoke cleanup while in cleanup" self.in_cleanup = True if typ is None: try: for (f,a) in self.at_commit: f(*a) except: typ, val, tb = sys.exc_info() if typ is not None: try: self.rollback_to(0) except: typ, val, tb = sys.exc_info() managers = [(posn,mgr) for (mgr, posn) in self.managers.items()] managers.sort() self.managers.clear() try: while managers: try: managers.pop()[1].__exit__(typ, val, tb) except: typ, val, tb = sys.exc_info() if typ is not None: raise typ, val, tb finally: del self.at_commit[:], self.undo[:] self.in_cleanup = False typ = val = tb = None def change_attr(self, ob, attr, val): """Set `ob.attr` to `val`, w/undo log to restore the previous value""" self.on_undo(setattr, ob, attr, getattr(ob, attr)) setattr(ob, attr, val) def rollback_to(self, sp=0): """Rollback to the specified savepoint""" assert self.active, "Can't rollback without active history" undo = self.undo self.undoing = True rb = self.rollback_to try: while len(undo) > sp: f, a = undo.pop() if f==rb and a: sp = min(sp, a[0]) else: f(*a) finally: self.undoing = False def on_commit(self, func, *args): """Call `func(*args)` if atomic operation is committed""" assert self.active, "Not in an atomic operation" self.at_commit.append((func, args)) self.undo.append((self.at_commit.pop,())) class Controller(STMHistory): """STM History with support for subjects, listeners, and queueing""" current_listener = destinations = routes = None readonly = False def __init__(self): super(Controller, self).__init__() self.reads = {} self.writes = {} self.has_run = {} # listeners that have run self.layers = [] # heap of layer numbers self.queues = {} # [layer] -> dict of listeners to be run self.to_retry = {} from peak.events.trellis import Value self.pulse = Value(0) def cleanup(self, *args): try: self.has_run.clear() return super(Controller, self).cleanup(*args) finally: self.current_listener = None def _retry(self): try: # undo back through listeners, watching to detect cycles self.destinations = set(self.to_retry) self.routes = {} # tree of rules that (re)triggered retry targets self.rollback_to(min([self.has_run[r] for r in self.to_retry])) for item in self.to_retry: if item in self.routes: raise CircularityError(self.routes) else: map(self.schedule, self.to_retry) finally: self.to_retry.clear() self.destinations = self.routes = None def _unrun(self, listener, notified): destinations = self.destinations if destinations is not None: via = destinations.intersection(notified) if via: self.routes[listener] = via; destinations.add(listener) def run_rule(self, listener, initialized=True): """Run the specified listener""" if listener.layer is Max and not self.readonly: return self.with_readonly(self.run_rule, listener, initialized) old = self.current_listener self.current_listener = listener try: 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" old_reads, self.reads = self.reads, {} try: listener.run() self._process_reads(listener, initialized) finally: self.reads = old_reads else: if initialized: self.has_run[listener] = self.savepoint() self.on_undo(self.has_run.pop, listener, None) try: listener.run() self._process_writes(listener) self._process_reads(listener, initialized) except: self.reads.clear() self.writes.clear() raise finally: self.current_listener = old def _process_writes(self, listener): # # Remove changed items from self.writes and notify their listeners, # and setting up an undo action to track this listener's participation # in any cyclic dependency that might occur later. # notified = {} writes = self.writes layer = listener.layer while writes: subject, writer = writes.popitem() for dependent in subject.iter_listeners(): if dependent is not listener: if dependent.dirty(): self.schedule(dependent, layer) #, writer notified[dependent] = 1 if notified: self.on_undo(self._unrun, listener, notified) def _process_reads(self, listener, undo=True): # # Remove subjects from self.reads and link them to `listener` # (Old subjects of the listener are deleted, and self.reads is cleared # subjects = self.reads link = listener.next_subject while link is not None: nxt = link.next_subject # avoid unlinks breaking iteration if link.subject in subjects: del subjects[link.subject] else: if undo: self.undo.append((Link, (link.subject, listener))) link.unlink() link = nxt while subjects: link = Link(subjects.popitem()[0], listener) if undo: self.undo.append((link.unlink, ())) def schedule(self, listener, source_layer=None): """Schedule `listener` to run during an atomic operation If an operation is already in progress, it's immediately scheduled, and its scheduling is logged in the undo queue (unless it was already scheduled). If `source_layer` is specified, ensure that the listener belongs to a higher layer than the source, moving the listener from an existing queue layer if necessary. (This layer elevation is intentionally NOT undo-logged, however.) """ new = old = listener.layer get = self.queues.get assert not self.readonly or old is Max, \ "Shouldn't be scheduling a non-Observer during commit" if source_layer is not None and source_layer >= listener.layer: new = source_layer + 1 if listener in self.has_run: self.to_retry[listener]=1 q = get(old) if q and listener in q: if new is not old: self.cancel(listener) elif self.active and not self.undoing: self.on_undo(self.cancel, listener) if new is not old: listener.layer = new q = get(new) if q is None: q = self.queues[new] = {listener:1} heapq.heappush(self.layers, new) else: q[listener] = 1 def cancel(self, listener): """Prevent the listener from being recalculated, if applicable""" q = self.queues.get(listener.layer) if q and listener in q: del q[listener] if not q: del self.queues[listener.layer] self.layers.remove(listener.layer) self.layers.sort() # preserve heap order def atomically(self, func=lambda:None, *args, **kw): """Invoke ``func(*args,**kw)`` atomically""" if self.active: return func(*args, **kw) return super(Controller,self).atomically(self._process, func, args, kw) def _process(self, func, args, kw): try: retval = func(*args, **kw) layers = self.layers queues = self.queues while layers or self.at_commit: self.pulse.value += 1 while layers: if self.to_retry: self._retry() q = queues[layers[0]] if q: listener = q.popitem()[0] self.on_undo(self.schedule, listener) self.run_rule(listener) else: del queues[layers[0]] heapq.heappop(layers) self.cleanup() return retval except: del self.layers[:] self.queues.clear() raise def lock(self, subject): assert self.active, "Subjects must be accessed atomically" manager = subject.manager if manager is not None and manager not in self.managers: self.manage(manager) def used(self, subject): self.lock(subject) cl = self.current_listener if cl is not None and subject not i