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

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

150 statements  

1""" 

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

3line :command:`ipython` program. 

4""" 

5 

6# Copyright (c) IPython Development Team. 

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

8 

9 

10import logging 

11import os 

12import sys 

13import warnings 

14 

15from traitlets.config.loader import Config 

16from traitlets.config.application import boolean_flag, catch_config_error 

17from IPython.core import release 

18from IPython.core import usage 

19from IPython.core.completer import IPCompleter 

20from IPython.core.crashhandler import CrashHandler 

21from IPython.core.formatters import PlainTextFormatter 

22from IPython.core.history import HistoryManager 

23from IPython.core.application import ( 

24 ProfileDir, BaseIPythonApplication, base_flags, base_aliases 

25) 

26from IPython.core.magic import MagicsManager 

27from IPython.core.magics import ( 

28 ScriptMagics, LoggingMagics 

29) 

30from IPython.core.shellapp import ( 

31 InteractiveShellApp, shell_flags, shell_aliases 

32) 

33from IPython.extensions.storemagic import StoreMagics 

34from .interactiveshell import TerminalInteractiveShell 

35from IPython.paths import get_ipython_dir 

36from traitlets import ( 

37 Bool, List, default, observe, Type 

38) 

39 

40#----------------------------------------------------------------------------- 

41# Globals, utilities and helpers 

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

43 

44_examples = """ 

45ipython --matplotlib # enable matplotlib integration 

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

47 

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

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

50 

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

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

53 

54ipython locate # print the path to the IPython directory 

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

56""" 

57 

58#----------------------------------------------------------------------------- 

59# Crash handler for this application 

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

61 

62class IPAppCrashHandler(CrashHandler): 

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

64 

65 def __init__(self, app): 

66 contact_name = release.author 

67 contact_email = release.author_email 

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

69 super().__init__( 

70 app, contact_name, contact_email, bug_tracker 

71 ) 

72 

73 def make_report(self,traceback): 

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

75 

76 sec_sep = self.section_sep 

77 # Start with parent report 

78 report = [super().make_report(traceback)] 

79 # Add interactive-specific info we may have 

80 rpt_add = report.append 

81 try: 

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

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

84 rpt_add(line) 

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

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

87 except Exception: 

88 pass 

89 

90 return ''.join(report) 

91 

92#----------------------------------------------------------------------------- 

93# Aliases and Flags 

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

95flags = dict(base_flags) 

96flags.update(shell_flags) 

97frontend_flags = {} 

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

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

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

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

102) 

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

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

105 "Use a rich interactive prompt with prompt_toolkit", 

106) 

107 

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

109 "Display a banner upon starting IPython.", 

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

111) 

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

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

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

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

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

117) 

118addflag( 

119 "tip", 

120 "TerminalInteractiveShell.enable_tip", 

121 """Shows a tip when IPython starts.""", 

122 "Don't show tip when IPython starts.", 

123) 

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

125 "Enable auto setting the terminal title.", 

126 "Disable auto setting the terminal title." 

127) 

128classic_config = Config() 

129classic_config.InteractiveShell.cache_size = 0 

130classic_config.PlainTextFormatter.pprint = False 

131classic_config.TerminalInteractiveShell.prompts_class = ( 

132 "IPython.terminal.prompts.ClassicPrompts" 

133) 

134classic_config.InteractiveShell.separate_in = "" 

135classic_config.InteractiveShell.separate_out = "" 

136classic_config.InteractiveShell.separate_out2 = "" 

137classic_config.InteractiveShell.colors = "nocolor" 

138classic_config.InteractiveShell.xmode = "Plain" 

139 

140frontend_flags['classic']=( 

141 classic_config, 

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

143) 

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

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

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

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

148# 

149# # quick is harder to implement 

150frontend_flags['quick']=( 

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

152 "Enable quick startup with no config files." 

153) 

154 

