1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 """A threaded version of the relax interpreter for use by the GUI."""
24
25
26 import sys
27 from threading import Thread
28 from time import sleep
29 from traceback import print_exc
30 import wx
31
32
33 from gui.errors import gui_raise
34 from lib.compat import Queue
35 from lib.errors import AllRelaxErrors
36 from prompt import interpreter
37 from status import Status; status = Status()
38 from user_functions.data import Uf_info; uf_info = Uf_info()
39
40
42 """The threaded interpreter."""
43
44
45 _instance = None
46
69
70
72 """Return the user function object corresponding to the given string.
73
74 @param uf: The name of the user function.
75 @type uf: str
76 @return: The user function object.
77 @rtype: func
78 """
79
80
81 info = uf_info.get_uf(uf)
82
83
84 return info.backend
85
86
87 - def apply(self, uf, *args, **kwds):
88 """Apply a user function for synchronous execution.
89
90 @param uf: The user function as a string.
91 @type uf: str
92 @param args: The user function arguments.
93 @type args: any arguments
94 @param kwds: The user function keyword arguments.
95 @type kwds: any keyword arguments
96 @return: Whether the user function was successfully applied or not.
97 @rtype: bool
98 """
99
100
101 if status.debug:
102 sys.stdout.write("debug> GUI interpreter: Applying the %s user function for synchronous execution.\n" % uf)
103
104
105 fn = self._get_backend(uf)
106
107
108 try:
109 fn(*args, **kwds)
110
111
112 except AllRelaxErrors:
113 instance = sys.exc_info()[1]
114
115
116 gui_raise(instance, raise_flag=False)
117
118
119 return False
120
121
122 except:
123
124 print_exc()
125 sys.stderr.flush()
126
127
128 return False
129
130
131 status.observers.gui_uf.notify()
132
133
134 return True
135
136
138 """Determine if the interpreter thread queue is empty.
139
140 This is a wrapper method for the thread method.
141 """
142
143
144 return self._interpreter_thread.empty()
145
146
148 """Cause the thread to exit once all currently queued user functions are processed.
149
150 This is a wrapper method for the thread method.
151 """
152
153
154 return self._interpreter_thread.exit()
155
156
158 """Return only once the queue is empty.
159
160 This is a wrapper method for the interpreter thread.
161 """
162
163
164 if status.debug:
165 sys.stdout.write("debug> GUI interpreter: Flushing.\n")
166
167
168 sleep(0.05)
169
170
171 while not self._interpreter_thread.empty():
172
173 sleep(0.05)
174
175
176 while status.exec_lock.locked():
177 sleep(0.1)
178
179
180 wx.Yield()
181
182
183 if status.debug:
184 sys.stdout.write("debug> GUI interpreter: Flushed.\n")
185
186
188 """Wrapper method for the Queue.join() method."""
189
190
191 self._interpreter_thread.join()
192
193
194 - def queue(self, uf, *args, **kwds):
195 """Queue up a user function.
196
197 This is a wrapper method for the interpreter thread.
198
199 @param uf: The user function as a string.
200 @type uf: str
201 @param args: The user function arguments.
202 @type args: any arguments
203 @param kwds: The user function keyword arguments.
204 @type kwds: any keyword arguments
205 @return: Whether the user function was successfully applied or not (though as this is asynchronous, this cannot be checked so True will always be returned.
206 @rtype: bool
207 """
208
209
210 if status.debug:
211 sys.stdout.write("debug> GUI interpreter: Queuing the %s user function for asynchronous execution.\n" % uf)
212
213
214 fn = self._get_backend(uf)
215
216
217 self._interpreter_thread.queue(fn, *args, **kwds)
218
219
220 return True
221
222
223
225 """The threaded interpreter."""
226
228 """Initialise the object."""
229
230
231 Thread.__init__(self)
232
233
234 self.daemon = True
235
236
237 self._queue = Queue()
238
239
240 self._uf_list = []
241
242
243 self._exit = False
244
245
247 """Is the queue empty?"""
248
249
250 if status.exec_lock.locked():
251 return False
252
253
254 elif len(self._uf_list):
255 return False
256
257
258 else:
259 return True
260
261
263 """Cause the thread to exit once all currently queued user functions are processed."""
264
265
266 self._exit = True
267
268
269 self._queue.put([None, None, None])
270
271
273 """Wrapper method for the Queue.join() method."""
274
275
276 self._queue.join()
277
278
279 - def queue(self, fn, *args, **kwds):
280 """Queue up a user function for asynchronous execution.
281
282 @param fn: The user function as a string.
283 @type fn: str
284 @param args: The user function arguments.
285 @type args: any arguments
286 @param kwds: The user function keyword arguments.
287 @type kwds: any keyword arguments
288 """
289
290
291 self._uf_list.append(repr(fn))
292
293
294 self._queue.put([fn, args, kwds])
295
296
298 """Execute the thread."""
299
300
301 while not self._exit:
302
303 fn, args, kwds = self._queue.get()
304
305
306 if fn == None:
307 continue
308
309
310 status.exec_lock.acquire('gui', mode='interpreter thread')
311
312
313 try:
314 try:
315 fn(*args, **kwds)
316
317
318 except AllRelaxErrors:
319 instance = sys.exc_info()[1]
320
321
322 wx.CallAfter(gui_raise, instance, raise_flag=False)
323
324
325 except:
326
327 print_exc()
328
329
330 finally:
331
332 self._queue.task_done()
333
334
335 status.exec_lock.release()
336
337
338 self._uf_list.pop(self._uf_list.index(repr(fn)))
339
340
341 status.observers.gui_uf.notify()
342