Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/IPython/terminal/ipapp.py: 57%

150 statements  

« prev     ^ index     » next       coverage.py v7.4.4, created at 2024-04-20 06:09 +0000

1#!/usr/bin/env python 

2# encoding: utf-8 

3""" 

4The :class:`~traitlets.config.application.Application` object for the command 

5line :command:`ipython` program. 

6""" 

7 

8# Copyright (c) IPython Development Team. 

9# Distributed under the terms of the Modified BSD License. 

10 

11 

12import logging 

13import os 

14import sys 

15import warnings 

16 

17from traitlets.config.loader import Config 

18from traitlets.config.application import boolean_flag, catch_config_error 

19from IPython.core import release 

20from IPython.core import usage 

21from IPython.core.completer import IPCompleter 

22from IPython.core.crashhandler import CrashHandler 

23from IPython.core.formatters import PlainTextFormatter 

24from IPython.core.history import HistoryManager 

25from IPython.core.application import ( 

26 ProfileDir, BaseIPythonApplication, base_flags, base_aliases 

27) 

28from IPython.core.magic import MagicsManager 

29from IPython.core.magics import ( 

30 ScriptMagics, LoggingMagics 

31) 

32from IPython.core.shellapp import ( 

33 InteractiveShellApp, shell_flags, shell_aliases 

34) 

35from IPython.extensions.storemagic import StoreMagics 

36from .interactiveshell import TerminalInteractiveShell 

37from IPython.paths import get_ipython_dir 

38from traitlets import ( 

39 Bool, List, default, observe, Type 

40) 

41 

42#----------------------------------------------------------------------------- 

43# Globals, utilities and helpers 

44#----------------------------------------------------------------------------- 

45 

46_examples = """ 

47ipython --matplotlib # enable matplotlib integration 

48ipython --matplotlib=qt # enable matplotlib integration with qt4 backend 

49 

50ipython --log-level=DEBUG # set logging to DEBUG 

51ipython --profile=foo # start with profile foo 

52 

53ipython profile create foo # create profile foo w/ default config files 

54ipython help profile # show the help for the profile subcmd 

55 

56ipython locate # print the path to the IPython directory 

57ipython locate profile foo # print the path to the directory for profile `foo` 

58""" 

59 

60#----------------------------------------------------------------------------- 

61# Crash handler for this application 

62#----------------------------------------------------------------------------- 

63 

64class IPAppCrashHandler(CrashHandler): 

65 """sys.excepthook for IPython itself, leaves a detailed report on disk.""" 

66 

67 def __init__(self, app): 

68 contact_name = release.author 

69 contact_email = release.author_email 

70 bug_tracker = 'https://github.com/ipython/ipython/issues' 

71 super(IPAppCrashHandler,self).__init__( 

72 app, contact_name, contact_email, bug_tracker 

73 ) 

74 

75 def make_report(self,traceback): 

76 """Return a string containing a crash report.""" 

77 

78 sec_sep = self.section_sep 

79 # Start with parent report 

80 report = [super(IPAppCrashHandler, self).make_report(traceback)] 

81 # Add interactive-specific info we may have 

82 rpt_add = report.append 

83 try: 

84 rpt_add(sec_sep+"History of session input:") 

85 for line in self.app.shell.user_ns['_ih']: 

86 rpt_add(line) 

87 rpt_add('\n*** Last line of input (may not be in above history):\n') 

88 rpt_add(self.app.shell._last_input_line+'\n') 

89 except: 

90 pass 

91 

92 return ''.join(report) 

93 

94#----------------------------------------------------------------------------- 

95# Aliases and Flags 

96#----------------------------------------------------------------------------- 

97flags = dict(base_flags) 

98flags.update(shell_flags) 

99frontend_flags = {} 

100addflag = lambda *args: frontend_flags.update(boolean_flag(*args)) 

101addflag('autoedit-syntax', 'TerminalInteractiveShell.autoedit_syntax', 

102 'Turn on auto editing of files with syntax errors.', 

103 'Turn off auto editing of files with syntax errors.' 

104) 

105addflag('simple-prompt', 'TerminalInteractiveShell.simple_prompt', 

106 "Force simple minimal prompt using `raw_input`", 

107 "Use a rich interactive prompt with prompt_toolkit", 

108) 

109 

