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 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 wx.Yield()
172
173
174 if status.debug:
175 sys.stdout.write("debug> GUI interpreter: Flushed.\n")
176
177
179 """Wrapper method for the Queue.join() method."""
180
181
182 self._interpreter_thread.join()
183
184
185 - def queue(self, uf, *args, **kwds):
186 """Queue up a user function.
187
188 This is a wrapper method for the interpreter thread.
189
190 @param uf: The user function as a string.
191 @type uf: str
192 @param args: The user function arguments.
193 @type args: any arguments
194 @param kwds: The user function keyword arguments.
195 @type kwds: any keyword arguments
196 @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.
197 @rtype: bool
198 """
199
200
201 if status.debug:
202 sys.stdout.write("debug> GUI interpreter: Queuing the %s user function for asynchronous execution.\n" % uf)
203
204
205 fn = self._get_backend(uf)
206
207
208 self._interpreter_thread.queue(fn, *args, **kwds)
209
210
211 return True
212
213
214
216 """The threaded interpreter."""
217
219 """Initialise the object."""
220
221
222 Thread.__init__(self)
223
224
225 self.daemon = True
226
227
228 self._queue = Queue()
229
230
231 self._uf_list = []
232
233
234 self._exit = False
235
236
238 """Is the queue empty?"""
239
240
241 if status.exec_lock.locked():
242 return False
243
244
245 elif len(self._uf_list):
246 return False
247
248
249 else:
250 return True
251
252
254 """Cause the thread to exit once all currently queued user functions are processed."""
255
256
257 self._exit = True
258
259
260 self._queue.put([None, None, None])
261
262
264 """Wrapper method for the Queue.join() method."""
265
266
267 self._queue.join()
268
269
270 - def queue(self, fn, *args, **kwds):
271 """Queue up a user function for asynchronous execution.
272
273 @param fn: The user function as a string.
274 @type fn: str
275 @param args: The user function arguments.
276 @type args: any arguments
277 @param kwds: The user function keyword arguments.
278 @type kwds: any keyword arguments
279 """
280
281
282 self._uf_list.append(repr(fn))
283
284
285 self._queue.put([fn, args, kwds])
286
287
289 """Execute the thread."""
290
291
292 while not self._exit:
293
294 fn, args, kwds = self._queue.get()
295
296
297 if fn == None:
298 continue
299
300
301 status.exec_lock.acquire('gui', mode='interpreter thread')
302
303
304 try:
305 try:
306 fn(*args, **kwds)
307
308
309 except AllRelaxErrors:
310 instance = sys.exc_info()[1]
311
312
313 wx.CallAfter(gui_raise, instance, raise_flag=False)
314
315
316 except:
317
318 print_exc()
319
320
321 finally:
322
323 self._queue.task_done()
324
325
326 status.exec_lock.release()
327
328
329 self._uf_list.pop(self._uf_list.index(repr(fn)))
330
331
332 status.observers.gui_uf.notify()
333