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 from re import search
27 import sys
28 from threading import Thread
29 from time import sleep
30 from traceback import print_exc
31 import wx
32
33
34 from compat import Queue
35 from prompt import interpreter
36 from relax_errors import AllRelaxErrors
37 from status import Status; status = Status()
38 from user_functions.data import Uf_info; uf_info = Uf_info()
39
40
41 from gui.errors import gui_raise
42
43
45 """The threaded interpreter."""
46
47
48 _instance = None
49
72
73
75 """Return the user function object corresponding to the given string.
76
77 @param uf: The name of the user function.
78 @type uf: str
79 @return: The user function object.
80 @rtype: func
81 """
82
83
84 info = uf_info.get_uf(uf)
85
86
87 return info.backend
88
89
90 - def apply(self, uf, *args, **kwds):
91 """Apply a user function for synchronous execution.
92
93 @param uf: The user function as a string.
94 @type uf: str
95 @param args: The user function arguments.
96 @type args: any arguments
97 @param kwds: The user function keyword arguments.
98 @type kwds: any keyword arguments
99 @return: Whether the user function was successfully applied or not.
100 @rtype: bool
101 """
102
103
104 if status.debug:
105 sys.stdout.write("debug> GUI interpreter: Applying the %s user function for synchronous execution.\n" % uf)
106
107
108 fn = self._get_backend(uf)
109
110
111 try:
112 apply(fn, args, kwds)
113
114
115 except AllRelaxErrors:
116 instance = sys.exc_info()[1]
117
118
119 gui_raise(instance, raise_flag=False)
120
121
122 return False
123
124
125 status.observers.gui_uf.notify()
126
127
128 return True
129
130
132 """Determine if the interpreter thread queue is empty.
133
134 This is a wrapper method for the thread method.
135 """
136
137
138 return self._interpreter_thread.empty()
139
140
142 """Cause the thread to exit once all currently queued user functions are processed.
143
144 This is a wrapper method for the thread method.
145 """
146
147
148 return self._interpreter_thread.exit()
149
150
152 """Return only once the queue is empty.
153
154 This is a wrapper method for the interpreter thread.
155 """
156
157
158 if status.debug:
159 sys.stdout.write("debug> GUI interpreter: Flushing.\n")
160
161
162 sleep(0.05)
163
164
165 while not self._interpreter_thread.empty():
166
167 sleep(0.05)
168
169
170 while status.exec_lock.locked():
171 sleep(0.1)
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 apply(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