blob: f28371fc5c98ab9de5cca52f12146c69d354d838 [file] [log] [blame]
Guido van Rossum1557a731997-07-18 16:57:52 +00001"""Utilities dealing with code objects."""
2
Guido van Rossuma93b8481998-06-23 19:31:19 +00003import sys
4import string
5import traceback
6
Guido van Rossum1557a731997-07-18 16:57:52 +00007def compile_command(source, filename="<input>", symbol="single"):
8 r"""Compile a command and determine whether it is incomplete.
9
10 Arguments:
11
12 source -- the source string; may contain \n characters
13 filename -- optional filename from which source was read; default "<input>"
14 symbol -- optional grammar start symbol; "single" (default) or "eval"
15
16 Return value / exception raised:
17
18 - Return a code object if the command is complete and valid
19 - Return None if the command is incomplete
20 - Raise SyntaxError if the command is a syntax error
21
22 Approach:
23
24 Compile three times: as is, with \n, and with \n\n appended. If
25 it compiles as is, it's complete. If it compiles with one \n
26 appended, we expect more. If it doesn't compile either way, we
27 compare the error we get when compiling with \n or \n\n appended.
28 If the errors are the same, the code is broken. But if the errors
29 are different, we expect more. Not intuitive; not even guaranteed
30 to hold in future releases; but this matches the compiler's
31 behavior in Python 1.4 and 1.5.
32
33 """
34
35 err = err1 = err2 = None
36 code = code1 = code2 = None
37
38 try:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000039 code = compile(source, filename, symbol)
Guido van Rossum1557a731997-07-18 16:57:52 +000040 except SyntaxError, err:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000041 pass
Guido van Rossum1557a731997-07-18 16:57:52 +000042
43 try:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000044 code1 = compile(source + "\n", filename, symbol)
Guido van Rossum1557a731997-07-18 16:57:52 +000045 except SyntaxError, err1:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000046 pass
Guido van Rossum1557a731997-07-18 16:57:52 +000047
48 try:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000049 code2 = compile(source + "\n\n", filename, symbol)
Guido van Rossum1557a731997-07-18 16:57:52 +000050 except SyntaxError, err2:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000051 pass
Guido van Rossum1557a731997-07-18 16:57:52 +000052
53 if code:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000054 return code
Guido van Rossum86871641998-01-14 15:40:30 +000055 try:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000056 e1 = err1.__dict__
Guido van Rossum86871641998-01-14 15:40:30 +000057 except AttributeError:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000058 e1 = err1
Guido van Rossum86871641998-01-14 15:40:30 +000059 try:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000060 e2 = err2.__dict__
Guido van Rossum86871641998-01-14 15:40:30 +000061 except AttributeError:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000062 e2 = err2
Guido van Rossum86871641998-01-14 15:40:30 +000063 if not code1 and e1 == e2:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000064 raise SyntaxError, err1
Guido van Rossum90981e01997-10-07 14:47:24 +000065
66
Guido van Rossuma93b8481998-06-23 19:31:19 +000067class InteractiveConsole:
68 """Closely emulate the behavior of the interactive Python interpreter.
69
70 After code by Jeff Epler and Fredrik Lundh.
71 """
72
73 def __init__(self, filename="<console>", locals=None):
74 """Constructor.
75
76 The optional filename argument specifies the (file)name of the
77 input stream; it will show up in tracebacks. It defaults to
78 '<console>'.
79
80 """
81 self.filename = filename
82 if locals is None:
83 locals = {}
84 self.locals = locals
85 self.resetbuffer()
86
87 def resetbuffer(self):
88 """Reset the input buffer (but not the variables!)."""
89 self.buffer = []
90
91 def interact(self, banner=None):
92 """Closely emulate the interactive Python console."""
93 try:
94 sys.ps1
95 except AttributeError:
96 sys.ps1 = ">>> "
97 try:
98 sys.ps2
99 except AttributeError:
100 sys.ps2 = "... "
101 if banner is None:
102 self.write("Python %s on %s\n%s\n(%s)\n" %
103 (sys.version, sys.platform, sys.copyright,
104 self.__class__.__name__))
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000105 else:
Guido van Rossuma93b8481998-06-23 19:31:19 +0000106 self.write("%s\n" % str(banner))
107 more = 0
108 while 1:
109 try:
110 if more:
111 prompt = sys.ps2
112 else:
113 prompt = sys.ps1
114 try:
115 line = self.raw_input(prompt)
116 except EOFError:
117 self.write("\n")
118 break
119 else:
120 more = self.push(line)
121 except KeyboardInterrupt:
122 self.write("\nKeyboardInterrupt\n")
123 self.resetbuffer()
124 more = 0
125
126 def push(self, line):
127 """Push a line to the interpreter.
128
129 The line should not have a trailing newline.
130
131 One of three things will happen:
132
133 1) The input is incorrect; compile_command() raised
134 SyntaxError. A syntax traceback will be printed.
135
136 2) The input is incomplete, and more input is required;
137 compile_command() returned None.
138
139 3) The input is complete; compile_command() returned a code
140 object. The code is executed. When an exception occurs, a
141 traceback is printed. All exceptions are caught except
142 SystemExit, which is reraised.
143
144 The return value is 1 in case 2, 0 in the other cases. (The
145 return value can be used to decide whether to use sys.ps1 or
146 sys.ps2 to prompt the next line.)
147
148 A note about KeyboardInterrupt: this exception may occur
149 elsewhere in this code, and will not always be caught. The
150 caller should be prepared to deal with it.
151
152 """
153 self.buffer.append(line)
154
155 try:
156 x = compile_command(string.join(self.buffer, "\n"),
157 filename=self.filename)
158 except SyntaxError:
159 # Case 1
160 self.showsyntaxerror()
161 self.resetbuffer()
162 return 0
163
164 if x is None:
165 # Case 2
166 return 1
167
168 # Case 3
169 try:
170 exec x in self.locals
171 except SystemExit:
172 raise
173 except:
174 self.showtraceback()
175 self.resetbuffer()
176 return 0
177
178 def showsyntaxerror(self):
179 """Display the syntax error that just occurred.
180
181 This doesn't display a stack trace because there isn't one.
182
183 The output is written by self.write(), below.
184
185 """
186 type, value = sys.exc_info()[:2]
187 # Work hard to stuff the correct filename in the exception
188 try:
189 msg, (filename, lineno, offset, line) = value
190 except:
191 pass
192 else:
193 try:
194 value = SyntaxError(msg, (self.filename, lineno, offset, line))
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000195 except:
Guido van Rossuma93b8481998-06-23 19:31:19 +0000196 value = msg, (self.filename, lineno, offset, line)
197 list = traceback.format_exception_only(type, value)
198 map(self.write, list)
199
200 def showtraceback(self):
201 """Display the exception that just occurred.
202
203 We remove the first stack item because it is our own code.
204
205 The output is written by self.write(), below.
206
207 """
208 try:
209 type, value, tb = sys.exc_info()
210 tblist = traceback.extract_tb(tb)
211 del tblist[0]
212 list = traceback.format_list(tblist)
213 list[len(list):] = traceback.format_exception_only(type, value)
214 finally:
215 tblist = tb = None
216 map(self.write, list)
217
218 def write(self, data):
219 """Write a string.
220
221 The base implementation writes to sys.stderr; a subclass may
222 replace this with a different implementation.
223
224 """
225 sys.stderr.write(data)
226
227 def raw_input(self, prompt=""):
228 """Write a prompt and read a line.
229
230 The returned line does not include the trailing newline.
231 When the user enters the EOF key sequence, EOFError is raised.
232
233 The base implementation uses the built-in function
234 raw_input(); a subclass may replace this with a different
235 implementation.
236
237 """
238 return raw_input(prompt)
239
240
241def interact(banner=None, readfunc=None, locals=None):
242 """Closely emulate the interactive Python interpreter.
243
244 This is a backwards compatible interface to the InteractiveConsole
245 class. It attempts to import the readline module to enable GNU
246 readline if it is available.
247
248 Arguments (all optional, all default to None):
249
250 banner -- passed to InteractiveConsole.interact()
251 readfunc -- if not None, replaces InteractiveConsole.raw_input()
252 locals -- passed to InteractiveConsole.__init__()
253
254 """
255 try:
256 import readline
257 except:
258 pass
259 console = InteractiveConsole(locals=locals)
260 if readfunc is not None:
261 console.raw_input = readfunc
262 console.interact(banner)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000263
Guido van Rossum90981e01997-10-07 14:47:24 +0000264if __name__ == '__main__':
265 interact()