mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	Subsume the interact() function in a class. This should make it
possible to use this in PythonWin, and to replace Fredrik Lundh's PythonInterpreter class. Fredrik is credited with the class' API.
This commit is contained in:
		
							parent
							
								
									d9d2625dbd
								
							
						
					
					
						commit
						a93b848e33
					
				
					 1 changed files with 198 additions and 43 deletions
				
			
		
							
								
								
									
										241
									
								
								Lib/code.py
									
										
									
									
									
								
							
							
						
						
									
										241
									
								
								Lib/code.py
									
										
									
									
									
								
							|  | @ -1,5 +1,9 @@ | |||
| """Utilities dealing with code objects.""" | ||||
| 
 | ||||
| import sys | ||||
| import string | ||||
| import traceback | ||||
| 
 | ||||
| def compile_command(source, filename="<input>", symbol="single"): | ||||
|     r"""Compile a command and determine whether it is incomplete. | ||||
| 
 | ||||
|  | @ -60,51 +64,202 @@ def compile_command(source, filename="<input>", symbol="single"): | |||
|         raise SyntaxError, err1 | ||||
| 
 | ||||
| 
 | ||||
| def interact(banner=None, readfunc=raw_input, local=None): | ||||
|     # Due to Jeff Epler, with changes by Guido: | ||||
|     """Closely emulate the interactive Python console.""" | ||||
|     try: import readline # Enable GNU readline if available | ||||
|     except: pass | ||||
|     local = local or {} | ||||
|     import sys, string, traceback | ||||
|     sys.ps1 = '>>> ' | ||||
|     sys.ps2 = '... ' | ||||
|     if banner: | ||||
|         print banner | ||||
|     else: | ||||
|         print "Python Interactive Console", sys.version | ||||
|         print sys.copyright | ||||
|     buf = [] | ||||
|     while 1: | ||||
|         if buf: prompt = sys.ps2 | ||||
|         else: prompt = sys.ps1 | ||||
|         try: line = readfunc(prompt) | ||||
|         except KeyboardInterrupt: | ||||
|             print "\nKeyboardInterrupt" | ||||
|             buf = [] | ||||
|             continue | ||||
|         except EOFError: break | ||||
|         buf.append(line) | ||||
|         try: x = compile_command(string.join(buf, "\n")) | ||||
|         except SyntaxError: | ||||
|             traceback.print_exc(0) | ||||
|             buf = [] | ||||
|             continue | ||||
|         if x == None: continue | ||||
| class InteractiveConsole: | ||||
|     """Closely emulate the behavior of the interactive Python interpreter. | ||||
| 
 | ||||
|     After code by Jeff Epler and Fredrik Lundh. | ||||
|     """ | ||||
| 
 | ||||
|     def __init__(self, filename="<console>", locals=None): | ||||
|         """Constructor. | ||||
| 
 | ||||
|         The optional filename argument specifies the (file)name of the | ||||
|         input stream; it will show up in tracebacks.  It defaults to | ||||
|         '<console>'. | ||||
| 
 | ||||
|         """ | ||||
|         self.filename = filename | ||||
|         if locals is None: | ||||
|             locals = {} | ||||
|         self.locals = locals | ||||
|         self.resetbuffer() | ||||
| 
 | ||||
|     def resetbuffer(self): | ||||
|         """Reset the input buffer (but not the variables!).""" | ||||
|         self.buffer = [] | ||||
| 
 | ||||
|     def interact(self, banner=None): | ||||
|         """Closely emulate the interactive Python console.""" | ||||
|         try: | ||||
|             sys.ps1 | ||||
|         except AttributeError: | ||||
|             sys.ps1 = ">>> " | ||||
|         try: | ||||
|             sys.ps2 | ||||
|         except AttributeError: | ||||
|             sys.ps2 = "... " | ||||
|         if banner is None: | ||||
|             self.write("Python %s on %s\n%s\n(%s)\n" % | ||||
|                        (sys.version, sys.platform, sys.copyright, | ||||
|                         self.__class__.__name__)) | ||||
|         else: | ||||
|             try: exec x in local | ||||
|             self.write("%s\n" % str(banner)) | ||||
|         more = 0 | ||||
|         while 1: | ||||
|             try: | ||||
|                 if more: | ||||
|                     prompt = sys.ps2 | ||||
|                 else: | ||||
|                     prompt = sys.ps1 | ||||
|                 try: | ||||
|                     line = self.raw_input(prompt) | ||||
|                 except EOFError: | ||||
|                     self.write("\n") | ||||
|                     break | ||||
|                 else: | ||||
|                     more = self.push(line) | ||||
|             except KeyboardInterrupt: | ||||
|                 self.write("\nKeyboardInterrupt\n") | ||||
|                 self.resetbuffer() | ||||
|                 more = 0 | ||||
| 
 | ||||
|     def push(self, line): | ||||
|         """Push a line to the interpreter. | ||||
| 
 | ||||
|         The line should not have a trailing newline. | ||||
| 
 | ||||
|         One of three things will happen: | ||||
| 
 | ||||
|         1) The input is incorrect; compile_command() raised | ||||
|         SyntaxError.  A syntax traceback will be printed. | ||||
| 
 | ||||
|         2) The input is incomplete, and more input is required; | ||||
|         compile_command() returned None. | ||||
| 
 | ||||
|         3) The input is complete; compile_command() returned a code | ||||
|         object.  The code is executed.  When an exception occurs, a | ||||
|         traceback is printed.  All exceptions are caught except | ||||
|         SystemExit, which is reraised. | ||||
| 
 | ||||
