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   
 41  # relax GUI module imports. 
 42  from gui.errors import gui_raise 
 43   
 44   
45 -class Interpreter(object):
46 """The threaded interpreter.""" 47 48 # Class variable for storing the class instance (for the singleton). 49 _instance = None 50
51 - def __new__(self, *args, **kargs):
52 """Replacement method for implementing the singleton design pattern.""" 53 54 # First instantiation. 55 if self._instance is None: 56 # Instantiate. 57 self._instance = object.__new__(self, *args, **kargs) 58 59 # Load a copy of the relax interpreter. 60 self._instance._interpreter = interpreter.Interpreter(show_script=False, quit=False, raise_relax_error=True) 61 self._instance._interpreter.populate_self() 62 self._instance._interpreter.on(verbose=False) 63 64 # Start the interpreter thread for asynchronous operations. 65 self._instance._interpreter_thread = Interpreter_thread() 66 self._instance._interpreter_thread.start() 67 68 # Hack to turn off ANSI escape characters in GUI mode. 69 self._instance._interpreter._exec_info.prompt_colour_off() 70 71 # Already instantiated, so return the instance. 72 return self._instance
73 74
75 - def _get_uf(self, uf):
76 """Return the user function object corresponding to the given string. 77 78 @param uf: The name of the user function. 79 @type uf: str 80 @return: The user function object. 81 @rtype: func 82 """ 83 84 # Handle the user function class. 85 if search('\.', uf): 86 # Split the user function. 87 uf_class, uf_fn = split(uf, '.') 88 89 # Get the user function class. 90 obj = getattr(self._interpreter, uf_class) 91 92 # Get the function. 93 fn = getattr(obj, uf_fn) 94 95 # Simple user function. 96 else: 97 fn = getattr(self._interpreter, uf) 98 99 # Return the user function. 100 return fn
101 102
103 - def apply(self, uf, *args, **kwds):
104 """Apply a user function for synchronous execution. 105 106 @param uf: The user function as a string. 107 @type uf: str 108 @param args: The user function arguments. 109 @type args: any arguments 110 @param kwds: The user function keyword arguments. 111 @type kwds: any keyword arguments 112 @return: Whether the user function was successfully applied or not. 113 @rtype: bool 114 """ 115 116 # Debugging. 117 if status.debug: 118 sys.stdout.write("debug> GUI interpreter: Applying the %s user function for synchronous execution.\n" % uf) 119 120 # Get the user function. 121 fn = self._get_uf(uf) 122 123 # Execute the user function. 124 try: 125 apply(fn, args, kwds) 126 127 # Catch all RelaxErrors. 128 except AllRelaxErrors, instance: 129 # Display a dialog with the error. 130 gui_raise(instance, raise_flag=False) 131 132 # Return as a failure. 133 return False 134 135 # Notify all observers that a user function has completed. 136 status.observers.gui_uf.notify() 137 138 # Return success. 139 return True
140 141
142 - def empty(self):
143 """Determine if the interpreter thread queue is empty. 144 145 This is a wrapper method for the thread method. 146 """ 147 148 # Return the queue empty state. 149 return self._interpreter_thread.empty()
150 151
152 - def exit(self):
153 """Cause the thread to exit once all currently queued user functions are processed. 154 155 This is a wrapper method for the thread method. 156 """ 157 158 # Call the thread's method. 159 return self._interpreter_thread.exit()
160 161
162 - def flush(self):
163 """Return only once the queue is empty. 164 165 This is a wrapper method for the interpreter thread. 166 """ 167 168 # Debugging. 169 if status.debug: 170 sys.stdout.write("debug> GUI interpreter: Flushing.\n") 171 172 # Wait a little while to prevent races with the reading of the queue. 173 sleep(0.5) 174 175 # Loop until empty. 176 while not self._interpreter_thread.empty(): 177 # Wait a bit for the queue to empty. 178 sleep(0.2) 179 180 # Wait until execution is complete. 181 while status.exec_lock.locked(): 182 sleep(0.5) 183 184 # Debugging. 185 if status.debug: 186 sys.stdout.write("debug> GUI interpreter: Flushed.\n")
187 188
189 - def join(self):
190 """Wrapper method for the Queue.join() method.""" 191 192 # Call the thread's method. 193 self._interpreter_thread.join()
194 195
196 - def queue(self, uf, *args, **kwds):
197 """Queue up a user function. 198 199 This is a wrapper method for the interpreter thread. 200 201 @param uf: The user function as a string. 202 @type uf: str 203 @param args: The user function arguments. 204 @type args: any arguments 205 @param kwds: The user function keyword arguments. 206 @type kwds: any keyword arguments 207 """ 208 209 # Debugging. 210 if status.debug: 211 sys.stdout.write("debug> GUI interpreter: Queuing the %s user function for asynchronous execution.\n" % uf) 212 213 # Get the user function. 214 fn = self._get_uf(uf) 215 216 # Call the thread's method. 217 self._interpreter_thread.queue(fn, *args, **kwds)
218 219 220
221 -class Interpreter_thread(Thread):
222 """The threaded interpreter.""" 223
224 - def __init__(self):
225 """Initialise the object.""" 226 227 # Set up the thread object. 228 Thread.__init__(self) 229 230 # Set the thread to be daemonic so that relax can exit. 231 self.daemon = True 232 233 # Create a queue object for the user function calls. 234 self._queue = Queue() 235 236 # The list of user functions still in the queue. 237 self._uf_list = [] 238 239 # A flag for exiting the thread. 240 self._exit = False
241 242
243 - def empty(self):
244 """Is the queue empty?""" 245 246 # Execution is locked. 247 if status.exec_lock.locked(): 248 return False 249 250 # There are still queued calls. 251 elif len(self._uf_list): 252 return False 253 254 # The queue is empty. 255 else: 256 return True
257 258
259 - def exit(self):
260 """Cause the thread to exit once all currently queued user functions are processed.""" 261 262 # First set the flag. 263 self._exit = True 264 265 # Then queue a dummy user function. 266 self._queue.put([None, None, None])
267 268
269 - def join(self):
270 """Wrapper method for the Queue.join() method.""" 271 272 # Join the queue. 273 self._queue.join()
274 275
276 - def queue(self, fn, *args, **kwds):
277 """Queue up a user function for asynchronous execution. 278 279 @param fn: The user function as a string. 280 @type fn: str 281 @param args: The user function arguments. 282 @type args: any arguments 283 @param kwds: The user function keyword arguments. 284 @type kwds: any keyword arguments 285 """ 286 287 # Add the user function name to the list. 288 self._uf_list.append(repr(fn)) 289 290 # Place the user function and its args onto the queue. 291 self._queue.put([fn, args, kwds])
292 293
294 - def run(self):
295 """Execute the thread.""" 296 297 # Loop until told to exit. 298 while not self._exit: 299 # Get the user function from the queue. 300 fn, args, kwds = self._queue.get() 301 302 # No user function. 303 if fn == None: 304 continue 305 306 # Execution lock. 307 status.exec_lock.acquire('gui', mode='interpreter thread') 308 309 # Execute the user function, catching errors. 310 try: 311 apply(fn, args, kwds) 312 313 # Catch all RelaxErrors. 314 except AllRelaxErrors, instance: 315 # Display a dialog with the error. 316 wx.CallAfter(gui_raise, instance, raise_flag=False) 317 318 # Handle all other errors. 319 except: 320 # Print the exception. 321 print_exc() 322 323 # Release the lock. 324 finally: 325 # Signal that the queue item has been processed. 326 self._queue.task_done() 327 328 # Release the execution lock. 329 status.exec_lock.release() 330 331 # Remove the user function from the list. 332 self._uf_list.pop(self._uf_list.index(repr(fn))) 333 334 # Notify all observers that a user function has completed. 335 status.observers.gui_uf.notify()
336