Home | History | Annotate | Download | only in Lib
      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 import argparse
     11 from codeop import CommandCompiler, compile_command
     12 
     13 __all__ = ["InteractiveInterpreter", "InteractiveConsole", "interact",
     14            "compile_command"]
     15 
     16 class 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 
    163 class 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 
    279 def 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 
    305 if __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