Coverage for /pythoncovmergedfiles/medio/medio/usr/lib/python3.9/code.py: 16%

121 statements  

« prev     ^ index     » next       coverage.py v7.3.1, created at 2023-09-25 06:05 +0000

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 traceback 

10from codeop import CommandCompiler, compile_command 

11 

12__all__ = ["InteractiveInterpreter", "InteractiveConsole", "interact", 

13 "compile_command"] 

14 

15class InteractiveInterpreter: 

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_type = type 

110 sys.last_value = value 

111 sys.last_traceback = tb 

112 if filename and type is SyntaxError: 

113 # Work hard to stuff the correct filename in the exception 

114 try: 

115 msg, (dummy_filename, lineno, offset, line) = value.args 

116 except ValueError: 

117 # Not the format we expect; leave it alone 

118 pass 

119 else: 

120 # Stuff in the right filename 

121 value = SyntaxError(msg, (filename, lineno, offset, line)) 

122 sys.last_value = value 

123 if sys.excepthook is sys.__excepthook__: 

124 lines = traceback.format_exception_only(type, value) 

125 self.write(''.join(lines)) 

126 else: 

127 # If someone has set sys.excepthook, we let that take precedence 

128 # over self.write 

129 sys.excepthook(type, value, tb) 

130 

131 def showtraceback(self): 

132 """Display the exception that just occurred. 

133 

134 We remove the first stack item because it is our own code. 

135 

136 The output is written by self.write(), below. 

137 

138 """ 

139 sys.last_type, sys.last_value, last_tb = ei = sys.exc_info() 

140 sys.last_traceback = last_tb 

141 try: 

142 lines = traceback.format_exception(ei[0], ei[1], last_tb.tb_next) 

143 if sys.excepthook is sys.__excepthook__: 

144 self.write(''.join(lines)) 

145 else: 

146 # If someone has set sys.excepthook, we let that take precedence 

147 # over self.write 

148 sys.excepthook(ei[0], ei[1], last_tb) 

149 finally: 

150 last_tb = ei = None 

151 

152 def write(self, data): 

153 """Write a string. 

154 

155 The base implementation writes to sys.stderr; a subclass may 

156 replace this with a different implementation. 

157 

158 """ 

159 sys.stderr.write(data) 

160 

161 

162class InteractiveConsole(InteractiveInterpreter): 

163 """Closely emulate the behavior of the interactive Python interpreter. 

164 

165 This class builds on InteractiveInterpreter and adds prompting 

166 using the familiar sys.ps1 and sys.ps2, and input buffering. 

167 

168 """ 

169 

170 def __init__(self, locals=None, filename="<console>"): 

171 """Constructor. 

172 

173 The optional locals argument will be passed to the 

174 InteractiveInterpreter base class. 

175 

176 The optional filename argument should specify the (file)name 

177 of the input stream; it will show up in tracebacks. 

178 

179 """ 

180 InteractiveInterpreter.__init__(self, locals) 

181 self.filename = filename 

182 self.resetbuffer() 

183 

184 def resetbuffer(self): 

185 """Reset the input buffer.""" 

186 self.buffer = [] 

187 

188 def interact(self, banner=None, exitmsg=None): 

189 """Closely emulate the interactive Python console. 

190 

191 The optional banner argument specifies the banner to print 

192 before the first interaction; by default it prints a banner 

193 similar to the one printed by the real Python interpreter, 

194 followed by the current class name in parentheses (so as not 

195 to confuse this with the real interpreter -- since it's so 

196 close!). 

197 

198 The optional exitmsg argument specifies the exit message 

199 printed when exiting. Pass the empty string to suppress 

200 printing an exit message. If exitmsg is not given or None, 

201 a default message is printed. 

202 

203 """ 

204 try: 

205 sys.ps1 

206 except AttributeError: 

207 sys.ps1 = ">>> " 

208 try: 

209 sys.ps2 

210 except AttributeError: 

211 sys.ps2 = "... " 

212 cprt = 'Type "help", "copyright", "credits" or "license" for more information.' 

213 if banner is None: 

214 self.write("Python %s on %s\n%s\n(%s)\n" % 

215 (sys.version, sys.platform, cprt, 

216 self.__class__.__name__)) 

217 elif banner: 

218 self.write("%s\n" % str(banner)) 

219 more = 0 

220 while 1: 

221 try: 

222 if more: 

223 prompt = sys.ps2 

224 else: 

225 prompt = sys.ps1 

226 try: 

227 line = self.raw_input(prompt) 

228 except EOFError: 

229 self.write("\n") 

230 break 

231 else: 

232 more = self.push(line) 

233 except KeyboardInterrupt: 

234 self.write("\nKeyboardInterrupt\n") 

235 self.resetbuffer() 

236 more = 0 

237 if exitmsg is None: 

238 self.write('now exiting %s...\n' % self.__class__.__name__) 

239 elif exitmsg != '': 

240 self.write('%s\n' % exitmsg) 

241 

242 def push(self, line): 

243 """Push a line to the interpreter. 

244 

245 The line should not have a trailing newline; it may have 

246 internal newlines. The line is appended to a buffer and the 

247 interpreter's runsource() method is called with the 

248 concatenated contents of the buffer as source. If this 

249 indicates that the command was executed or invalid, the buffer 

250 is reset; otherwise, the command is incomplete, and the buffer 

251 is left as it was after the line was appended. The return 

252 value is 1 if more input is required, 0 if the line was dealt 

253 with in some way (this is the same as runsource()). 

254 

255 """ 

256 self.buffer.append(line) 

257 source = "\n".join(self.buffer) 

258 more = self.runsource(source, self.filename) 

259 if not more: 

260 self.resetbuffer() 

261 return more 

262 

263 def raw_input(self, prompt=""): 

264 """Write a prompt and read a line. 

265 

266 The returned line does not include the trailing newline. 

267 When the user enters the EOF key sequence, EOFError is raised. 

268 

269 The base implementation uses the built-in function 

270 input(); a subclass may replace this with a different 

271 implementation. 

272 

273 """ 

274 return input(prompt) 

275 

276 

277 

278def interact(banner=None, readfunc=None, local=None, exitmsg=None): 

279 """Closely emulate the interactive Python interpreter. 

280 

281 This is a backwards compatible interface to the InteractiveConsole 

282 class. When readfunc is not specified, it attempts to import the 

283 readline module to enable GNU readline if it is available. 

284 

285 Arguments (all optional, all default to None): 

286 

287 banner -- passed to InteractiveConsole.interact() 

288 readfunc -- if not None, replaces InteractiveConsole.raw_input() 

289 local -- passed to InteractiveInterpreter.__init__() 

290 exitmsg -- passed to InteractiveConsole.interact() 

291 

292 """ 

293 console = InteractiveConsole(local) 

294 if readfunc is not None: 

295 console.raw_input = readfunc 

296 else: 

297 try: 

298 import readline 

299 except ImportError: 

300 pass 

301 console.interact(banner, exitmsg) 

302 

303 

304if __name__ == "__main__": 

305 import argparse 

306 

307 parser = argparse.ArgumentParser() 

308 parser.add_argument('-q', action='store_true', 

309 help="don't print version and copyright messages") 

310 args = parser.parse_args() 

311 if args.q or sys.flags.quiet: 

312 banner = '' 

313 else: 

314 banner = None 

315 interact(banner)