File: scheduler.py

package info (click to toggle)
pype 2.9.1-1
  • links: PTS
  • area: main
  • in suites: squeeze
  • size: 1,200 kB
  • ctags: 1,468
  • sloc: python: 13,860; makefile: 8; sh: 7
file content (180 lines) | stat: -rw-r--r-- 5,557 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180

'''
This software is licensed under the GPL (GNU General Public License) version 2
as it appears here: http://www.gnu.org/copyleft/gpl.html
It is also included with this archive as `gpl.txt <gpl.txt>`_.
'''


import sched
import time
import traceback
import Queue
import sys
import os

USE_WX_TIMER = 1

class sobject(object):
    __slots__ = 'sched', 'function', 'args', 'kwargs', 'delay', 'priority', 'runcount', 'item'
    # an object-oriented version of the scheduler interface, with auto multi-run
    def __init__(self, sched, runcount, delay, priority, function, *args, **kwargs):
        ## print "scheduling item with delay", delay, function
        self.sched = sched
        self.function = function
        self.args = args
        self.kwargs = kwargs
        self.runcount = runcount
        self.delay = delay
        self.priority = priority
        self.item = None
        if runcount is None or runcount > 0:
            self._sched(delay, priority, self.run)
                
    def _sched(self, delay, priority, run):
        self.item = GlobalSchedule.enter(delay, priority, run, ())
        gsq = GlobalSchedule._queue[:1]
        if USE_WX_TIMER and gsq and gsq[0] is self.item:
            dt = max(int((gsq[0].time - time.time())*1000), 10)
            TIMER_INSTANCE.Stop()
            TIMER_INSTANCE.Start(milliseconds=dt, oneShot=True)
            ## print "starting timer!"

    def cancel(self):
        if self.runcount is None or self.runcount > 0:
            if self.item:
                self.sched.cancel(self.item)
            self.runcount = 0

    def run(self):
        if self.runcount is None or self.runcount > 0:
            try:
                return self.function(*self.args, **self.kwargs)
            finally:
                if self.runcount is not None:
                    self.runcount -= 1
                if self.runcount is None or self.runcount > 0:
                    self._sched(self.delay, self.priority, self.run)

    def reenter(self, delay, priority, runcount=1):
        self.cancel()
        self.runcount = runcount
        self.item = self.sched.enter(delay, self.priority, self.run, ())

    #the wx-like interface
    def Start(self, msdelay=-1, oneShot=False):
        if msdelay == -1:
            msdelay = 1000*self.delay
        if not oneShot:
            count = None
        else:
            count = 1
        ## print ''.join(traceback.format_stack()[-4:]).rstrip()
        ## print "starting", msdelay/1000.0, self.function
        self.reenter(msdelay/1000.0, 0, count)

    Stop = cancel

    def IsRunning(self):
        return self.runcount is None or self.runcount > 0

GlobalSchedule = sched.scheduler(time.time, (lambda arg:None), True)
GlobalQ = Queue.Queue()
CyclesPerSecond = 40
QUIT = 0

def PFutureCall(msdelay, priority, function, *args, **kwargs):
    return sobject(GlobalSchedule, 1, msdelay/1000.0, priority, function, *args, **kwargs)

def FutureCall(msdelay, function, *args, **kwargs):
    return PFutureCall(msdelay, 0, function, *args, **kwargs)

def ShutdownScheduler():
    global QUIT
    QUIT = 1
    def runme(*args, **kwargs):
        os._exit(0)
    PFutureCall(-1000000, -1000000, runme)

def Timer(function, *args, **kwargs):
    # We'll "schedule" it to run zero times after 1 second
    return sobject(GlobalSchedule, 0, 1, 0, function, *args, **kwargs)

def actually_run():
    global cancelled
    try:
        cancelled
    except NameError:
        cancelled = sys.modules['__main__'].cancelled
    for i in GlobalQ.get():
        if QUIT:
            break
        _1, _2, fcn, arg = i
        try:
            ## print "running function...", fcn
            fcn(*arg)
        except cancelled:
            pass
        except (SystemExit, AssertionError, KeyboardInterrupt):
            break
        except:
            import traceback
            traceback.print_exc()

def RunScheduledEvents():
    x = GlobalSchedule.getqueue(time.time(), copy=0)
    if QUIT:
        return 1
    import wx
    GlobalQ.put(x)
    if QUIT:
        return 1
    try:
        wx.CallAfter(actually_run)
    except AssertionError:
        return 1
    return 0

def _schedulethread(ok=0):
    while ok and not QUIT:
        time.sleep(1.0/max(CyclesPerSecond, 1))
        if QUIT:
            return
        if RunScheduledEvents():
            return
    if QUIT:
        return
    import threading
    x = threading.Thread(target=_schedulethread, args=(1,))
    x.setDaemon(1)
    x.start()

import sys
sys.modules['__builtin__'].FutureCall = FutureCall
sys.modules['__builtin__'].PFutureCall = FutureCall
sys.modules['__builtin__'].Timer = Timer
sys.modules['__builtin__'].ShutdownScheduler = ShutdownScheduler

if USE_WX_TIMER:
    def OnTimerDone(evt=None):
        ## print "going to run scheduled events..."
        TIMER_INSTANCE.Stop()
        if RunScheduledEvents():
            ## print "need to kill the scheduler..."
            return
        gsq = GlobalSchedule._queue[:1]
        dt = 1000
        if gsq:
            ## print "event:", gsq[0]
            dt = min(max(int((gsq[0].time - time.time())*1000), 10), 1000)
        TIMER_INSTANCE.Start(milliseconds=dt, oneShot=True)
        ## print "starting timer!"

    def _schedulethread(ok=0):
        global wx, WXAPP, TIMER_INSTANCE
        import wx
        WXAPP = wx.GetApp()
        TIMER_INSTANCE = wx.Timer(WXAPP, wx.NewId())
        WXAPP.Bind(wx.EVT_TIMER, OnTimerDone, TIMER_INSTANCE)
        TIMER_INSTANCE.Start(1, oneShot=True)
        ## print "starting timer!"