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