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

Source Code for Module prompt.interpreter

  1  ############################################################################### 
  2  #                                                                             # 
  3  # Copyright (C) 2003-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  """The prompt based relax user interface (UI).""" 
 25   
 26  # Dependency check module. 
 27  import dep_check 
 28   
 29  # Python module imports. 
 30  import ansi 
 31  from code import InteractiveConsole, softspace 
 32  from math import pi 
 33  from os import F_OK, access, chdir, getcwd, path 
 34  from re import search 
 35  if dep_check.readline_module: 
 36      import readline 
 37  if dep_check.runpy_module: 
 38      import runpy 
 39  from string import split 
 40  import sys 
 41   
 42  # relax module imports. 
 43  from info import Info_box 
 44  from prompt.command import Ls, Lh, Ll, system 
 45  from prompt.gpl import GPL 
 46  from prompt.help import _Helper, _Helper_python 
 47  if dep_check.readline_module: 
 48      from prompt.tab_completion import Tab_completion 
 49  from prompt.uf_objects import Class_container, Uf_object 
 50  from relax_errors import AllRelaxErrors, RelaxBinError, RelaxError, RelaxNoneError, RelaxStrError 
 51  from status import Status; status = Status() 
 52  from user_functions.data import Uf_info; uf_info = Uf_info() 
 53   
 54   
 55  # Module variables. 
 56  ################### 
 57   
 58  # The prompts (to change the Python prompt, as well as the function printouts). 
 59  PS1_ORIG = 'relax> ' 
 60  PS2_ORIG = 'relax| ' 
 61  PS3_ORIG = '\n%s' % PS1_ORIG 
 62   
 63  # Coloured text. 
 64  PS1_COLOUR = "%s%s%s" % (ansi.relax_prompt, PS1_ORIG, ansi.end) 
 65  PS2_COLOUR = "%s%s%s" % (ansi.relax_prompt, PS2_ORIG, ansi.end) 
 66  PS3_COLOUR = "\n%s%s%s" % (ansi.relax_prompt, PS1_ORIG, ansi.end) 
 67   
 68   
