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