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