69 -class Interpreter:
70 - def __init__(self, show_script=True, quit=True, raise_relax_error=False):
71 """The interpreter class. 72 73 @param show_script: If true, the relax will print the script contents prior to 74 executing the script. 75 @type show_script: bool 76 @param quit: If true, the default, then relax will exit after running the 77 run() method. 78 @type quit: bool 79 @param raise_relax_error: If false, the default, then relax will print a nice error 80 message to STDERR, without a traceback, when a RelaxError 81 occurs. This is to make things nicer for the user. 82 @type raise_relax_error: bool 83 """ 84 85 # Place the arguments in the class namespace. 86 self.__show_script = show_script 87 self.__quit_flag = quit 88 self.__raise_relax_error = raise_relax_error 89 90 # Build the intro string. 91 info = Info_box() 92 self.__intro_string = info.intro_text() 93 94 # The prompts (change the Python prompt, as well as the function printouts). 95 if ansi.enable_control_chars(stream=1): 96 self.prompt_colour_on() 97 else: 98 self.prompt_colour_off() 99 100 # Set up the interpreter objects. 101 self._locals = self._setup()
102 103
104 - def _execute_uf(self, *args, **kargs):
105 """Private method for executing the given user function. 106 107 @keyword uf_name: The name of the user function. 108 @type uf_name: str 109 """ 110 111 # Checks. 112 if 'uf_name' not in kargs: 113 raise RelaxError("The user function name argument 'uf_name' has not been supplied.") 114 115 # Process the user function name. 116 uf_name = kargs.pop('uf_name') 117 118 # Split up the name. 119 if search('\.', uf_name): 120 class_name, uf_name = split(uf_name, '.') 121 else: 122 class_name = None 123 124 # Get the class object. 125 if class_name: 126 class_obj = self._locals[class_name] 127 128 # Get the user function. 129 if class_name: 130 uf = getattr(class_obj, uf_name) 131 else: 132 uf = self._locals[uf_name] 133 134 # Call the user function. 135 uf(*args, **kargs)
136 137
138 - def _setup(self):
139 """Set up all the interpreter objects. 140 141 All objects are initialised and placed in a dictionary. These will be later placed in different namespaces such as the run() method local namespace. All the user functions and classes will be auto-generated. 142 143 @return: The dictionary of interpreter objects. 144 @rtype: dict 145 """ 146 147 # Initialise the dictionary. 148 objects = {} 149 150 # Python objects. 151 objects['pi'] = pi 152 153 # Import the functions emulating system commands. 154 objects['lh'] = Lh() 155 objects['ll'] = Ll() 156 objects['ls'] = Ls() 157 objects['system'] = system 158 159 # The GPL license. 160 objects['gpl'] = objects['GPL'] = GPL() 161 162 # Builtin interpreter functions. 163 objects['intro_off'] = self.off 164 objects['intro_on'] = self.on 165 objects['exit'] = objects['bye'] = objects['quit'] = objects['q'] = _Exit() 166 167 # Modify the help system. 168 objects['help_python'] = _Helper_python() 169 objects['help'] = _Helper() 170 171 # Add the user function classes. 172 for name, data in uf_info.class_loop(): 173 # Generate a new container. 174 obj = Class_container(name, data.title) 175 176 # Add the object to the local namespace. 177 objects[name] = obj 178 179 # Add the user functions. 180 self._uf_dict = {} 181 for name, data in uf_info.uf_loop(): 182 # Split up the name. 183 if search('\.', name): 184 class_name, uf_name = split(name, '.') 185 else: 186 class_name = None 187 188 # Generate a new container. 189 obj = Uf_object(name, title=data.title, kargs=data.kargs, backend=data.backend, desc=data.desc) 190 191 # Get the class object. 192 if class_name: 193 class_obj = objects[class_name] 194 195 # Add the object to the local namespace or user function class. 196 if class_name: 197 setattr(class_obj, uf_name, obj) 198 else: 199 objects[name] = obj 200 201 # Store the user functions by full text name (for faster retrieval). 202 self._uf_dict[name] = obj 203 204 # Return the dictionary. 205 return objects
206 207
208 - def off(self, verbose=True):
209 """Turn the user function introductions off.""" 210 211 status.uf_intro = False 212 213 # Print out. 214 if verbose: 215 print("Echoing of user function calls has been disabled.")
216 217
218 - def on(self, verbose=True):
219 """Turn the user function introductions on.""" 220 221 status.uf_intro = True 222 223 # Print out. 224 if verbose: 225 print("Echoing of user function calls has been enabled.")
226 227
228 - def populate_self(self):
229 """Place all special objects into self.""" 230 231 # Add the interpreter objects to the class namespace. 232 for name in self._locals.keys(): 233 setattr(self, name, self._locals[name])
234 235
236 - def prompt_colour_off(self):
237 """Turn the prompt colouring ANSI escape sequences off.""" 238 239 sys.ps1 = status.ps1 = PS1_ORIG 240 sys.ps2 = status.ps2 = PS2_ORIG 241 sys.ps3 = status.ps3 = PS3_ORIG
242 243
244 - def prompt_colour_on(self):
245 """Turn the prompt colouring ANSI escape sequences off.""" 246 247 sys.ps1 = status.ps1 = PS1_COLOUR 248 sys.ps2 = status.ps2 = PS2_COLOUR 249 sys.ps3 = status.ps3 = PS3_COLOUR
250 251
252 - def run(self, script_file=None):
253 """Run the python interpreter. 254 255 The namespace of this function is the namespace seen inside the interpreter. All user 256 accessible functions, classes, etc, should be placed in this namespace. 257 258 259 @param script_file: The script file to be executed. For the interpreter mode, this 260 should be left as None. 261 @type script_file: None or str 262 """ 263 264 # Add the interpreter objects to the local run namespace. 265 for name in self._locals.keys(): 266 locals()[name] = self._locals[name] 267 268 # Setup tab completion. 269 if dep_check.readline_module: 270 readline.set_completer(Tab_completion(name_space=locals()).finish) 271 readline.set_completer_delims(' \t\n`~!@#$%^&*()=+{}\\|;:",<>/?') 272 readline.parse_and_bind("tab: complete") 273 274 # Execute the script file if given. 275 if script_file: 276 # Turn on the user function intro flag. 277 status.uf_intro = True 278 279 # Run the script. 280 return run_script(intro=self.__intro_string, local=locals(), script_file=script_file, quit=self.__quit_flag, show_script=self.__show_script, raise_relax_error=self.__raise_relax_error) 281 282 # Go to the prompt. 283 else: 284 prompt(intro=self.__intro_string, local=locals())
285 286 287
288 -class _Exit:
289 - def __repr__(self):
290 """Exit the program.""" 291 292 print("Exiting the program.") 293 sys.exit()
294 295 296
297 -def exec_script(name, globals):
298 """Execute the script.""" 299 300 # Execution lock. 301 status.exec_lock.acquire('script UI', mode='script') 302 303 # The module path. 304 head, tail = path.split(name) 305 script_path = path.join(getcwd(), head) 306 sys.path.append(script_path) 307 308 # Switch directories for nested scripting. 309 if head: 310 orig_dir = getcwd() 311 chdir(head) 312 313 # The module name. 314 module, ext = path.splitext(tail) 315 316 # Check if the script name is ok. 317 if search('\.', module): 318 raise RelaxError("The relax script must not contain the '.' character (except before the extension '*.py').") 319 if ext != '.py': 320 raise RelaxError("The script must have the extension *.py.") 321 322 # Execute the module. 323 try: 324 # Reverse the system path so that the script path is first. 325 sys.path.reverse() 326 327 # Execute the script as a module. 328 if dep_check.runpy_module: 329 runpy.run_module(module, globals) 330 331 # Allow scripts to run under Python <= 2.4. 332 else: 333 exec(compile(open(name).read(), name, 'exec'), globals) 334 335 finally: 336 # Switch back to the original working directory. 337 if head: 338 chdir(orig_dir) 339 340 # Remove the script path. 341 sys.path.reverse() 342 sys.path.pop(sys.path.index(script_path)) 343 344 # Unlock execution if needed. 345 status.exec_lock.release()
346 347
348 -def interact_prompt(self, intro=None, local={}):
349 """Replacement function for 'code.InteractiveConsole.interact'. 350 351 This will enter into the prompt. 352 353 @param intro: The string to print prior to jumping to the prompt mode. 354 @type intro: str 355 @param local: A namespace which will become that of the prompt (i.e. the namespace visible to 356 the user when in the prompt mode). This should be the output of a function such 357 as locals(). 358 @type local: dict 359 """ 360 361 # Print the program introduction. 362 if intro: 363 sys.stdout.write("%s\n" % intro) 364 365 # Ignore SIGINT. 366 #signal.signal(2, 1) 367 368 # Prompt. 369 more = False 370 while True: 371 try: 372 if more: 373 prompt = sys.ps2 374 else: 375 prompt = sys.ps1 376 try: 377 line = self.raw_input(prompt) 378 except EOFError: 379 self.write("\n") 380 break 381 else: 382 more = self.push(line) 383 except KeyboardInterrupt: 384 self.write("\nKeyboardInterrupt\n") 385 self.resetbuffer() 386 more = False
387 388
389 -def interact_script(self, intro=None, local={}, script_file=None, quit=True, show_script=True, raise_relax_error=False):
390 """Replacement function for 'code.InteractiveConsole.interact'. 391 392 This will execute the script file. 393 394 395 @param intro: The string to print prior to jumping to the prompt mode. 396 @type intro: str 397 @param local: A namespace which will become that of the prompt (i.e. the namespace 398 visible to the user when in the prompt mode). This should be the 399 output of a function such as locals(). 400 @type local: dict 401 @param script_file: The script file to be executed. 402 @type script_file: None or str 403 @param quit: If true, the default, then relax will exit after running the script. 404 @type quit: bool 405 @param show_script: If true, the relax will print the script contents prior to executing 406 the script. 407 @type show_script: bool 408 @param raise_relax_error: If false, the default, then a nice error message will be sent to 409 STDERR, without a traceback, when a RelaxError occurs. This is to 410 make things nicer for the user. 411 @type raise_relax_error: bool 412 """ 413 414 # Print the program introduction. 415 if intro: 416 sys.stdout.write("%s\n" % intro) 417 418 # Print the script. 419 if show_script: 420 try: 421 file = open(script_file, 'r') 422 except IOError, warning: 423 try: 424 raise RelaxError("The script file '" + script_file + "' does not exist.") 425 except AllRelaxErrors, instance: 426 sys.stdout.write(instance.__str__()) 427 sys.stdout.write("\n") 428 return 429 430 # Coloured text. 431 if ansi.enable_control_chars(stream=1): 432 sys.stdout.write(ansi.script) 433 434 # Print the script. 435 sys.stdout.write("script = " + repr(script_file) + "\n") 436 sys.stdout.write("----------------------------------------------------------------------------------------------------\n") 437 sys.stdout.write(file.read()) 438 sys.stdout.write("----------------------------------------------------------------------------------------------------") 439 440 # End coloured text. 441 if ansi.enable_control_chars(stream=1): 442 sys.stdout.write(ansi.end) 443 444 # Terminating newline. 445 sys.stdout.write("\n") 446 447 # Close the script file handle. 448 file.close() 449 450 # The execution flag. 451 exec_pass = True 452 453 # Execute the script. 454 try: 455 exec_script(script_file, local) 456 457 # Catch ctrl-C. 458 except KeyboardInterrupt: 459 # Unlock execution. 460 status.exec_lock.release() 461 462 # Throw the error. 463 if status.debug: 464 raise 465 466 # Be nicer to the user. 467 else: 468 sys.stderr.write("\nScript execution cancelled.\n") 469 470 # The script failed. 471 exec_pass = False 472 473 # Catch the RelaxErrors. 474 except AllRelaxErrors, instance: 475 # Unlock execution. 476 status.exec_lock.release() 477 478 # Throw the error. 479 if raise_relax_error: 480 raise 481 482 # Nice output for the user. 483 else: 484 # Print the scary traceback normally hidden from the user. 485 if status.debug: 486 self.showtraceback() 487 488 # Print the RelaxError message line. 489 else: 490 sys.stderr.write(instance.__str__()) 491 492 # The script failed. 493 exec_pass = False 494 495 # Throw all other errors. 496 except: 497 # Unlock execution. 498 status.exec_lock.release() 499 500 # Raise the error. 501 raise 502 503 # Add an empty line to make exiting relax look better. 504 if show_script: 505 sys.stdout.write("\n") 506 507 # Quit relax. 508 # FIXME: need to drop off end of interpreter loop to exit cleanly 509 #if quit: 510 # sys.exit() 511 512 # Return the execution flag. 513 return exec_pass
514 515
516 -def prompt(intro=None, local=None):
517 """Python interpreter emulation. 518 519 This function replaces 'code.interact'. 520 521 522 @param intro: The string to print prior to jumping to the prompt mode. 523 @type intro: str 524 @param local: A namespace which will become that of the prompt (i.e. the namespace visible to 525 the user when in the prompt mode). This should be the output of a function such 526 as locals(). 527 @type local: dict 528 """ 529 530 # Replace the 'InteractiveConsole.interact' and 'InteractiveConsole.runcode' functions. 531 InteractiveConsole.interact = interact_prompt 532 InteractiveConsole.runcode = runcode 533 534 # The console. 535 console = InteractiveConsole(local) 536 console.interact(intro, local)
537 538
539 -def run_script(intro=None, local=None, script_file=None, quit=True, show_script=True, raise_relax_error=False):
540 """Python interpreter emulation. 541 542 This function replaces 'code.interact'. 543 544 545 @param intro: The string to print prior to jumping to the prompt mode. 546 @type intro: str 547 @param local: A namespace which will become that of the prompt (i.e. the namespace 548 visible to the user when in the prompt mode). This should be the 549 output of a function such as locals(). 550 @type local: dict 551 @param script_file: The script file to be executed. 552 @type script_file: None or str 553 @param quit: If true, the default, then relax will exit after running the script. 554 @type quit: bool 555 @param show_script: If true, the relax will print the script contents prior to executing 556 the script. 557 @type show_script: bool 558 @param raise_relax_error: If false, the default, then a nice error message will be sent to 559 STDERR, without a traceback, when a RelaxError occurs. This is to 560 make things nicer for the user. 561 @type raise_relax_error: bool 562 """ 563 564 # Replace the 'InteractiveConsole.interact' and 'InteractiveConsole.runcode' functions. 565 InteractiveConsole.interact = interact_script 566 InteractiveConsole.runcode = runcode 567 568 # The console. 569 console = InteractiveConsole(local) 570 return console.interact(intro, local, script_file, quit, show_script=show_script, raise_relax_error=raise_relax_error)
571 572
573 -def runcode(self, code):
574 """Replacement code for code.InteractiveInterpreter.runcode. 575 576 @param code: The code to execute. 577 @type code: str 578 """ 579 580 try: 581 exec(code, self.locals) 582 except SystemExit: 583 raise 584 except AllRelaxErrors, instance: 585 self.write(instance.__str__()) 586 self.write("\n") 587 except: 588 self.showtraceback() 589 else: 590 if softspace(sys.stdout, 0): 591 print('')
592