110addflag('banner', 'TerminalIPythonApp.display_banner', 

111 "Display a banner upon starting IPython.", 

112 "Don't display a banner upon starting IPython." 

113) 

114addflag('confirm-exit', 'TerminalInteractiveShell.confirm_exit', 

115 """Set to confirm when you try to exit IPython with an EOF (Control-D 

116 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit', 

117 you can force a direct exit without any confirmation.""", 

118 "Don't prompt the user when exiting." 

119) 

120addflag('term-title', 'TerminalInteractiveShell.term_title', 

121 "Enable auto setting the terminal title.", 

122 "Disable auto setting the terminal title." 

123) 

124classic_config = Config() 

125classic_config.InteractiveShell.cache_size = 0 

126classic_config.PlainTextFormatter.pprint = False 

127classic_config.TerminalInteractiveShell.prompts_class='IPython.terminal.prompts.ClassicPrompts' 

128classic_config.InteractiveShell.separate_in = '' 

129classic_config.InteractiveShell.separate_out = '' 

130classic_config.InteractiveShell.separate_out2 = '' 

131classic_config.InteractiveShell.colors = 'NoColor' 

132classic_config.InteractiveShell.xmode = 'Plain' 

133 

134frontend_flags['classic']=( 

135 classic_config, 

136 "Gives IPython a similar feel to the classic Python prompt." 

137) 

138# # log doesn't make so much sense this way anymore 

139# paa('--log','-l', 

140# action='store_true', dest='InteractiveShell.logstart', 

141# help="Start logging to the default log file (./ipython_log.py).") 

142# 

143# # quick is harder to implement 

144frontend_flags['quick']=( 

145 {'TerminalIPythonApp' : {'quick' : True}}, 

146 "Enable quick startup with no config files." 

147) 

148 

149frontend_flags['i'] = ( 

150 {'TerminalIPythonApp' : {'force_interact' : True}}, 

151 """If running code from the command line, become interactive afterwards. 

152 It is often useful to follow this with `--` to treat remaining flags as 

153 script arguments. 

154 """ 

155) 

156flags.update(frontend_flags) 

157 

158aliases = dict(base_aliases) 

159aliases.update(shell_aliases) # type: ignore[arg-type] 

160 

161#----------------------------------------------------------------------------- 

162# Main classes and functions 

163#----------------------------------------------------------------------------- 

164 

165 

166class LocateIPythonApp(BaseIPythonApplication): 

167 description = """print the path to the IPython dir""" 

168 subcommands = dict( 

169 profile=('IPython.core.profileapp.ProfileLocate', 

170 "print the path to an IPython profile directory", 

171 ), 

172 ) 

173 def start(self): 

174 if self.subapp is not None: 

175 return self.subapp.start() 

176 else: 

177 print(self.ipython_dir) 

178 

179 

180class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp): 

181 name = u'ipython' 

182 description = usage.cl_usage 

183 crash_handler_class = IPAppCrashHandler # typing: ignore[assignment] 

184 examples = _examples 

185 

186 flags = flags 

187 aliases = aliases 

188 classes = List() 

189 

190 interactive_shell_class = Type( 

191 klass=object, # use default_value otherwise which only allow subclasses. 

192 default_value=TerminalInteractiveShell, 

193 help="Class to use to instantiate the TerminalInteractiveShell object. Useful for custom Frontends" 

194 ).tag(config=True) 

195 

196 @default('classes') 

197 def _classes_default(self): 

198 """This has to be in a method, for TerminalIPythonApp to be available.""" 

199 return [ 

200 InteractiveShellApp, # ShellApp comes before TerminalApp, because 

201 self.__class__, # it will also affect subclasses (e.g. QtConsole) 

202 TerminalInteractiveShell, 

203 HistoryManager, 

204 MagicsManager, 

205 ProfileDir, 

206 PlainTextFormatter, 

207 IPCompleter, 

208 ScriptMagics, 

209 LoggingMagics, 

210 StoreMagics, 

211 ] 

212 

213 subcommands = dict( 

214 profile = ("IPython.core.profileapp.ProfileApp", 

215 "Create and manage IPython profiles." 

216 ), 

217 kernel = ("ipykernel.kernelapp.IPKernelApp", 

218 "Start a kernel without an attached frontend." 

219 ), 

220 locate=('IPython.terminal.ipapp.LocateIPythonApp', 

221 LocateIPythonApp.description 

222 ), 

223 history=('IPython.core.historyapp.HistoryApp', 

224 "Manage the IPython history database." 

225 ), 

226 ) 

