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 (http://www.nmr-relax.com).          # 
  6  #                                                                             # 
  7  # This program 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 3 of the License, or           # 
 10  # (at your option) any later version.                                         # 
 11  #                                                                             # 
 12  # This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.       # 
 19  #                                                                             # 
 20  ############################################################################### 
 21   
 22  # Module docstring. 
 23  """A threaded version of the relax interpreter for use by the GUI.""" 
 24   
 25  # Python module imports. 
 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  # relax module imports. 
 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  # relax GUI module imports. 
 41  from gui.errors import gui_raise 
 42   
 43   
44 -class Interpreter(object):
45 """The threaded interpreter.""" 46 47 # Class variable for storing the class instance (for the singleton). 48 _instance = None 49
50 - def __new__(self, *args, **kargs):
51 """Replacement method for implementing the singleton design pattern.""" 52 53 # First instantiation. 54 if self._instance is None: 55 # Instantiate. 56 self._instance = object.__new__(self, *args, **kargs) 57 58 # Load a copy of the relax interpreter. 59 self._instance._interpreter = interpreter.Interpreter(show_script=False, quit=False, raise_relax_error=True) 60 self._instance._interpreter.populate_self() 61 self._instance._interpreter.on(verbose=False) 62 63 # Start the interpreter thread for asynchronous operations. 64 self._instance._interpreter_thread = Interpreter_thread() 65 self._instance._interpreter_thread.start() 66 67 # Hack to turn off ANSI escape characters in GUI mode. 68 self._instance._interpreter.prompt_colour_off() 69 70 # Already instantiated, so return the instance. 71 return self._instance
72 73
74 - def _get_backend(self, uf):
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 # Get the user function info object. 84 info = uf_info.get_uf(uf) 85 86 # Return the backend. 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 # Debugging. 104 if status.debug: 105 sys.stdout.write("debug> GUI interpreter: Applying the %s user function for synchronous execution.\n" % uf) 106 107 # Get the user function backend. 108 fn = self._get_backend(uf) 109 110 # Execute the user function. 111 try: 112 apply(fn, args, kwds) 113 114 # Catch all RelaxErrors. 115 except AllRelaxErrors: 116 instance = sys.exc_info()[1] 117 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 @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 # Debugging. 201 if status.debug: 202 sys.stdout.write("debug> GUI interpreter: Queuing the %s user function for asynchronous execution.\n" % uf) 203 204 # Get the user function. 205 fn = self._get_backend(uf) 206 207 # Call the thread's method. 208 self._interpreter_thread.queue(fn, *args, **kwds) 209 210 # Cannot judge if the user function was successful. 211 return True
212 213 214
215 -class Interpreter_thread(Thread):
216 """The threaded interpreter.""" 217
218 - def __init__(self):
219 """Initialise the object.""" 220 221 # Set up the thread object. 222 Thread.__init__(self) 223 224 # Set the thread to be daemonic so that relax can exit. 225 self.daemon = True 226 227 # Create a queue object for the user function calls. 228 self._queue = Queue() 229 230 # The list of user functions still in the queue. 231 self._uf_list = [] 232 233 # A flag for exiting the thread. 234 self._exit = False
235 236
237 - def empty(self):
238 """Is the queue empty?""" 239 240 # Execution is locked. 241 if status.exec_lock.locked(): 242 return False 243 244 # There are still queued calls. 245 elif len(self._uf_list): 246 return False 247 248 # The queue is empty. 249 else: 250 return True
251 252
253 - def exit(self):
254 """Cause the thread to exit once all currently queued user functions are processed.""" 255 256 # First set the flag. 257 self._exit = True 258 259 # Then queue a dummy user function. 260 self._queue.put([None, None, None])
261 262
263 - def join(self):
264 """Wrapper method for the Queue.join() method.""" 265 266 # Join the queue. 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 # Add the user function name to the list. 282 self._uf_list.append(repr(fn)) 283 284 # Place the user function and its args onto the queue. 285 self._queue.put([fn, args, kwds])
286 287
288 - def run(self):
289 """Execute the thread.""" 290 291 # Loop until told to exit. 292 while not self._exit: 293 # Get the user function from the queue. 294 fn, args, kwds = self._queue.get() 295 296 # No user function. 297 if fn == None: 298 continue 299 300 # Execution lock. 301 status.exec_lock.acquire('gui', mode='interpreter thread') 302 303 # Execute the user function, catching errors (the nested try-except statements within the try-finally statements are for Python 2.4 and earlier support). 304 try: 305 try: 306 apply(fn, args, kwds) 307 308 # Catch all RelaxErrors. 309 except AllRelaxErrors: 310 instance = sys.exc_info()[1] 311 312 # Display a dialog with the error. 313 wx.CallAfter(gui_raise, instance, raise_flag=False) 314 315 # Handle all other errors. 316 except: 317 # Print the exception. 318 print_exc() 319 320 # Release the lock. 321 finally: 322 # Signal that the queue item has been processed. 323 self._queue.task_done() 324 325 # Release the execution lock. 326 status.exec_lock.release() 327 328 # Remove the user function from the list. 329 self._uf_list.pop(self._uf_list.index(repr(fn))) 330 331 # Notify all observers that a user function has completed. 332 status.observers.gui_uf.notify()
333