def loop(condition, timeout=None): """ Executes the main loop until condition is met. This function may be called recursively, however two loops may not run in parallel threads. :param condition: a callable or object that is evaluated after each step of the loop. If it evaluates False, the loop terminates. (If condition is therefore ``True``, the loop will run forever.) :param timeout: number of seconds after which the loop will terminate (regardless of the condition). """ _loop_lock.acquire() if is_running() and not is_mainthread(): # race condition. Two threads started a mainloop and the other # one is executed right now. Raise a RuntimeError _loop_lock.release() raise RuntimeError('loop running in a different thread') initial_mainloop = False if not is_running(): # no mainloop is running, set this thread as mainloop and # set the internal running state. initial_mainloop = True set_as_mainthread() _set_running(True) # ok, that was the critical part _loop_lock.release() if not callable(condition): condition = lambda: condition abort = [] if timeout is not None: # timeout handling to stop the mainloop after the given timeout # even when the condition is still True. sec = timeout timeout = OneShotTimer(lambda: abort.append(True)) timeout.start(sec) try: while condition() and not abort: try: notifier.step() signals['step'].emit() except BaseException, e: if signals['exception'].emit(*sys.exc_info()) != False: # Either there are no global exception handlers, or none of # them explicitly returned False to abort mainloop # termination. So abort the main loop. type, value, tb = sys.exc_info() raise type, value, tb finally: # make sure we set mainloop status if timeout is not None: timeout.stop() if initial_mainloop: _set_running(False)
def delay(seconds): """ Returns an InProgress that finishes after the given time in seconds. :param obj: object to represent as an InProgress. :return: :class:`~kaa.InProgress` """ ip = InProgressCallback() timer = OneShotTimer(ip) # If the IP gets aborted, stop the timer. Otherwise the timer # will fire and the IP would attempt to get finished a second # time (and would therefore raise an exception). ip.signals['abort'].connect_weak(lambda exc: timer.stop()) timer.start(seconds) return ip
class EventManager(object): """ Class to manage Event and EventHandler objects. Internal use only. """ def __init__(self): self.queue = [] self.locked = False self.timer = OneShotTimer(self.handle) self.handler = [] def post(self, event): """ Add event to the queue. """ self.queue.append(event) if not self.timer.active: self.timer.start(0) def handle(self): """ Handle the next event. """ if self.locked: self.timer.start(0.01) return if not self.queue: return self.locked = True event = self.queue[0] self.queue = self.queue[1:] try: for handler in copy.copy(self.handler): handler(event) except Exception, e: log.exception('event callback') self.locked = False if self.queue and not self.timer.active: self.timer.start(0)
def __init__(self): self.queue = [] self.locked = False self.timer = OneShotTimer(self.handle) self.handler = []