Package gui :: Module interpreter
[hide private]
[frames] | no frames]

Source Code for Module gui.interpreter

  1  ############################################################################### 
  2  #                                                                             # 
  3  # Copyright (C) 2011-2012 Edward d'Auvergne                                   # 
  4  #                                                                             # 
  5  # This file is part of the program relax.                                     # 
  6  #                                                                             # 
  7  # relax is free software; you can redistribute it and/or modify               # 
  8  # it under the terms of the GNU General Public License as published by        # 
  9  # the Free Software Foundation; either version 2 of the License, or           # 
 10  # (at your option) any later version.                                         # 
 11  #                                                                             # 
 12  # relax is distributed in the hope that it will be useful,                    # 
 13  # but WITHOUT ANY WARRANTY; without even the implied warranty of              # 
 14  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               # 
 15  # GNU General Public License for more details.                                # 
 16  #                                                                             # 
 17  # You should have received a copy of the GNU General Public License           # 
 18  # along with relax; if not, write to the Free Software                        # 
 19  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA   # 
 20  #                                                                             # 
 21  ############################################################################### 
 22   
 23  # Module docstring. 
 24  """A threaded version of the relax interpreter for use by the GUI.""" 
 25   
 26  # Python module imports. 
 27  from Queue import Queue 
 28  from re import search 
 29  from string import split 
 30  import sys 
 31  from threading import Thread 
 32  from time import sleep 
 33  from traceback import print_exc 
 34  import wx 
 35   
 36  # relax module imports. 
 37  from prompt import interpreter 
 38  from relax_errors import AllRelaxErrors 
 39  from status import Status; status = Status() 
 40  from user_functions.data import Uf_info; uf_info = Uf_info() 
 41   
 42  # relax GUI module imports. 
 43  from gui.errors import gui_raise 
 44   
 45   