155frontend_flags['i'] = ( 

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

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

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

159 script arguments. 

160 """ 

161) 

162flags.update(frontend_flags) 

163 

164aliases = dict(base_aliases) 

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

166 

167#----------------------------------------------------------------------------- 

168# Main classes and functions 

169#----------------------------------------------------------------------------- 

170 

171 

172class LocateIPythonApp(BaseIPythonApplication): 

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

174 subcommands = dict( 

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

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

177 ), 

178 ) 

179 def start(self): 

180 if self.subapp is not None: 

181 return self.subapp.start() 

182 else: 

183 print(self.ipython_dir) 

184 

185 

186class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp): 

187 name = "ipython" 

188 description = usage.cl_usage 

189 crash_handler_class = IPAppCrashHandler # typing: ignore[assignment] 

190 examples = _examples 

191 

192 flags = flags 

193 aliases = aliases 

194 classes = List() 

195 

196 interactive_shell_class = Type( 

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

198 default_value=TerminalInteractiveShell, 

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

200 ).tag(config=True) 

201 

202 @default('classes') 

203 def _classes_default(self): 

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

205 return [ 

206 InteractiveShellApp, # ShellApp comes before TerminalApp, because 

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

208 TerminalInteractiveShell, 

209 HistoryManager, 

210 MagicsManager, 

211 ProfileDir, 

212 PlainTextFormatter, 

213 IPCompleter, 

214 ScriptMagics, 

215 LoggingMagics, 

216 StoreMagics, 

217 ] 

218 

219 subcommands = dict( 

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

221 "Create and manage IPython profiles." 

222 ), 

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

224 "Start a kernel without an attached frontend." 

225 ), 

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

227 LocateIPythonApp.description 

228 ), 

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

230 "Manage the IPython history database." 

231 ), 

232 ) 

233 

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

235 auto_create = Bool(True).tag(config=True) 

236 

237 # configurables 

238 quick = Bool(False, 

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

240 ).tag(config=True) 

241 @observe('quick') 

242 def _quick_changed(self, change): 

243 if change['new']: 

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

245 

246 display_banner = Bool(True, 

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

248 ).tag(config=True) 

249 

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

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

252 force_interact = Bool(False, 

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

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

255 file or command.""" 

256 ).tag(config=True) 

257 @observe('force_interact') 

258 def _force_interact_changed(self, change): 

259 if change['new']: 

260 self.interact = True 

261 

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

263 def _file_to_run_changed(self, change): 

264 new = change['new'] 

265 if new: 

266 self.something_to_run = True 

267 if new and not self.force_interact: 

268 self.interact = False 

269 

270 # internal, not-configurable 

271 something_to_run=Bool(False) 

272 

273 @catch_config_error 

274 def initialize(self, argv=None): 

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

276 super().initialize(argv) 

277 if self.subapp is not None: 

278 # don't bother initializing further, starting subapp 

279 return 

280 # print(self.extra_args) 

281 if self.extra_args and not self.something_to_run: 

282 self.file_to_run = self.extra_args[0] 

283 self.init_path() 

284 # create the shell 

285 self.init_shell() 

286 # and draw the banner 

287 self.init_banner() 

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

289 self.init_gui_pylab() 

290 self.init_extensions() 

291 self.init_code() 

292 

293 def init_shell(self): 

294 """initialize the InteractiveShell instance""" 

295 # Create an InteractiveShell instance. 

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

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

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

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

300 profile_dir=self.profile_dir, 

301 ipython_dir=self.ipython_dir, user_ns=self.user_ns) 

302 self.shell.configurables.append(self) 

303 

304 def init_banner(self): 

305 """optionally display the banner""" 

306 if self.display_banner and self.interact: 

307 self.shell.show_banner() 

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

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

310 

311 @observe("pylab") 

312 def _pylab_changed(self, change): 

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

314 if change["new"] == "inline": 

315 warnings.warn( 

316 "'inline' not available as pylab backend, using 'auto' instead." 

317 ) 

318 self.pylab = "auto" 

319 

320 def start(self): 

321 if self.subapp is not None: 

322 return self.subapp.start() 

323 # perform any prexec steps: 

324 if self.interact: 

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

326 self.shell.mainloop() 

327 else: 

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

329 self.shell.restore_term_title() 

330 if not self.shell.last_execution_succeeded: 

331 sys.exit(1) 

332 

333def load_default_config(ipython_dir=None): 

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

335 

336 This is useful for embedded shells. 

337 """ 

338 if ipython_dir is None: 

339 ipython_dir = get_ipython_dir() 

340 

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

342 app = TerminalIPythonApp() 

343 app.config_file_paths.append(profile_dir) 

344 app.load_config_file() 

345 return app.config 

346 

347launch_new_instance = TerminalIPythonApp.launch_instance