python (3.12.0)

(root)/
lib/
python3.12/
code.py
       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 ESC[4;38;5;81mInteractiveInterpreter:
      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 of 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_exc = value
     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_exc = 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          sys.last_exc = ei[1]
     143          try:
     144              lines = traceback.format_exception(ei[0], ei[1], last_tb.tb_next)
     145              if sys.excepthook is sys.__excepthook__:
     146                  self.write(''.join(lines))
     147              else:
     148                  # If someone has set sys.excepthook, we let that take precedence
     149                  # over self.write
     150                  sys.excepthook(ei[0], ei[1], last_tb)
     151          finally:
     152              last_tb = ei = None
     153  
     154      def write(self, data):
     155          """Write a string.
     156  
     157          The base implementation writes to sys.stderr; a subclass may
     158          replace this with a different implementation.
     159  
     160          """
     161          sys.stderr.write(data)
     162  
     163  
     164  class ESC[4;38;5;81mInteractiveConsole(ESC[4;38;5;149mInteractiveInterpreter):
     165      """Closely emulate the behavior of the interactive Python interpreter.
     166  
     167      This class builds on InteractiveInterpreter and adds prompting
     168      using the familiar sys.ps1 and sys.ps2, and input buffering.
     169  
     170      """
     171  
     172      def __init__(self, locals=None, filename="<console>"):
     173          """Constructor.
     174  
     175          The optional locals argument will be passed to the
     176          InteractiveInterpreter base class.
     177  
     178          The optional filename argument should specify the (file)name
     179          of the input stream; it will show up in tracebacks.
     180  
     181          """
     182          InteractiveInterpreter.__init__(self, locals)
     183          self.filename = filename
     184          self.resetbuffer()
     185  
     186      def resetbuffer(self):
     187          """Reset the input buffer."""
     188          self.buffer = []
     189  
     190      def interact(self, banner=None, exitmsg=None):
     191          """Closely emulate the interactive Python console.
     192  
     193          The optional banner argument specifies the banner to print
     194          before the first interaction; by default it prints a banner
     195          similar to the one printed by the real Python interpreter,
     196          followed by the current class name in parentheses (so as not
     197          to confuse this with the real interpreter -- since it's so
     198          close!).
     199  
     200          The optional exitmsg argument specifies the exit message
     201          printed when exiting. Pass the empty string to suppress
     202          printing an exit message. If exitmsg is not given or None,
     203          a default message is printed.
     204  
     205          """
     206          try:
     207              sys.ps1
     208          except AttributeError:
     209              sys.ps1 = ">>> "
     210          try:
     211              sys.ps2
     212          except AttributeError:
     213              sys.ps2 = "... "
     214          cprt = 'Type "help", "copyright", "credits" or "license" for more information.'
     215          if banner is None:
     216              self.write("Python %s on %s\n%s\n(%s)\n" %
     217                         (sys.version, sys.platform, cprt,
     218                          self.__class__.__name__))
     219          elif banner:
     220              self.write("%s\n" % str(banner))
     221          more = 0
     222          while 1:
     223              try:
     224                  if more:
     225                      prompt = sys.ps2
     226                  else:
     227                      prompt = sys.ps1
     228                  try:
     229                      line = self.raw_input(prompt)
     230                  except EOFError:
     231                      self.write("\n")
     232                      break
     233                  else:
     234                      more = self.push(line)
     235              except KeyboardInterrupt:
     236                  self.write("\nKeyboardInterrupt\n")
     237                  self.resetbuffer()
     238                  more = 0
     239          if exitmsg is None:
     240              self.write('now exiting %s...\n' % self.__class__.__name__)
     241          elif exitmsg != '':
     242              self.write('%s\n' % exitmsg)
     243  
     244      def push(self, line):
     245          """Push a line to the interpreter.
     246  
     247          The line should not have a trailing newline; it may have
     248          internal newlines.  The line is appended to a buffer and the
     249          interpreter's runsource() method is called with the
     250          concatenated contents of the buffer as source.  If this
     251          indicates that the command was executed or invalid, the buffer
     252          is reset; otherwise, the command is incomplete, and the buffer
     253          is left as it was after the line was appended.  The return
     254          value is 1 if more input is required, 0 if the line was dealt
     255          with in some way (this is the same as runsource()).
     256  
     257          """
     258          self.buffer.append(line)
     259          source = "\n".join(self.buffer)
     260          more = self.runsource(source, self.filename)
     261          if not more:
     262              self.resetbuffer()
     263          return more
     264  
     265      def raw_input(self, prompt=""):
     266          """Write a prompt and read a line.
     267  
     268          The returned line does not include the trailing newline.
     269          When the user enters the EOF key sequence, EOFError is raised.
     270  
     271          The base implementation uses the built-in function
     272          input(); a subclass may replace this with a different
     273          implementation.
     274  
     275          """
     276          return input(prompt)
     277  
     278  
     279  
     280  def interact(banner=None, readfunc=None, local=None, exitmsg=None):
     281      """Closely emulate the interactive Python interpreter.
     282  
     283      This is a backwards compatible interface to the InteractiveConsole
     284      class.  When readfunc is not specified, it attempts to import the
     285      readline module to enable GNU readline if it is available.
     286  
     287      Arguments (all optional, all default to None):
     288  
     289      banner -- passed to InteractiveConsole.interact()
     290      readfunc -- if not None, replaces InteractiveConsole.raw_input()
     291      local -- passed to InteractiveInterpreter.__init__()
     292      exitmsg -- passed to InteractiveConsole.interact()
     293  
     294      """
     295      console = InteractiveConsole(local)
     296      if readfunc is not None:
     297          console.raw_input = readfunc
     298      else:
     299          try:
     300              import readline
     301          except ImportError:
     302              pass
     303      console.interact(banner, exitmsg)
     304  
     305  
     306  if __name__ == "__main__":
     307      import argparse
     308  
     309      parser = argparse.ArgumentParser()
     310      parser.add_argument('-q', action='store_true',
     311                         help="don't print version and copyright messages")
     312      args = parser.parse_args()
     313      if args.q or sys.flags.quiet:
     314          banner = ''
     315      else:
     316          banner = None
     317      interact(banner)