|         The return value is 1 in case 2, 0 in the other cases.  (The | ||||
|         return value can be used to decide whether to use sys.ps1 or | ||||
|         sys.ps2 to prompt the next line.) | ||||
| 
 | ||||
|         A note about KeyboardInterrupt: this exception may occur | ||||
|         elsewhere in this code, and will not always be caught.  The | ||||
|         caller should be prepared to deal with it. | ||||
| 
 | ||||
|         """ | ||||
|         self.buffer.append(line) | ||||
| 
 | ||||
|         try: | ||||
|             x = compile_command(string.join(self.buffer, "\n"), | ||||
|                                 filename=self.filename) | ||||
|         except SyntaxError: | ||||
|             # Case 1 | ||||
|             self.showsyntaxerror() | ||||
|             self.resetbuffer() | ||||
|             return 0 | ||||
| 
 | ||||
|         if x is None: | ||||
|             # Case 2 | ||||
|             return 1 | ||||
| 
 | ||||
|         # Case 3 | ||||
|         try: | ||||
|             exec x in self.locals | ||||
|         except SystemExit: | ||||
|             raise | ||||
|         except: | ||||
|             self.showtraceback() | ||||
|         self.resetbuffer() | ||||
|         return 0 | ||||
| 
 | ||||
|     def showsyntaxerror(self): | ||||
|         """Display the syntax error that just occurred. | ||||
| 
 | ||||
|         This doesn't display a stack trace because there isn't one. | ||||
| 
 | ||||
|         The output is written by self.write(), below. | ||||
| 
 | ||||
|         """ | ||||
|         type, value = sys.exc_info()[:2] | ||||
|         # Work hard to stuff the correct filename in the exception | ||||
|         try: | ||||
|             msg, (filename, lineno, offset, line) = value | ||||
|         except: | ||||
|             pass | ||||
|         else: | ||||
|             try: | ||||
|                 value = SyntaxError(msg, (self.filename, lineno, offset, line)) | ||||
|             except: | ||||
|                 exc_type, exc_value, exc_traceback = \ | ||||
|                         sys.exc_type, sys.exc_value, \ | ||||
|                         sys.exc_traceback | ||||
|                 l = len(traceback.extract_tb(sys.exc_traceback)) | ||||
|                 try: 1/0 | ||||
|                 except: | ||||
|                     m = len(traceback.extract_tb( | ||||
|                             sys.exc_traceback)) | ||||
|                 traceback.print_exception(exc_type, | ||||
|                         exc_value, exc_traceback, l-m) | ||||
|             buf = [] | ||||
|                 value = msg, (self.filename, lineno, offset, line) | ||||
|         list = traceback.format_exception_only(type, value) | ||||
|         map(self.write, list) | ||||
| 
 | ||||
|     def showtraceback(self): | ||||
|         """Display the exception that just occurred. | ||||
| 
 | ||||
|         We remove the first stack item because it is our own code. | ||||
| 
 | ||||
|         The output is written by self.write(), below. | ||||
| 
 | ||||
|         """ | ||||
|         try: | ||||
|             type, value, tb = sys.exc_info() | ||||
|             tblist = traceback.extract_tb(tb) | ||||
|             del tblist[0] | ||||
|             list = traceback.format_list(tblist) | ||||
|             list[len(list):] = traceback.format_exception_only(type, value) | ||||
|         finally: | ||||
|             tblist = tb = None | ||||
|         map(self.write, list) | ||||
| 
 | ||||
|     def write(self, data): | ||||
|         """Write a string. | ||||
| 
 | ||||
|         The base implementation writes to sys.stderr; a subclass may | ||||
|         replace this with a different implementation. | ||||
| 
 | ||||
|         """ | ||||
|         sys.stderr.write(data) | ||||
| 
 | ||||
|     def raw_input(self, prompt=""): | ||||
|         """Write a prompt and read a line. | ||||
| 
 | ||||
|         The returned line does not include the trailing newline. | ||||
|         When the user enters the EOF key sequence, EOFError is raised. | ||||
| 
 | ||||
|         The base implementation uses the built-in function | ||||
|         raw_input(); a subclass may replace this with a different | ||||
|         implementation. | ||||
| 
 | ||||
|         """ | ||||
|         return raw_input(prompt) | ||||
| 
 | ||||
| 
 | ||||
| def interact(banner=None, readfunc=None, locals=None): | ||||
|     """Closely emulate the interactive Python interpreter. | ||||
| 
 | ||||
|     This is a backwards compatible interface to the InteractiveConsole | ||||
|     class.  It attempts to import the readline module to enable GNU | ||||
|     readline if it is available. | ||||
| 
 | ||||
|     Arguments (all optional, all default to None): | ||||
| 
 | ||||
|     banner -- passed to InteractiveConsole.interact() | ||||
|     readfunc -- if not None, replaces InteractiveConsole.raw_input() | ||||
|     locals -- passed to InteractiveConsole.__init__() | ||||
| 
 | ||||
|     """ | ||||
|     try: | ||||
|         import readline | ||||
|     except: | ||||
|         pass | ||||
|     console = InteractiveConsole(locals=locals) | ||||
|     if readfunc is not None: | ||||
|         console.raw_input = readfunc | ||||
|     console.interact(banner) | ||||
|                  | ||||
| if __name__ == '__main__': | ||||
|     interact() | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Guido van Rossum
						Guido van Rossum