code.py revision d90ae19b92b6172f5b1aceb34c5c18ca28144ca7
1"""Utilities dealing with code objects. 2 3Inspired by similar code by Jeff Epler and Fredrik Lundh. 4""" 5 6import sys 7import string 8import traceback 9 10def compile_command(source, filename="<input>", symbol="single"): 11 r"""Compile a command and determine whether it is incomplete. 12 13 Arguments: 14 15 source -- the source string; may contain \n characters 16 filename -- optional filename from which source was read; default "<input>" 17 symbol -- optional grammar start symbol; "single" (default) or "eval" 18 19 Return value / exceptions raised: 20 21 - Return a code object if the command is complete and valid 22 - Return None if the command is incomplete 23 - Raise SyntaxError or OverflowError if the command is a syntax error 24 (OverflowError if the error is in a numeric constant) 25 26 Approach: 27 28 First, check if the source consists entirely of blank lines and 29 comments; if so, replace it with 'pass', because the built-in 30 parser doesn't always do the right thing for these. 31 32 Compile three times: as is, with \n, and with \n\n appended. If 33 it compiles as is, it's complete. If it compiles with one \n 34 appended, we expect more. If it doesn't compile either way, we 35 compare the error we get when compiling with \n or \n\n appended. 36 If the errors are the same, the code is broken. But if the errors 37 are different, we expect more. Not intuitive; not even guaranteed 38 to hold in future releases; but this matches the compiler's 39 behavior from Python 1.4 through 1.5.2, at least. 40 41 Caveat: 42 43 It is possible (but not likely) that the parser stops parsing 44 with a successful outcome before reaching the end of the source; 45 in this case, trailing symbols may be ignored instead of causing an 46 error. For example, a backslash followed by two newlines may be 47 followed by arbitrary garbage. This will be fixed once the API 48 for the parser is better. 49 50 """ 51 52 # Check for source consisting of only blank lines and comments 53 for line in string.split(source, "\n"): 54 line = string.strip(line) 55 if line and line[0] != '#': 56 break # Leave it alone 57 else: 58 source = "pass" # Replace it with a 'pass' statement 59 60 err = err1 = err2 = None 61 code = code1 = code2 = None 62 63 try: 64 code = compile(source, filename, symbol) 65 except SyntaxError, err: 66 pass 67 68 try: 69 code1 = compile(source + "\n", filename, symbol) 70 except SyntaxError, err1: 71 pass 72 73 try: 74 code2 = compile(source + "\n\n", filename, symbol) 75 except SyntaxError, err2: 76 pass 77 78 if code: 79 return code 80 try: 81 e1 = err1.__dict__ 82 except AttributeError: 83 e1 = err1 84 try: 85 e2 = err2.__dict__ 86 except AttributeError: 87 e2 = err2 88 if not code1 and e1 == e2: 89 raise SyntaxError, err1 90 91 92class InteractiveInterpreter: 93 """Base class for InteractiveConsole. 94 95 This class deals with parsing and interpreter state (the user's 96 namespace); it doesn't deal with input buffering or prompting or 97 input file naming (the filename is always passed in explicitly). 98 99 """ 100 101 def __init__(self, locals=None): 102 """Constructor. 103 104 The optional 'locals' argument specifies the dictionary in 105 which code will be executed; it defaults to a newly created 106 dictionary with key "__name__" set to "__console__" and key 107 "__doc__" set to None. 108 109 """ 110 if locals is None: 111 locals = {"__name__": "__console__", "__doc__": None} 112 self.locals = locals 113 114 def runsource(self, source, filename="<input>", symbol="single"): 115 """Compile and run some source in the interpreter. 116 117 Arguments are as for compile_command(). 118 119 One several things can happen: 120 121 1) The input is incorrect; compile_command() raised an 122 exception (SyntaxError or OverflowError). A syntax traceback 123 will be printed by calling the showsyntaxerror() method. 124 125 2) The input is incomplete, and more input is required; 126 compile_command() returned None. Nothing happens. 127 128 3) The input is complete; compile_command() returned a code 129 object. The code is executed by calling self.runcode() (which 130 also handles run-time exceptions, except for SystemExit). 131 132 The return value is 1 in case 2, 0 in the other cases (unless 133 an exception is raised). The return value can be used to 134 decide whether to use sys.ps1 or sys.ps2 to prompt the next 135 line. 136 137 """ 138 try: 139 code = compile_command(source, filename, symbol) 140 except (OverflowError, SyntaxError): 141 # Case 1 142 self.showsyntaxerror(filename) 143 return 0 144 145 if code is None: 146 # Case 2 147 return 1 148 149 # Case 3 150 self.runcode(code) 151 return 0 152 153 def runcode(self, code): 154 """Execute a code object. 155 156 When an exception occurs, self.showtraceback() is called to 157 display a traceback. All exceptions are caught except 158 SystemExit, which is reraised. 159 160 A note about KeyboardInterrupt: this exception may occur 161 elsewhere in this code, and may not always be caught. The 162 caller should be prepared to deal with it. 163 164 """ 165 try: 166 exec code in self.locals 167 except SystemExit: 168 raise 169 except: 170 self.showtraceback() 171 172 def showsyntaxerror(self, filename=None): 173 """Display the syntax error that just occurred. 174 175 This doesn't display a stack trace because there isn't one. 176 177 If a filename is given, it is stuffed in the exception instead 178 of what was there before (because Python's parser always uses 179 "<string>" when reading from a string). 180 181 The output is written by self.write(), below. 182 183 """ 184 type, value, sys.last_traceback = sys.exc_info() 185 sys.last_type = type 186 sys.last_value = value 187 if filename and type is SyntaxError: 188 # Work hard to stuff the correct filename in the exception 189 try: 190 msg, (dummy_filename, lineno, offset, line) = value 191 except: 192 # Not the format we expect; leave it alone 193 pass 194 else: 195 # Stuff in the right filename 196 try: 197 # Assume SyntaxError is a class exception 198 value = SyntaxError(msg, (filename, lineno, offset, line)) 199 except: 200 # If that failed, assume SyntaxError is a string 201 value = msg, (filename, lineno, offset, line) 202 list = traceback.format_exception_only(type, value) 203 map(self.write, list) 204 205 def showtraceback(self): 206 """Display the exception that just occurred. 207 208 We remove the first stack item because it is our own code. 209 210 The output is written by self.write(), below. 211 212 """ 213 try: 214 type, value, tb = sys.exc_info() 215 sys.last_type = type 216 sys.last_value = value 217 sys.last_traceback = tb 218 tblist = traceback.extract_tb(tb) 219 del tblist[:1] 220 list = traceback.format_list(tblist) 221 if list: 222 list.insert(0, "Traceback (innermost last):\n") 223 list[len(list):] = traceback.format_exception_only(type, value) 224 finally: 225 tblist = tb = None 226 map(self.write, list) 227 228 def write(self, data): 229 """Write a string. 230 231 The base implementation writes to sys.stderr; a subclass may 232 replace this with a different implementation. 233 234 """ 235 sys.stderr.write(data) 236 237 238class InteractiveConsole(InteractiveInterpreter): 239 """Closely emulate the behavior of the interactive Python interpreter. 240 241 This class builds on InteractiveInterpreter and adds prompting 242 using the familiar sys.ps1 and sys.ps2, and input buffering. 243 244 """ 245 246 def __init__(self, locals=None, filename="<console>"): 247 """Constructor. 248 249 The optional locals argument will be passed to the 250 InteractiveInterpreter base class. 251 252 The optional filename argument should specify the (file)name 253 of the input stream; it will show up in tracebacks. 254 255 """ 256 InteractiveInterpreter.__init__(self, locals) 257 self.filename = filename 258 self.resetbuffer() 259 260 def resetbuffer(self): 261 """Reset the input buffer.""" 262 self.buffer = [] 263 264 def interact(self, banner=None): 265 """Closely emulate the interactive Python console. 266 267 The optional banner argument specify the banner to print 268 before the first interaction; by default it prints a banner 269 similar to the one printed by the real Python interpreter, 270 followed by the current class name in parentheses (so as not 271 to confuse this with the real interpreter -- since it's so 272 close!). 273 274 """ 275 try: 276 sys.ps1 277 except AttributeError: 278 sys.ps1 = ">>> " 279 try: 280 sys.ps2 281 except AttributeError: 282 sys.ps2 = "... " 283 if banner is None: 284 self.write("Python %s on %s\n%s\n(%s)\n" % 285 (sys.version, sys.platform, sys.copyright, 286 self.__class__.__name__)) 287 else: 288 self.write("%s\n" % str(banner)) 289 more = 0 290 while 1: 291 try: 292 if more: 293 prompt = sys.ps2 294 else: 295 prompt = sys.ps1 296 try: 297 line = self.raw_input(prompt) 298 except EOFError: 299 self.write("\n") 300 break 301 else: 302 more = self.push(line) 303 except KeyboardInterrupt: 304 self.write("\nKeyboardInterrupt\n") 305 self.resetbuffer() 306 more = 0 307 308 def push(self, line): 309 """Push a line to the interpreter. 310 311 The line should not have a trailing newline; it may have 312 internal newlines. The line is appended to a buffer and the 313 interpreter's runsource() method is called with the 314 concatenated contents of the buffer as source. If this 315 indicates that the command was executed or invalid, the buffer 316 is reset; otherwise, the command is incomplete, and the buffer 317 is left as it was after the line was appended. The return 318 value is 1 if more input is required, 0 if the line was dealt 319 with in some way (this is the same as runsource()). 320 321 """ 322 self.buffer.append(line) 323 source = string.join(self.buffer, "\n") 324 more = self.runsource(source, self.filename) 325 if not more: 326 self.resetbuffer() 327 return more 328 329 def raw_input(self, prompt=""): 330 """Write a prompt and read a line. 331 332 The returned line does not include the trailing newline. 333 When the user enters the EOF key sequence, EOFError is raised. 334 335 The base implementation uses the built-in function 336 raw_input(); a subclass may replace this with a different 337 implementation. 338 339 """ 340 return raw_input(prompt) 341 342 343def interact(banner=None, readfunc=None, local=None): 344 """Closely emulate the interactive Python interpreter. 345 346 This is a backwards compatible interface to the InteractiveConsole 347 class. When readfunc is not specified, it attempts to import the 348 readline module to enable GNU readline if it is available. 349 350 Arguments (all optional, all default to None): 351 352 banner -- passed to InteractiveConsole.interact() 353 readfunc -- if not None, replaces InteractiveConsole.raw_input() 354 local -- passed to InteractiveInterpreter.__init__() 355 356 """ 357 console = InteractiveConsole(local) 358 if readfunc is not None: 359 console.raw_input = readfunc 360 else: 361 try: 362 import readline 363 except: 364 pass 365 console.interact(banner) 366 367 368if __name__ == '__main__': 369 interact() 370