46 -class Interpreter(object):
47 """The threaded interpreter.""" 48 49 # Class variable for storing the class instance (for the singleton). 50 _instance = None 51
52 - def __new__(self, *args, **kargs):
53 """Replacement method for implementing the singleton design pattern.""" 54 55 # First instantiation. 56 if self._instance is None: 57 # Instantiate. 58 self._instance = object.__new__(self, *args, **kargs) 59 60 # Load a copy of the relax interpreter. 61 self._instance._interpreter = interpreter.Interpreter(show_script=False, quit=False, raise_relax_error=True) 62 self._instance._interpreter.populate_self() 63 self._instance._interpreter.on(verbose=False) 64 65 # Start the interpreter thread for asynchronous operations. 66 self._instance._interpreter_thread = Interpreter_thread() 67 self._instance._interpreter_thread.start() 68 69 # Hack to turn off ANSI escape characters in GUI mode. 70 self._instance._interpreter.prompt_colour_off() 71 72 # Already instantiated, so return the instance. 73 return self._instance
74 75
76 - def _get_backend(self, uf):
77 """Return the user function object corresponding to the given string. 78 79 @param uf: The name of the user function. 80 @type uf: str 81 @return: The user function object. 82 @rtype: func 83 """ 84 85 # Get the user function info object. 86 info = uf_info.get_uf(uf) 87 88 # Return the backend. 89 return info.backend
90 91
92 - def apply(self, uf, *args, **kwds):
93 """Apply a user function for synchronous execution. 94 95 @param uf: The user function as a string. 96 @type uf: str 97 @param args: The user function arguments. 98 @type args: any arguments 99 @param kwds: The user function keyword arguments. 100 @type kwds: any keyword arguments 101 @return: Whether the user function was successfully applied or not. 102 @rtype: bool 103 """ 104 105 # Debugging. 106 if status.debug: 107 sys.stdout.write("debug> GUI interpreter: Applying the %s user function for synchronous execution.\n" % uf) 108 109 # Get the user function backend. 110 fn = self._get_backend(uf) 111 112 # Execute the user function. 113 try: 114 apply(fn, args, kwds) 115 116 # Catch all RelaxErrors. 117 except AllRelaxErrors, instance: 118 # Display a dialog with the error. 119 gui_raise(instance, raise_flag=False) 120 121 # Return as a failure. 122 return False 123 124 # Notify all observers that a user function has completed. 125 status.observers.gui_uf.notify() 126 127 # Return success. 128 return True
129 130
131 - def empty(self):
132 """Determine if the interpreter thread queue is empty. 133 134 This is a wrapper method for the thread method. 135 """ 136 137 # Return the queue empty state. 138 return self._interpreter_thread.empty()
139 140
141 - def exit(self):
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 # Call the thread's method. 148 return self._interpreter_thread.exit()
149 150
151 - def flush(self):
152 """Return only once the queue is empty. 153 154 This is a wrapper method for the interpreter thread. 155 """ 156 157 # Debugging. 158 if status.debug: 159 sys.stdout.write("debug> GUI interpreter: Flushing.\n") 160 161 # Wait a little while to prevent races with the reading of the queue. 162 sleep(0.05) 163 164 # Loop until empty. 165 while not self._interpreter_thread.empty(): 166 # Wait a bit for the queue to empty. 167 sleep(0.05) 168 169 # Wait until execution is complete. 170 while status.exec_lock.locked(): 171 sleep(0.1) 172 173 # Debugging. 174 if status.debug: 175 sys.stdout.write("debug> GUI interpreter: Flushed.\n")
176 177
178 - def join(self):
179 """Wrapper method for the Queue.join() method.""" 180 181 # Call the thread's method. 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 """ 197 198 # Debugging. 199 if status.debug: 200 sys.stdout.write("debug> GUI interpreter: Queuing the %s user function for asynchronous execution.\n" % uf) 201 202 # Get the user function. 203 fn = self._get_backend(uf) 204 205 # Call the thread's method. 206 self._interpreter_thread.queue(fn, *args, **kwds)
207 208 209
210 -class Interpreter_thread(Thread):
211 """The threaded interpreter.""" 212
213 - def __init__(self):
214 """Initialise the object.""" 215 216 # Set up the thread object. 217 Thread.__init__(self) 218 219 # Set the thread to be daemonic so that relax can exit. 220 self.daemon = True 221 222 # Create a queue object for the user function calls. 223 self._queue = Queue() 224 225 # The list of user functions still in the queue. 226 self._uf_list = [] 227 228 # A flag for exiting the thread. 229 self._exit = False
230 231
232 - def empty(self):
233 """Is the queue empty?""" 234 235 # Execution is locked. 236 if status.exec_lock.locked(): 237 return False 238 239 # There are still queued calls. 240 elif len(self._uf_list): 241 return False 242 243 # The queue is empty. 244 else: 245 return True
246 247
248 - def exit(self):
249 """Cause the thread to exit once all currently queued user functions are processed.""" 250 251 # First set the flag. 252 self._exit = True 253 254 # Then queue a dummy user function. 255 self._queue.put([None, None, None])
256 257
258 - def join(self):
259 """Wrapper method for the Queue.join() method.""" 260 261 # Join the queue. 262 self._queue.join()
263 264
265 - def queue(self, fn, *args, **kwds):
266 """Queue up a user function for asynchronous execution. 267 268 @param fn: The user function as a string. 269 @type fn: str 270 @param args: The user function arguments. 271 @type args: any arguments 272 @param kwds: The user function keyword arguments. 273 @type kwds: any keyword arguments 274 """ 275 276 # Add the user function name to the list. 277 self._uf_list.append(repr(fn)) 278 279 # Place the user function and its args onto the queue. 280 self._queue.put([fn, args, kwds])
281 282
283 - def run(self):
284 """Execute the thread.""" 285 286 # Loop until told to exit. 287 while not self._exit: 288 # Get the user function from the queue. 289 fn, args, kwds = self._queue.get() 290 291 # No user function. 292 if fn == None: 293 continue 294 295 # Execution lock. 296 status.exec_lock.acquire('gui', mode='interpreter thread') 297 298 # Execute the user function, catching errors. 299 try: 300 apply(fn, args, kwds) 301 302 # Catch all RelaxErrors. 303 except AllRelaxErrors, instance: 304 # Display a dialog with the error. 305 wx.CallAfter(gui_raise, instance, raise_flag=False) 306 307 # Handle all other errors. 308 except: 309 # Print the exception. 310 print_exc() 311 312 # Release the lock. 313 finally: 314 # Signal that the queue item has been processed. 315 self._queue.task_done() 316 317 # Release the execution lock. 318 status.exec_lock.release() 319 320 # Remove the user function from the list. 321 self._uf_list.pop(self._uf_list.index(repr(fn))) 322 323 # Notify all observers that a user function has completed. 324 status.observers.gui_uf.notify()
325