codekingpro/portable-devtools
114k
1import traceback2 3import eventlet.hubs4from eventlet.support import greenlets as greenlet5import six6 7""" If true, captures a stack trace for each timer when constructed. This is8useful for debugging leaking timers, to find out where the timer was set up. """9_g_debug = False10 11 12class Timer(object):13 def __init__(self, seconds, cb, *args, **kw):14 """Create a timer.15 seconds: The minimum number of seconds to wait before calling16 cb: The callback to call when the timer has expired17 *args: The arguments to pass to cb18 **kw: The keyword arguments to pass to cb19 20 This timer will not be run unless it is scheduled in a runloop by21 calling timer.schedule() or runloop.add_timer(timer).22 """23 self.seconds = seconds24 self.tpl = cb, args, kw25 self.called = False26 if _g_debug:27 self.traceback = six.StringIO()28 traceback.print_stack(file=self.traceback)29 30 @property31 def pending(self):32 return not self.called33 34 def __repr__(self):35 secs = getattr(self, 'seconds', None)36 cb, args, kw = getattr(self, 'tpl', (None, None, None))37 retval = "Timer(%s, %s, *%s, **%s)" % (38 secs, cb, args, kw)39 if _g_debug and hasattr(self, 'traceback'):40 retval += '\n' + self.traceback.getvalue()41 return retval42 43 def copy(self):44 cb, args, kw = self.tpl45 return self.__class__(self.seconds, cb, *args, **kw)46 47 def schedule(self):48 """Schedule this timer to run in the current runloop.49 """50 self.called = False51 self.scheduled_time = eventlet.hubs.get_hub().add_timer(self)52 return self53 54 def __call__(self, *args):55 if not self.called:56 self.called = True57 cb, args, kw = self.tpl58 try:59 cb(*args, **kw)60 finally:61 try:62 del self.tpl63 except AttributeError:64 pass65 66 def cancel(self):67 """Prevent this timer from being called. If the timer has already68 been called or canceled, has no effect.69 """70 if not self.called:71 self.called = True72 eventlet.hubs.get_hub().timer_canceled(self)73 try:74 del self.tpl75 except AttributeError:76 pass77 78 # No default ordering in 3.x. heapq uses <79 # FIXME should full set be added?80 def __lt__(self, other):81 return id(self) < id(other)82 83 84class LocalTimer(Timer):85 86 def __init__(self, *args, **kwargs):87 self.greenlet = greenlet.getcurrent()88 Timer.__init__(self, *args, **kwargs)89 90 @property91 def pending(self):92 if self.greenlet is None or self.greenlet.dead:93 return False94 return not self.called95 96 def __call__(self, *args):97 if not self.called:98 self.called = True99 if self.greenlet is not None and self.greenlet.dead:100 return101 cb, args, kw = self.tpl102 cb(*args, **kw)103 104 def cancel(self):105 self.greenlet = None106 Timer.cancel(self)107 