summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
Diffstat (limited to 'Lib')
-rw-r--r--Lib/code.py239
1 files changed, 197 insertions, 42 deletions
diff --git a/Lib/code.py b/Lib/code.py
index d0ff4bf..f28371f 100644
--- a/Lib/code.py
+++ b/Lib/code.py
@@ -1,5 +1,9 @@
"""Utilities dealing with code objects."""
+import sys
+import string
+import traceback
+
def compile_command(source, filename="<input>", symbol="single"):
r"""Compile a command and determine whether it is incomplete.
@@ -60,51 +64,202 @@ def compile_command(source, filename="<input>", symbol="single"):
raise SyntaxError, err1
-def interact(banner=None, readfunc=raw_input, local=None):
- # Due to Jeff Epler, with changes by Guido:
- """Closely emulate the interactive Python console."""
- try: import readline # Enable GNU readline if available
- except: pass
- local = local or {}
- import sys, string, traceback
- sys.ps1 = '>>> '
- sys.ps2 = '... '
- if banner:
- print banner
- else:
- print "Python Interactive Console", sys.version
- print sys.copyright
- buf = []
- while 1:
- if buf: prompt = sys.ps2
- else: prompt = sys.ps1
- try: line = readfunc(prompt)
- except KeyboardInterrupt:
- print "\nKeyboardInterrupt"
- buf = []
- continue
- except EOFError: break
- buf.append(line)
- try: x = compile_command(string.join(buf, "\n"))
+class InteractiveConsole:
+ """Closely emulate the behavior of the interactive Python interpreter.
+
+ After code by Jeff Epler and Fredrik Lundh.
+ """
+
+ def __init__(self, filename="<console>", locals=None):
+ """Constructor.
+
+ The optional filename argument specifies the (file)name of the
+ input stream; it will show up in tracebacks. It defaults to
+ '<console>'.
+
+ """
+ self.filename = filename
+ if locals is None:
+ locals = {}
+ self.locals = locals
+ self.resetbuffer()
+
+ def resetbuffer(self):
+ """Reset the input buffer (but not the variables!)."""
+ self.buffer = []
+
+ def interact(self, banner=None):
+ """Closely emulate the interactive Python console."""
+ try:
+ sys.ps1
+ except AttributeError:
+ sys.ps1 = ">>> "
+ try:
+ sys.ps2
+ except AttributeError:
+ sys.ps2 = "... "
+ if banner is None:
+ self.write("Python %s on %s\n%s\n(%s)\n" %
+ (sys.version, sys.platform, sys.copyright,
+ self.__class__.__name__))
+ else:
+ self.write("%s\n" % str(banner))
+ more = 0
+ while 1:
+ try:
+ if more:
+ prompt = sys.ps2
+ else:
+ prompt = sys.ps1
+ try:
+ line = self.raw_input(prompt)
+ except EOFError:
+ self.write("\n")
+ break
+ else:
+ more = self.push(line)
+ except KeyboardInterrupt:
+ self.write("\nKeyboardInterrupt\n")
+ self.resetbuffer()
+ more = 0
+
+ def push(self, line):
+ """Push a line to the interpreter.
+
+ The line should not have a trailing newline.
+
+ One of three things will happen:
+
+ 1) The input is incorrect; compile_command() raised
+ SyntaxError. A syntax traceback will be printed.
+
+ 2) The input is incomplete, and more input is required;
+ compile_command() returned None.
+
+ 3) The input is complete; compile_command() returned a code
+ object. The code is executed. When an exception occurs, a
+ traceback is printed. All exceptions are caught except
+ SystemExit, which is reraised.
+
+ The return value is 1 in case 2, 0 in the other cases. (The
+ return value can be used to decide whether to use sys.ps1 or
+ sys.ps2 to prompt the next line.)
+
+ A note about KeyboardInterrupt: this exception may occur
+ elsewhere in this code, and will not always be caught. The
+ caller should be prepared to deal with it.
+
+ """
+ self.buffer.append(line)
+
+ try:
+ x = compile_command(string.join(self.buffer, "\n"),
+ filename=self.filename)
except SyntaxError:
- traceback.print_exc(0)
- buf = []
- continue
- if x == None: continue
+ # Case 1
+ self.showsyntaxerror()
+ self.resetbuffer()
+ return 0
+
+ if x is None:
+ # Case 2
+ return 1
+
+ # Case 3
+ try:
+ exec x in self.locals
+ except SystemExit:
+ raise
+ except:
+ self.showtraceback()
+ self.resetbuffer()
+ return 0
+
+ def showsyntaxerror(self):
+ """Display the syntax error that just occurred.
+
+ This doesn't display a stack trace because there isn't one.
+
+ The output is written by self.write(), below.
+
+ """
+ type, value = sys.exc_info()[:2]
+ # Work hard to stuff the correct filename in the exception
+ try:
+ msg, (filename, lineno, offset, line) = value
+ except:
+ pass
else:
- try: exec x in local
+ try:
+ value = SyntaxError(msg, (self.filename, lineno, offset, line))
except:
- exc_type, exc_value, exc_traceback = \
- sys.exc_type, sys.exc_value, \
- sys.exc_traceback
- l = len(traceback.extract_tb(sys.exc_traceback))
- try: 1/0
- except:
- m = len(traceback.extract_tb(
- sys.exc_traceback))
- traceback.print_exception(exc_type,
- exc_value, exc_traceback, l-m)
- buf = []
+ value = msg, (self.filename, lineno, offset, line)
+ list = traceback.format_exception_only(type, value)
+ map(self.write, list)
+
+ def showtraceback(self):
+ """Display the exception that just occurred.
+
+ We remove the first stack item because it is our own code.
+
+ The output is written by self.write(), below.
+
+ """
+ try:
+ type, value, tb = sys.exc_info()
+ tblist = traceback.extract_tb(tb)
+ del tblist[0]
+ list = traceback.format_list(tblist)
+ list[len(list):] = traceback.format_exception_only(type, value)
+ finally:
+ tblist = tb = None
+ map(self.write, list)
+
+ def write(self, data):
+ """Write a string.
+
+ The base implementation writes to sys.stderr; a subclass may
+ replace this with a different implementation.
+
+ """
+ sys.stderr.write(data)
+
+ def raw_input(self, prompt=""):
+ """Write a prompt and read a line.
+
+ The returned line does not include the trailing newline.
+ When the user enters the EOF key sequence, EOFError is raised.
+
+ The base implementation uses the built-in function
+ raw_input(); a subclass may replace this with a different
+ implementation.
+
+ """
+ return raw_input(prompt)
+
+
+def interact(banner=None, readfunc=None, locals=None):
+ """Closely emulate the interactive Python interpreter.
+
+ This is a backwards compatible interface to the InteractiveConsole
+ class. It attempts to import the readline module to enable GNU
+ readline if it is available.
+
+ Arguments (all optional, all default to None):
+
+ banner -- passed to InteractiveConsole.interact()
+ readfunc -- if not None, replaces InteractiveConsole.raw_input()
+ locals -- passed to InteractiveConsole.__init__()
+
+ """
+ try:
+ import readline
+ except:
+ pass
+ console = InteractiveConsole(locals=locals)
+ if readfunc is not None:
+ console.raw_input = readfunc
+ console.interact(banner)
if __name__ == '__main__':
interact()