1"""Utilities needed to emulate Python's interactive interpreter. 2 3""" 4 5# Inspired by similar code by Jeff Epler and Fredrik Lundh. 6 7 8import sys 9import traceback 10import argparse 11from codeop import CommandCompiler, compile_command 12 13__all__ = ["InteractiveInterpreter", "InteractiveConsole", "interact", 14 "compile_command"] 15 16class InteractiveInterpreter: 17 """Base class for InteractiveConsole. 18 19 This class deals with parsing and interpreter state (the user's 20 namespace); it doesn't deal with input buffering or prompting or 21 input file naming (the filename is always passed in explicitly). 22 23 """ 24 25 def __init__(self, locals=None): 26 """Constructor. 27 28 The optional 'locals' argument specifies the dictionary in 29 which code will be executed; it defaults to a newly created 30 dictionary with key "__name__" set to "__console__" and key 31 "__doc__" set to None. 32 33 """ 34 if locals is None: 35 locals = {"__name__": "__console__", "__doc__": None} 36 self.locals = locals 37 self.compile = CommandCompiler() 38 39 def runsource(self, source, filename="<input>", symbol="single"): 40 """Compile and run some source in the interpreter. 41 42 Arguments are as for compile_command(). 43 44 One several things can happen: 45 46 1) The input is incorrect; compile_command() raised an 47 exception (SyntaxError or OverflowError). A syntax traceback 48 will be printed by calling the showsyntaxerror() method. 49 50 2) The input is incomplete, and more input is required; 51 compile_command() returned None. Nothing happens. 52 53 3) The input is complete; compile_command() returned a code 54 object. The code is executed by calling self.runcode() (which 55 also handles run-time exceptions, except for SystemExit). 56 57 The return value is True in case 2, False in the other cases (unless 58 an exception is raised). The return value can be used to 59 decide whether to use sys.ps1 or sys.ps2 to prompt the next 60 line. 61 62 """ 63 try: 64 code = self.compile(source, filename, symbol) 65 except (OverflowError, SyntaxError, ValueError): 66 # Case 1 67 self.showsyntaxerror(filename) 68 return False 69 70 if code is None: 71 # Case 2 72 return True 73 74 # Case 3 75 self.runcode(code) 76 return False 77 78 def runcode(self, code): 79 """Execute a code object. 80 81 When an exception occurs, self.showtraceback() is called to 82 display a traceback. All exceptions are caught except 83 SystemExit, which is reraised. 84 85 A note about KeyboardInterrupt: this exception may occur 86 elsewhere in this code, and may not always be caught. The 87 caller should be prepared to deal with it. 88 89 """ 90 try: 91 exec(code, self.locals) 92 except SystemExit: 93 raise 94 except: 95 self.showtraceback() 96 97 def showsyntaxerror(self, filename=None): 98 """Display the syntax error that just occurred. 99 100 This doesn't display a stack trace because there isn't one. 101 102 If a filename is given, it is stuffed in the exception instead 103 of what was there before (because Python's parser always uses 104 "<string>" when reading from a string). 105 106 The output is written by self.write(), below. 107 108 """ 109 type, value, tb = sys.exc_info() 110 sys.last_type = type 111 sys.last_value = value 112 sys.last_traceback = tb 113 if filename and type is SyntaxError: 114 # Work hard to stuff the correct filename in the exception 115 try: 116 msg, (dummy_filename, lineno, offset, line) = value.args 117 except ValueError: 118 # Not the format we expect; leave it alone 119 pass 120 else: 121 # Stuff in the right filename 122 value = SyntaxError(msg, (filename, lineno, offset, line)) 123 sys.last_value = value 124 if sys.excepthook is sys.__excepthook__: 125 lines = traceback.format_exception_only(type, value) 126 self.write(''.join(lines)) 127 else: 128 # If someone has set sys.excepthook, we let that take precedence 129 # over self.write 130 sys.excepthook(type, value, tb) 131 132 def showtraceback(self): 133 """Display the exception that just occurred. 134 135 We remove the first stack item because it is our own code. 136 137 The output is written by self.write(), below. 138 139 """ 140 sys.last_type, sys.last_value, last_tb = ei = sys.exc_info() 141 sys.last_traceback = last_tb 142 try: 143 lines = traceback.format_exception(ei[0], ei[1], last_tb.tb_next) 144 if sys.excepthook is sys.__excepthook__: 145 self.write(''.join(lines)) 146 else: 147 # If someone has set sys.excepthook, we let that take precedence 148 # over self.write 149 sys.excepthook(ei[0], ei[1], last_tb) 150 finally: 151 last_tb = ei = None 152 153 def write(self, data): 154 """Write a string. 155 156 The base implementation writes to sys.stderr; a subclass may 157 replace this with a different implementation. 158 159 """ 160 sys.stderr.write(data) 161 162 163class InteractiveConsole(InteractiveInterpreter): 164 """Closely emulate the behavior of the interactive Python interpreter. 165 166 This class builds on InteractiveInterpreter and adds prompting 167 using the familiar sys.ps1 and sys.ps2, and input buffering. 168 169 """ 170 171 def __init__(self, locals=None, filename="<console>"): 172 """Constructor. 173 174 The optional locals argument will be passed to the 175 InteractiveInterpreter base class. 176 177 The optional filename argument should specify the (file)name 178 of the input stream; it will show up in tracebacks. 179 180 """ 181 InteractiveInterpreter.__init__(self, locals) 182 self.filename = filename 183 self.resetbuffer() 184 185 def resetbuffer(self): 186 """Reset the input buffer.""" 187 self.buffer = [] 188 189 def interact(self, banner=None, exitmsg=None): 190 """Closely emulate the interactive Python console. 191 192 The optional banner argument specifies the banner to print 193 before the first interaction; by default it prints a banner 194 similar to the one printed by the real Python interpreter, 195 followed by the current class name in parentheses (so as not 196 to confuse this with the real interpreter -- since it's so 197 close!). 198 199 The optional exitmsg argument specifies the exit message 200 printed when exiting. Pass the empty string to suppress 201 printing an exit message. If exitmsg is not given or None, 202 a default message is printed. 203 204 """ 205 try: 206 sys.ps1 207 except AttributeError: 208 sys.ps1 = ">>> " 209 try: 210 sys.ps2 211 except AttributeError: 212 sys.ps2 = "... " 213 cprt = 'Type "help", "copyright", "credits" or "license" for more information.' 214 if banner is None: 215 self.write("Python %s on %s\n%s\n(%s)\n" % 216 (sys.version, sys.platform, cprt, 217 self.__class__.__name__)) 218 elif banner: 219 self.write("%s\n" % str(banner)) 220 more = 0 221 while 1: 222 try: 223 if more: 224 prompt = sys.ps2 225 else: 226 prompt = sys.ps1 227 try: 228 line = self.raw_input(prompt) 229 except EOFError: 230 self.write("\n") 231 break 232 else: 233 more = self.push(line) 234 except KeyboardInterrupt: 235 self.write("\nKeyboardInterrupt\n") 236 self.resetbuffer() 237 more = 0 238 if exitmsg is None: 239 self.write('now exiting %s...\n' % self.__class__.__name__) 240 elif exitmsg != '': 241 self.write('%s\n' % exitmsg) 242 243 def push(self, line): 244 """Push a line to the interpreter. 245 246 The line should not have a trailing newline; it may have 247 internal newlines. The line is appended to a buffer and the 248 interpreter's runsource() method is called with the 249 concatenated contents of the buffer as source. If this 250 indicates that the command was executed or invalid, the buffer 251 is reset; otherwise, the command is incomplete, and the buffer 252 is left as it was after the line was appended. The return 253 value is 1 if more input is required, 0 if the line was dealt 254 with in some way (this is the same as runsource()). 255 256 """ 257 self.buffer.append(line) 258 source = "\n".join(self.buffer) 259 more = self.runsource(source, self.filename) 260 if not more: 261 self.resetbuffer() 262 return more 263 264 def raw_input(self, prompt=""): 265 """Write a prompt and read a line. 266 267 The returned line does not include the trailing newline. 268 When the user enters the EOF key sequence, EOFError is raised. 269 270 The base implementation uses the built-in function 271 input(); a subclass may replace this with a different 272 implementation. 273 274 """ 275 return input(prompt) 276 277 278 279def interact(banner=None, readfunc=None, local=None, exitmsg=None): 280 """Closely emulate the interactive Python interpreter. 281 282 This is a backwards compatible interface to the InteractiveConsole 283 class. When readfunc is not specified, it attempts to import the 284 readline module to enable GNU readline if it is available. 285 286 Arguments (all optional, all default to None): 287 288 banner -- passed to InteractiveConsole.interact() 289 readfunc -- if not None, replaces InteractiveConsole.raw_input() 290 local -- passed to InteractiveInterpreter.__init__() 291 exitmsg -- passed to InteractiveConsole.interact() 292 293 """ 294 console = InteractiveConsole(local) 295 if readfunc is not None: 296 console.raw_input = readfunc 297 else: 298 try: 299 import readline 300 except ImportError: 301 pass 302 console.interact(banner, exitmsg) 303 304 305if __name__ == "__main__": 306 parser = argparse.ArgumentParser() 307 parser.add_argument('-q', action='store_true', 308 help="don't print version and copyright messages") 309 args = parser.parse_args() 310 if args.q or sys.flags.quiet: 311 banner = '' 312 else: 313 banner = None 314 interact(banner) 315