227 

228 

229 # *do* autocreate requested profile, but don't create the config file. 

230 auto_create=Bool(True) 

231 # configurables 

232 quick = Bool(False, 

233 help="""Start IPython quickly by skipping the loading of config files.""" 

234 ).tag(config=True) 

235 @observe('quick') 

236 def _quick_changed(self, change): 

237 if change['new']: 

238 self.load_config_file = lambda *a, **kw: None 

239 

240 display_banner = Bool(True, 

241 help="Whether to display a banner upon starting IPython." 

242 ).tag(config=True) 

243 

244 # if there is code of files to run from the cmd line, don't interact 

245 # unless the --i flag (App.force_interact) is true. 

246 force_interact = Bool(False, 

247 help="""If a command or file is given via the command-line, 

248 e.g. 'ipython foo.py', start an interactive shell after executing the 

249 file or command.""" 

250 ).tag(config=True) 

251 @observe('force_interact') 

252 def _force_interact_changed(self, change): 

253 if change['new']: 

254 self.interact = True 

255 

256 @observe('file_to_run', 'code_to_run', 'module_to_run') 

257 def _file_to_run_changed(self, change): 

258 new = change['new'] 

259 if new: 

260 self.something_to_run = True 

261 if new and not self.force_interact: 

262 self.interact = False 

263 

264 # internal, not-configurable 

265 something_to_run=Bool(False) 

266 

267 @catch_config_error 

268 def initialize(self, argv=None): 

269 """Do actions after construct, but before starting the app.""" 

270 super(TerminalIPythonApp, self).initialize(argv) 

271 if self.subapp is not None: 

272 # don't bother initializing further, starting subapp 

273 return 

274 # print self.extra_args 

275 if self.extra_args and not self.something_to_run: 

276 self.file_to_run = self.extra_args[0] 

277 self.init_path() 

278 # create the shell 

279 self.init_shell() 

280 # and draw the banner 

281 self.init_banner() 

282 # Now a variety of things that happen after the banner is printed. 

283 self.init_gui_pylab() 

284 self.init_extensions() 

285 self.init_code() 

286 

287 def init_shell(self): 

288 """initialize the InteractiveShell instance""" 

289 # Create an InteractiveShell instance. 

290 # shell.display_banner should always be False for the terminal 

291 # based app, because we call shell.show_banner() by hand below 

292 # so the banner shows *before* all extension loading stuff. 

293 self.shell = self.interactive_shell_class.instance(parent=self, 

294 profile_dir=self.profile_dir, 

295 ipython_dir=self.ipython_dir, user_ns=self.user_ns) 

296 self.shell.configurables.append(self) 

297 

298 def init_banner(self): 

299 """optionally display the banner""" 

300 if self.display_banner and self.interact: 

301 self.shell.show_banner() 

302 # Make sure there is a space below the banner. 

303 if self.log_level <= logging.INFO: print() 

304 

305 def _pylab_changed(self, name, old, new): 

306 """Replace --pylab='inline' with --pylab='auto'""" 

307 if new == 'inline': 

308 warnings.warn("'inline' not available as pylab backend, " 

309 "using 'auto' instead.") 

310 self.pylab = 'auto' 

311 

312 def start(self): 

313 if self.subapp is not None: 

314 return self.subapp.start() 

315 # perform any prexec steps: 

316 if self.interact: 

317 self.log.debug("Starting IPython's mainloop...") 

318 self.shell.mainloop() 

319 else: 

320 self.log.debug("IPython not interactive...") 

321 self.shell.restore_term_title() 

322 if not self.shell.last_execution_succeeded: 

323 sys.exit(1) 

324 

325def load_default_config(ipython_dir=None): 

326 """Load the default config file from the default ipython_dir. 

327 

328 This is useful for embedded shells. 

329 """ 

330 if ipython_dir is None: 

331 ipython_dir = get_ipython_dir() 

332 

333 profile_dir = os.path.join(ipython_dir, 'profile_default') 

334 app = TerminalIPythonApp() 

335 app.config_file_paths.append(profile_dir) 

336 app.load_config_file() 

337 return app.config 

338 

339launch_new_instance = TerminalIPythonApp.launch_instance 

340 

341 

342if __name__ == '__main__': 

343 launch_new_instance()