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