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 apply(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 status.observers.gui_uf.notify()
123
124
125 return True
126
127
129 """Determine if the interpreter thread queue is empty.
130
131 This is a wrapper method for the thread method.
132 """
133
134
135 return self._interpreter_thread.empty()
136
137
139 """Cause the thread to exit once all currently queued user functions are processed.
140
141 This is a wrapper method for the thread method.
142 """
143
144
145 return self._interpreter_thread.exit()
146
147
149 """Return only once the queue is empty.
150
151 This is a wrapper method for the interpreter thread.
152 """
153
154
155 if status.debug:
156 sys.stdout.write("debug> GUI interpreter: Flushing.\n")
157
158
159 sleep(0.05)
160
161
162 while not self._interpreter_thread.empty():
163
164 sleep(0.05)
165
166
167 while status.exec_lock.locked():
168 sleep(0.1)
169
170
171 if status.debug:
172 sys.stdout.write("debug> GUI interpreter: Flushed.\n")
173
174
176 """Wrapper method for the Queue.join() method."""
177
178
179 self._interpreter_thread.join()
180
181
182 - def queue(self, uf, *args, **kwds):
183 """Queue up a user function.
184
185 This is a wrapper method for the interpreter thread.
186
187 @param uf: The user function as a string.
188 @type uf: str
189 @param args: The user function arguments.
190 @type args: any arguments
191 @param kwds: The user function keyword arguments.
192 @type kwds: any keyword arguments
193 @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.
194 @rtype: bool
195 """
196
197
198 if status.debug:
199 sys.stdout.write("debug> GUI interpreter: Queuing the %s user function for asynchronous execution.\n" % uf)
200
201
202 fn = self._get_backend(uf)
203
204
205 self._interpreter_thread.queue(fn, *args, **kwds)
206
207
208 return True
209
210
211
213 """The threaded interpreter."""
214
216 """Initialise the object."""
217
218
219 Thread.__init__(self)
220
221
222 self.daemon = True
223
224
225 self._queue = Queue()
226
227
228 self._uf_list = []
229
230
231 self._exit = False
232
233
235 """Is the queue empty?"""
236
237
238 if status.exec_lock.locked():
239 return False
240
241
242 elif len(self._uf_list):
243 return False
244
245
246 else:
247 return True
248
249
251 """Cause the thread to exit once all currently queued user functions are processed."""
252
253
254 self._exit = True
255
256
257 self._queue.put([None, None, None])
258
259
261 """Wrapper method for the Queue.join() method."""
262
263
264 self._queue.join()
265
266
267 - def queue(self, fn, *args, **kwds):
268 """Queue up a user function for asynchronous execution.
269
270 @param fn: The user function as a string.
271 @type fn: str
272 @param args: The user function arguments.
273 @type args: any arguments
274 @param kwds: The user function keyword arguments.
275 @type kwds: any keyword arguments
276 """
277
278
279 self._uf_list.append(repr(fn))
280
281
282 self._queue.put([fn, args, kwds])
283
284
286 """Execute the thread."""
287
288
289 while not self._exit:
290
291 fn, args, kwds = self._queue.get()
292
293
294 if fn == None:
295 continue
296
297
298 status.exec_lock.acquire('gui', mode='interpreter thread')
299
300
301 try:
302 try:
303 apply(fn, args, kwds)
304
305
306 except AllRelaxErrors:
307 instance = sys.exc_info()[1]
308
309
310 wx.CallAfter(gui_raise, instance, raise_flag=False)
311
312
313 except:
314
315 print_exc()
316
317
318 finally:
319
320 self._queue.task_done()
321
322
323 status.exec_lock.release()
324
325
326 self._uf_list.pop(self._uf_list.index(repr(fn)))
327
328
329 status.observers.gui_uf.notify()
330